玩家登录
介绍
本篇,我们将介绍玩家登录功能。学习完后,你将可以完成登录、顶号、禁止重复登录等功能。
登录
我们定义了两个数据协议 LoginVerify
和 UserInfo
,用于处理登录业务。
- code 10,flowContext.bindingUserId 方法是登录的关键代码, 目的是在对外服的 channel 中设置用户的真实 userId。 之后用户的每次请求,可以通过 FlowContext 来获取该玩家的相关信息, FlowContext 是玩家这一次请求的上下文。
@ActionController(1)
public class LoginAction {
@ActionMethod(1)
public UserInfo loginVerify(LoginVerify loginVerify, FlowContext flowContext) {
String jwt = loginVerify.jwt;
// get user by jwt
UserInfo userInfo = ...;
long userId = userInfo.id;
boolean success = flowContext.bindingUserId(userId);
if (!success) {
// assert code
...
}
return userInfo;
}
}
@ProtobufClass
public class LoginVerify {
public String jwt;
}
@ProtobufClass
public class UserInfo {
public long userId;
public String name;
}
warning
一定要调用框架提供的这个方法才算是用户验证成功,否则后续在 FlowContext 上下文中拿不到 userId。
禁止重复登录
禁止重复登录指的是相同的号已经在线上了,不能重复登录该账号了。 登录相关的代码,在综合示例中。
- code 8,检测玩家是否在线。
- code 9,断言+异常机制,如果玩家在线就返回错误码给请求端。
- code 11,登录。
@ActionMethod(1)
public UserInfo loginVerify(LoginVerify loginVerify, FlowContext flowContext) {
// get user by jwt
UserInfo userInfo = ...
long userId = userInfo.id;
boolean existUser = ExternalCommunicationKit.existUser(userId);
GameCode.accountOnline.assertTrueThrows(existUser);
boolean success = flowContext.bindingUserId(userId);
...
return userInfo;
}
@Getter
public enum GameCode implements MsgExceptionInfo {
accountOnline(100, "User Online");
final int code;
final String msg;
GameCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
顶号
顶号指的是相同的号已经在线上了,把在线上的号顶下线,以最后一次登录为准。
- code 8,强制指定玩家下线。
- code 10,登录。
@ActionMethod(1)
public UserInfo loginVerify(LoginVerify loginVerify, FlowContext flowContext) {
// get user by jwt
UserInfo userInfo = ...
long userId = userInfo.id;
ExternalCommunicationKit.forcedOffline(userId);
boolean success = flowContext.bindingUserId(userId);
...
return userInfo;
}
UserId
登录后,可以通过 FlowContext 来获取玩家 userId。
@ActionMethod(2)
public long hello(FlowContext flowContext) {
return flowContext.getUserId();
}
userId 可以支持 String 类型的 Id 吗?
业务需求: 如果 userId 不是 long 类型的怎么办?我使用的是 MongoDB objectId 是 String 类型的。
ioGame 是一个扩展性极强的框架,这样的需求也是支持扩展的。扩展步骤如下
- 给用户数据关联一个 long 类型的 id,比如 Snowflake。
- 将 objectId 存放到元信息-附加信息中
- 配合自定义FlowContext
@ProtobufClass
public class MyAttachment implements Attachment {
@Getter
long userId;
/** MongoDB objectId */
public String objectId;
}
public class MyFlowContext extends FlowContext {
public String getUserIdString() {
var attachment = this.getAttachment(MyAttachment.class);
return attachment.objectId;
}
}