代码组织与约定
这里给出一些关于代码的命名约定,与项目的代码组织。
目的
- 减轻接手二手项目人员的负担,因为我们也有可能成为接手人员。
- 让团队新进成员快速的熟悉整个项目脉络。
路由
一个游戏项目,通常由多个模块组成,每个模块下会有多个业务方法。 将所有模块的主路由定义到一个接口中,并统一命名为 CmdModule。
每个模块单独一个文件,而每个模块文件管理对应的业务方法。 模块文件命名以 xxxCmd 结尾,单独模块下主路由统一命名为 cmd。
public interface CmdModule {
int userCmd = 1;
int emailCmd = 2;
}
public interface UserCmd {
int cmd = CmdModule.userCmd;
int loginVerify = 1;
}
public interface EmailCmd {
int cmd = CmdModule.emailCmd;
int openEmail = 1;
int listEmail = 2;
}
如果你将来接手了一个二手项目是遵循这些约定的,那么你可以通过 CmdModule.java 文件查看当前项目有多少个模块。 通过对应的模块文件,可以查看该模块下有多少个业务方法。
关于命名,可以使用标准的接口属性命名,全大写加下划线分割, 也可以使用驼峰命名,个人倾向使用驼峰命名。
广播路由
建议在路由文件中添加一个广播起始标记,这种方式可以让我们不需要关注具体的路由值。
public interface RoomCmd {
int cmd = 1;
...
/** broadcastIndex. cn:广播起始 */
AtomicInteger inc = new AtomicInteger(50);
CmdInfo enterRoomBroadcast = CmdInfo.of(cmd, inc.getAndIncrement());
CmdInfo quitRoomBroadcast = CmdInfo.of(cmd, inc.getAndIncrement());
}
// test example
@ActionController(RoomCmd.cmd)
public class RoomAction {
@ActionMethod(RoomCmd.enterRoom)
public void enterRoom(FlowContext flowContext) {
...
flowContext.broadcast(RoomCmd.enterRoomBroadcast, yourData);
}
}
Action
Action 类的命名建议使用 xxxAction 结尾。
@ActionController(UserCmd.cmd)
public class UserAction {
@ActionMethod(UserCmd.loginVerify)
public void loginVerify(String jwt) {
}
}
异常枚举
推荐使用枚举实现接口的方式,这样可以很方便的管理异常消息。
建议统一命名为 GameCode。
@Getter
public enum GameCode implements MsgExceptionInfo {
emailChecked(100, "Email error.");
final int code;
final String msg;
GameCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
使用示例
@ActionController(EmailCmd.cmd)
public class EmailAction {
@ActionMethod(EmailCmd.openEmail)
public void openEmail(String email) {
Pattern pattern = Pattern.compile("[a-zA-Z0-9_-]+@\\w+\\.[a-z]+(\\.[a-z]+)?");
var checkedResult = pattern.matcher(email).find();
GameCode.emailChecked.assertTrue(checkedResult);
}
}
数据协议
在简单介绍中,我们知道了如何自定义一个协议文件。 数据协议是纯 java 代码编写的,使用的是 jprotobuf,jprotobuf 是对 google protobuf 的简化使用,性能同等。
可以把这理解成 DTO、POJO、业务数据载体等,其主要目的是用于业务数据的传输。
标准的数据协议定义如下
- code 1,标记为 Protobuf。
- code 2,所有成员属性统一使用 public。
- code 3,数据协议类名以 xxMessage 结尾。
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class HelloMessage {
String name;
int level;
}
所有成员属性统一使用 public 能明确知道该数据协议类没有使用 setter、getter 做逻辑加工处理, 另外一点是原生的 proto 也不能在 setter、getter 内做逻辑加工处理。
当数据协议使用了 setter、getter,我们能快速的知道该数据协议类在里面做了一些额外的逻辑处理。
游戏逻辑服
游戏逻辑服的命名建议以 "xxLogicServer" 结尾。
public class UserLogicServer extends AbstractBrokerClientStartup {
@Override
public BarSkeleton createBarSkeleton() {
...
}
@Override
public BrokerClientBuilder createBrokerClientBuilder() {
BrokerClientBuilder builder = BrokerClient.newBuilder();
builder.appName("UserLogicServer");
return builder;
}
}
项目结构
- code 1,Broker(游戏网关),及相关扩展。
- code 4,游戏对外服,及相关扩展。
- code 7,该目录存放所有的游戏逻辑服模块。
- code 10,单体启动入口,方便日常开发。
- code 13,模拟客户端,方便日常模拟测试。
- code 16,该目录存放所有的游戏逻辑服模块对外提供服务的数据, 如路由、数据协议、访问该模块对应的游戏逻辑服接口。
- code 17,公共的模块包,提供给所有模块使用。如 CmdModule、公共的数据协议、公用类...等。
├── broker
│ ├── pom.xml
│ └── src
├── external
│ ├── pom.xml
│ └── src
├── logic
│ ├── email-logic
│ └── user-logic
├── one-application
│ ├── pom.xml
│ └── src
├── one-client
│ ├── pom.xml
│ └── src
└── provide
├── common-provide
├── email-provide
└── user-provide