【redis的使用、账号流程、游戏服Handler的反射调用】1.自增id 2.全局用户名这样子名字唯一 3.

发布于:2024-12-21 ⋅ 阅读:(208) ⋅ 点赞:(0)

一、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);
        }
    }


网站公告

今日签到

点亮在社区的每一天
去签到