Skip to content

Example

Hang edited this page Feb 27, 2021 · 7 revisions

客户端通信协议

客户端服务端消息编解码默认是基于java的反射机制,由底层根据协议文件的字段顺序及字段类型,自动进行序列化与反序列化。当然,为了提高拓展性,框架也提供了protobuff,protostuff,json等编解码方式。
通信协议需要实现Message接口,请求协议统一以Req开头,推送协议统一以Res开头。
Message类需用使用@MessageMeta绑定模块号与cmd。 业务模块号在Modules申明,而cmd在对应的业务模块内部自行定义即可,无需统一管理。
需要特别注意的是,如果协议字段本身是一个javabean,那么该字段也需要与Message同样的申明。

业务协议绑定

  1. 一个模块的所有业务处理都放在一个门面层进行统一管理,门面类以_Facade作为后缀,并用spring的@Controller注解。
  2. 绑定请求消息与对应的Method方法,使用@MessageMapper注解(也允许不申明该注解),获取请求参数后,转交给对应的业务管理类。
  3. 业务类以_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命令,可以视为游戏的金手指,允许你快速修改内存数据。笔者见过很多的游戏项目,所有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));
	}

}  

Getting Started

Communicaiton

Clone this wiki locally