-
Notifications
You must be signed in to change notification settings - Fork 172
Example
客户端服务端消息编解码默认是基于java的反射机制,由底层根据协议文件的字段顺序及字段类型,自动进行序列化与反序列化。当然,为了提高拓展性,框架也提供了protobuff,protostuff,json等编解码方式。
通信协议需要实现Message接口,请求协议统一以Req开头,推送协议统一以Res开头。
Message类需用使用@MessageMeta绑定模块号与cmd。 业务模块号在Modules申明,而cmd在对应的业务模块内部自行定义即可,无需统一管理。
需要特别注意的是,如果协议字段本身是一个javabean,那么该字段也需要与Message同样的申明。
- 一个模块的所有业务处理都放在一个门面层进行统一管理,门面类以_Facade作为后缀,并用spring的@Controller注解。
- 绑定请求消息与对应的Method方法,使用@MessageMapper注解(也允许不申明该注解),获取请求参数后,转交给对应的业务管理类。
- 业务类以_Service作为后缀,并用spring的@Service注解。
如下所示:
@Controller
@ModuleMeta(module = Modules.PLAYER)
public class PlayerFacade {
@Autowired
private LoginService loginService;
@MessageMapping
public void reqAccountLogin(IdSession session, ReqAccountLogin request) {
loginService.handleAccountLogin(session, request.getAccountId(), request.getPassword());
}
public void reqSelectPlayer(IdSession session, ReqSelectPlayer requst) {
loginService.handleSelectPlayer(session, requst.getPlayerId());
}
}
该框架使用Springdatajpa,处理orm问题非常简单。当你有个db数据需要持久化,比如Player对象,只需要让该类继承BaseEntity, 同时Player类加上@Entity,然后在各个需要持久化的字段加上@Column注解。需要特别注意的是,每个BaseEntity至少需要一个字段使用@Id注解作为主键。当然,您也需要申明对应的dao文件。
当entity需要插入或者更新时,您只需使用一下代码即可。
SpringContext.getAysncDbService().saveToDb(player);
当entity数据需要移除,那么您只能手动写删除代码了。可喜的是,借助于springdatajpa,代码非常简单,如下:
playerDao.delete(player);
缓存直接使用了springCache,具体实现为ehache第三方库。
springcache最常用的是@Cacheable和@Cacheput两个注解了,具体使用方法可参考其他博客教程。例子如下:
@Cacheable(cacheNames = "player")
public Player getPlayer(long id) {
PlayerEnt playerEnt = playerDao.getOne(id);
Player player = new Player();
player.setId(id);
player.setPlayerEnt(playerEnt);
return player;
}
比如一个玩家升级事件,您只需实现BaseEvent接口,如下:
public class PlayerLevelUpEvent implements BaseEvent {
private Player player;
public PlayerLevelUpEvent(Player player) {
this.player = player;
}
@Override
public Player getOwner() {
return player;
}
}
然后,其他facade层就可以捕捉该事件了,如下:
@Subscribe
public void onPlayerLevelUp(PlayerLevelUpEvent upEvent) {
}
GM命令,可以视为游戏的金手指,允许你快速修改内存数据。笔者见过很多的游戏项目,所有gm的处理都放在同一个类文件,其代码行数往往超过5K行。有感于此,我们的gm命令处理将放在对应的模块里,只留一个枚举类统一管理gm命令的指令名称,可以使用GmDoc工具类导出所有的gm命令说明(给项目其他部门的使用文档)。
public enum GmCommands {
/**
* 设置玩家等级 [level]
*/
LEVEL,
}
具体的逻辑处理放在facade层,如下:
public class PlayerFacade {
@GmHandler(cmd = GmCommands.LEVEL)
public void gmSetLevel(Player player, int level) {
System.err.println("[gm]修改玩家等级为" + level);
player.setLevel(level);
SpringContext.getPlayerService().savePlayer(player);
EventBus.getInstance().post(new PlayerLevelUpEvent(player));
}
}