Java游戏服(简单事件通知实现)

Posted Mature

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java游戏服(简单事件通知实现)相关的知识,希望对你有一定的参考价值。

本次主要用Java实现简单的游戏服务器事件通知,在游戏服中,事件通知是必不可少的一种游戏业务处理逻辑,可以基于观察者模式去编写,或则其他更好的方式。也可以用guava框架的事件通知框架,以下代码只是大概的实现思想,总体设计思路都大同小异;


1.Event注解

package ge;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.FIELD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Event {
    public GameEventType value();
}



处理器接口
IGameEventHandler.Java

package ge;


public interface IGameEventHandler extends Runnable{
}



GameEventHadler.java(父类事件处理器实现类)

package ge;

public abstract class GameEventHadler implements IGameEventHandler {
    /**
     * 事件类型
     */
    private GameEventType gameEventType;
    /**
     * 传递的参数
     */
    private GameEventMsg gameEventMsg;

    @Override
    public void run() {
        notice(gameEventType, gameEventMsg);
    }

    public abstract void notice(GameEventType gameEventType, GameEventMsg gameEventMsg);

    /**
     * 设置参数
     * 
     * @param gameEventType
     * @param gameEventMsg
     * @return
     */
    public GameEventHadler transmit(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        this.gameEventType = gameEventType;
        this.gameEventMsg = gameEventMsg;
        return this;

    }

    public GameEventType getGameEventType() {
        return gameEventType;
    }

    public void setGameEventType(GameEventType gameEventType) {
        this.gameEventType = gameEventType;
    }

    public GameEventMsg getGameEventMsg() {
        return gameEventMsg;
    }

    public void setGameEventMsg(GameEventMsg gameEventMsg) {
        this.gameEventMsg = gameEventMsg;
    }

}


事件管理器
GameEventMgr。Java
package ge;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import ge.util.EventRegister;

public class GameEventMgr {
    public static GameEventMgr observerMgr = new GameEventMgr();

    public static final String EVENT_PACKGE = "ge.imp";

    public static GameEventMgr getIns() {
        return observerMgr;
    }

    private static final int MAX_THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2;
    /**
     * 事件执行线程池
     */
    private static ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREAD_NUM);
    /**
     * 事件处理器容器
     */
    public static Map<GameEventType, GameEventHadler> gameEventHadlerMaps = new HashMap<>();

    static {
        // 注解注册
        EventRegister.registeredByAnnotation();
        // 代码对象注册
        EventRegister.registeredByClassCode();
    }
    
    /**
     *  事件通知
     * @param gameEventType
     * @param gameEventMsg
     */
    public static void poolEvent(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        if (gameEventHadlerMaps.containsKey(gameEventType)) {
            GameEventHadler gameEventHadler = gameEventHadlerMaps.get(gameEventType);
            executorService.execute(gameEventHadler.transmit(gameEventType, gameEventMsg));
        }
    }

    /**
     *  优雅的关闭线程池子
     */
    public static void shutDownExecutorService() {
        if (executorService != null) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdown();
                }
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                }

            } catch (Exception e) {
                executorService.shutdown();
                Thread.currentThread().interrupt();
            }
        }
        System.err.println("Thread pool shutdown:OK");
    }
}



事件消息基类
GameEventMsg。Java

package ge;
/**
 * 事件消息基类
 * @author admin
 *
 */
public abstract class GameEventMsg {

}



事件类型枚举类
package ge;

public enum GameEventType {

    UP_LEVEL(1, "升级事件"), 
    VIP_UP_LEVEL(2, "VIP升级事件"),
    RECHARGE(3, "充值事件"),
    MONSTER_DIE(4,"怪物死亡"),
    ;
    private int value;
    private String des;

    GameEventType(int value, String des) {
        this.value = value;
        this.des = des;
    }

    public String getDes() {
        return des;
    }

    public int getValue() {
        return value;
    }

}



消息实体
package ge.event;

import ge.GameEventMsg;

public class MonsterDeath_GE extends GameEventMsg {
    // 击杀者
    private long killPlayerId;
    // 怪物id
    private int monsterId;

    public long getKillPlayerId() {
        return killPlayerId;
    }

    public void setKillPlayerId(long killPlayerId) {
        this.killPlayerId = killPlayerId;
    }

    public int getMonsterId() {
        return monsterId;
    }

    public void setMonsterId(int monsterId) {
        this.monsterId = monsterId;
    }

}


package ge.event;

import ge.GameEventMsg;

public class RechargeEvent_GE extends GameEventMsg{
    /**
     * 充值数量
     */
    
    private int rechargeNum;

    public int getRechargeNum() {
        return rechargeNum;
    }

    public void setRechargeNum(int rechargeNum) {
        this.rechargeNum = rechargeNum;
    }
    

}



package ge.event;

import ge.GameEventMsg;

public class UpLevelEvent_GE extends GameEventMsg{
    /**
     * 等级
     */
    private int level;

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }


}



package ge.event;

import ge.GameEventMsg;

public class VipLevelEvent_GE extends GameEventMsg{
    /**
     * VIP等级
     */
    private int vipLevel;

    public int getVipLevel() {
        return vipLevel;
    }

    public void setVipLevel(int vipLevel) {
        this.vipLevel = vipLevel;
    }

}


通知处理器


package ge.imp;

import ge.GameEventHadler;
import ge.GameEventMsg;
import ge.GameEventType;
import ge.event.MonsterDeath_GE;
import ge.mgr.MonsterMgr;

public class MonsterDeathHandler extends GameEventHadler {

    @Override
    public void notice(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        MonsterDeath_GE MonsterDeath_GE = (MonsterDeath_GE) gameEventMsg;
        MonsterMgr.getIns().monsterKillEvent(MonsterDeath_GE.getKillPlayerId(), MonsterDeath_GE.getMonsterId());
    }

}



package ge.imp;

import ge.Event;
import ge.GameEventHadler;
import ge.GameEventMsg;
import ge.GameEventType;
import ge.mgr.RechargeMgr;
import observer.event.RechargeEvent_GE;

/**
 * 接收事件触发后的业务处理
 * 
 * @author admin
 *
 */
@Event(GameEventType.RECHARGE)
public class RechargeEventHandler extends GameEventHadler {
    @Override
    public void notice(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        RechargeEvent_GE e = (RechargeEvent_GE) gameEventMsg;
        RechargeMgr.getIns().rechargeEvent(e.getRechargeNum());
        /**
         * 通常相关业务处理:充值奖励,VIP充值经验增加等
         */
    }
}



package ge.imp;

import ge.Event;
import ge.GameEventHadler;
import ge.GameEventMsg;
import ge.GameEventType;
import ge.mgr.LevelMgr;
import observer.event.UpLevelEvent_GE;

/**
 * 接收事件触发后的业务处理
 * 
 * @author admin
 *
 */
@Event(GameEventType.UP_LEVEL)
public class UpLevelEventHandler extends GameEventHadler {

    @Override
    public void notice(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        UpLevelEvent_GE e = (UpLevelEvent_GE) gameEventMsg;
        LevelMgr.getIns().uplevelEvent(e.getLevel());
        /**
         * 通常相关业务处理:玩家战力,系统开放,等级礼包,等级排行等相关
         */
    }

}



package ge.imp;

import ge.Event;
import ge.GameEventHadler;
import ge.GameEventMsg;
import ge.GameEventType;
import ge.mgr.VipMgr;
import observer.event.VipLevelEvent_GE;

/**
 * 接收事件触发后的业务处理
 * 
 * @author admin
 *
 */
@Event(GameEventType.VIP_UP_LEVEL)
public class VipUpLevelEventHandler extends GameEventHadler {

    @Override
    public void notice(GameEventType gameEventType, GameEventMsg gameEventMsg) {
        VipLevelEvent_GE e = (VipLevelEvent_GE) gameEventMsg;
        VipMgr.getIns().vipLevelEvent(e.getVipLevel());
        /**
         * 通常相关业务处理:VIP特权,奖励,系统开放相关等
         */
    }
}



模拟业务管理器调用

package ge.mgr;
/**
 * 业务类
 * @author admin
 *
 */
public class LevelMgr {
    private static LevelMgr levelMgr=new LevelMgr();
    
    public static LevelMgr getIns() {
        return levelMgr;
    }
    public void uplevelEvent(int level) {
        System.err.println("升级到:" + level);
    }

}


package ge.mgr;

/**
 * 业务类
 * 
 * @author admin
 *
 */
public class MonsterMgr {
    private static MonsterMgr monsterMgr = new MonsterMgr();

    public static MonsterMgr getIns() {
        return monsterMgr;
    }

    public void monsterKillEvent(long killPlayer, int monsterId) {
        System.err.println("击杀者ID:" + killPlayer + ":怪物id:" + monsterId);
    }
}

package ge.mgr;

/**
 * 业务类
 * 
 * @author admin
 *
 */
public class RechargeMgr {
    private static RechargeMgr rechargeMgr = new RechargeMgr();

    public static RechargeMgr getIns() {
        return rechargeMgr;
    }

    public void rechargeEvent(int rechargeNum) {
        System.err.println("充值了" + rechargeNum);
    }
}




package ge.mgr;

public class VipMgr {
    /**
     * 业务类
     */
private static VipMgr vipMgr=new VipMgr();
    
    public static VipMgr getIns() {
        return vipMgr;
    }
    public void vipLevelEvent(int vipLevel) {
        System.err.println("VIP升级到:" + vipLevel);
    }
}




工具类
package ge.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;

public class ClazzUtils {
    /**
     * 从包package中获取所有的Class
     * 
     * @param pack
     * @return
     */
    public static Set<Class<?>> getClasses(String pack) {

        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
        boolean recursive = true;
        String packageName = pack;
        String packageDirName = packageName.replace(‘.‘, ‘/‘);
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    System.err.println("file类型的扫描");
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return classes;
    }

    /**
     * 以文件的形式来获取包下的所有Class
     * 
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,
            Set<Class<?>> classes) {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        File[] dirfiles = dir.listFiles(new FileFilter() {

            public boolean accept(File file) {
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        for (File file : dirfiles) {
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
                        classes);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    classes.add(
                            Thread.currentThread().getContextClassLoader().loadClass(packageName + ‘.‘ + className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Set<Class<?>> clazz = getClasses("observer.imp");
        clazz.forEach(s -> {
            System.err.println(s);
        });
    }
}




事件处理器注册类
package ge.util;

import java.util.Set;

import ge.Event;
import ge.GameEventHadler;
import ge.GameEventMgr;
import ge.GameEventType;
import ge.imp.MonsterDeathHandler;
import observer.imp.RechargeEventHandler;
import observer.imp.UpLevelEventHandler;
import observer.imp.VipUpLevelEventHandler;

public class EventRegister {

    /**
     * 代码:注册事件处理器[注册方式1]
     */
    public static void registeredByClassCode() {
        registered(GameEventType.UP_LEVEL, new UpLevelEventHandler());
        registered(GameEventType.RECHARGE, new RechargeEventHandler());
        registered(GameEventType.VIP_UP_LEVEL, new VipUpLevelEventHandler());
        registered(GameEventType.MONSTER_DIE, new MonsterDeathHandler());
    }

    /**
     * 注册:如果存在就不再进行重复注册
     * 
     * @param gameEventType
     * @param gameEventHadler
     */
    public static void registered(GameEventType gameEventType, GameEventHadler gameEventHadler) {
        GameEventMgr.gameEventHadlerMaps.computeIfAbsent(gameEventType, s -> {
            return gameEventHadler;
        });
    }

    /**
     * 通过扫描指定包名进行注册[注册方式2]
     */
    public static void registeredByAnnotation() {
        Set<Class<?>> clazzs = ClazzUtils.getClasses(GameEventMgr.EVENT_PACKGE);
        if (clazzs == null||clazzs.isEmpty()) {
            System.err.println("无可注册的事件处理器类");
            return;
        }
        for (Class<?> clazz : clazzs) {
            if (!clazz.isAnnotationPresent(Event.class)) {
                continue;
            }
            Event event = clazz.getAnnotation(Event.class);
            if (event == null) {
                continue;
            }
            GameEventType gameEventType = event.value();
            try {
                GameEventMgr.gameEventHadlerMaps.put(gameEventType, (GameEventHadler) clazz.newInstance());
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}


测试类


package ge;

import java.util.Scanner;

import ge.event.MonsterDeath_GE;
import observer.event.RechargeEvent_GE;
import observer.event.UpLevelEvent_GE;
import observer.event.VipLevelEvent_GE;

public class GameEventTest {
    @SuppressWarnings("static-access")
    /**
     * 测试
     * 
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        /**
         * 添加守护线程:在jvm关闭前关闭线程池:一般用在服务器关闭前的操作{数据持久,线程池关闭等等...}
         */
        Runtime.getRuntime().addShutdownHook(new Thread(() -> GameEventMgr.shutDownExecutorService()));

        /**
         * 模拟关闭程序命令操作
         */
        new Thread(() -> closeSystemThread()).start();
        /**
         * 模拟玩家升级
         */
        UpLevelEvent_GE upLevelEvent_GE = new UpLevelEvent_GE();
        upLevelEvent_GE.setLevel(1000);
        GameEventMgr.getIns().poolEvent(GameEventType.UP_LEVEL, upLevelEvent_GE);
        /**
         * 模拟vip升级
         */
        VipLevelEvent_GE vipLevelEvent_GE = new VipLevelEvent_GE();
        vipLevelEvent_GE.setVipLevel(12);
        GameEventMgr.getIns().poolEvent(GameEventType.VIP_UP_LEVEL, vipLevelEvent_GE);

        /**
         * 模拟充值
         */
        RechargeEvent_GE rechargeEvent_GE = new RechargeEvent_GE();
        rechargeEvent_GE.setRechargeNum(500);
        GameEventMgr.getIns().poolEvent(GameEventType.RECHARGE, rechargeEvent_GE);

        /**
         * 模拟怪物击杀
         */
        MonsterDeath_GE monsterDeath_GE = new MonsterDeath_GE();
        monsterDeath_GE.setKillPlayerId(1000200088);
        monsterDeath_GE.setMonsterId(100008);
        GameEventMgr.getIns().poolEvent(GameEventType.MONSTER_DIE, monsterDeath_GE);

    }

    /**
     * 关闭程序
     */
    @SuppressWarnings("resource")
    public static void closeSystemThread() {
        Scanner scanner = new Scanner(System.in);
        if (scanner.next().equals("close"))
            System.exit(0);
    }
}

  

以上是关于Java游戏服(简单事件通知实现)的主要内容,如果未能解决你的问题,请参考以下文章

简单Elixir游戏服设计-测试驱动?

简单Elixir游戏服设计- 游戏玩法介绍

将通知设置为在某个用户事件时触发

简单Elixir游戏服设计-完善测试和代码改进

简单Elixir游戏服设计-玩法simple_poker

Java实现一个简单的事件监听器