【redis的使用、账号流程、游戏服Handler的反射调用】1.自增id 2.全局用户名这样子名字唯一 3.
一、web服
1)账号注册 // 用于唯一命名服务
com.xinyue.game.center.business.account.logic.AccountRegisterService#accountRegister
public void accountRegister(AccountEntity account) {
accountManager.checkUsername(account.getUsername());
accountManager.checkPassword(account.getPassword());
checkUsernameHaveRegister(account.getUsername());
// 注册的用户名,立马用redis保存下
boolean saveResult = accountRedisManager.saveUsername(account.getUsername());
if (saveResult) {
AccountEntity saveAccount = accountDao.save(account);
account.setId(saveAccount.getId());
logger.info("用户注册成功,username:{}", account.getUsername());
} else {
throw ServerErrorCode.ACCOUNT_1005.exception();
}
}
唯一性实现
public boolean saveUsername(String username) {
String value = String.valueOf(System.currentTimeMillis());
return redisTemplate.opsForValue().setIfAbsent(username, value, Duration.ofHours(USERNAME_EXPIRE_HOURS));
}
经过注册后,进行登录
2)角色注册 / redis自增
com.xinyue.game.center.business.role.RoleService#createRole
public CreateRoleResponse createRole(CreateRoleRequest createRoleParam) throws Exception {
AccountEntity accountEntity = accountService.getAndCheckAccount(createRoleParam.getUserId());
createRoleManager.checkNicknameSensitive(createRoleParam.getNickname());
createRoleManager.checkRoleExist(accountEntity, createRoleParam.getZoneId());
// 创建角色,这一步是会使用redis的自增
PlayerEntity roleEntity = createRoleManager.createRole(createRoleParam);
ZoneRoleEntity zoneRoleEntity = createRoleManager.getZoneRole(roleEntity);
accountEntity.getSectionPlayerMap().put(createRoleParam.getZoneId(), zoneRoleEntity);
accountService.updateAccount(accountEntity);
CreateRoleResponse createRoleResponse = new CreateRoleResponse();
createRoleResponse.setPlayerId(zoneRoleEntity.getPlayerId());
createRoleResponse.setNickname(roleEntity.getNickname());
createRoleResponse.setCreateTime(roleEntity.getCreateTime());
createRoleResponse.setLastLoginTime(roleEntity.getCreateTime());
String token = this.createToken(roleEntity);
createRoleResponse.setToken(token);
return createRoleResponse;
}
自增实现
public String generateRoleId(String zoneId) {
String key = getKey(zoneId);
long roleId = redisTemplate.opsForValue().increment(key);
return zoneId + "_" + roleId;
}
二、游戏服
1.请求进入游戏 // 携带userId 和 playerId和token
com.xinyue.game.server.logic.player.PlayerHandler#enterGame
@GameMapping(EnterGameRequest.class)
public void enterGame(GameChannelContext ctx, EnterGameRequest request) {
String userId = request.getUserId();
userService.checkUserId(userId);
userService.checkToken(userId, request.getToken());
logger.debug("用户认证成功,userId: {},token:{}", userId, request.getToken());
this.bindChannel(ctx.getNettyCtx(), request.getPlayerId());
gameAsyncTaskService.execute(request.getPlayerId(), "获取玩家信息", () -> {
PlayerEntity playerEntity = playerCacheService.getPlayerOrLoading(request.getPlayerId());
if (playerEntity == null) {
ctx.writeAndFlush(EnumGameError.ROLE_NOT_EXIST);
} else {
EnterGameResponse response = new EnterGameResponse();
response.setRole(playerEntity);
ctx.writeAndFlush(response);
}
});
}
可见,核心是GameChannelContext!!!
这个上下文是如何构建的呢?
com.xinyue.server.framework.handler.GameRequestDispatcherHandler#channelRead
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof GameMessagePackage) {
try {
GameMessagePackage request = (GameMessagePackage) msg;
IGameMessage gameMessage = request.getBody();
GameMessageHeader header = request.getHeader();
// 重点就是这一步了
GameChannelContext gtx = new GameChannelContext(ctx, header);
IGameMessage requestMessage = gameMessage;
int messageId = header.getLogicMessageId();
int messageType = GameMessageType.REQUEST.getType();
MessageClassKey classKey = new MessageClassKey(messageId, messageType);
GameHandlerMappingManager gameHandlerMappingManager = GameHandlerMappingManager.getInstance();
// 进行反射调用。 这一步的消息其实可以包装到上下文中。
gameHandlerMappingManager.callMethod(gtx, classKey, requestMessage);
} catch (Throwable e) {
logger.error("处理客户端请求异常", e);
}
} else {
logger.warn("收到非游戏对象请求数据:{}", msg.getClass().getName());
ctx.fireChannelRead(msg);
}
}