diff --git a/.gitignore b/.gitignore index 434f26077c90e38a92b351d32d51337dc4de65d0..35d1e72d5bf4043cfaeb7176ef08a8ba8e1a505e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,7 @@ hs_err_pid* # target -target/ \ No newline at end of file +target/ + +# protobuf-itl +proto/ \ No newline at end of file diff --git a/README.md b/README.md index b94d7319d8fe29571b02923aded5205b9b001be5..89dc6cbebaf2740cb437000794a02c7a36e654de 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,150 @@ # paradogs #### 介绍 -一个基于 Java、Netty、发布订阅驱动的分布式游戏服务端框架 +一个基于 Java、Netty、的分布式游戏服务端框架,有疑问可以联系 Q410408824 #### 软件架构 -软件架构说明 +- 基础:SpringBoot +- 网络:Netty、protobuf (JProtobuf) +- 持久化:Mybatis-PlusS +- Excel 数据:easyExcel +- 代码生成:Freemarker +#### 快速开始 -#### 安装教程 +##### 启动 +1. 修改每个服的 mysql 连接配置为自己的连接地址 +```yaml +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/paradogs_game?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8 + username: root + password: root +``` +2. **启动中心服**:paradogs-demo-master | DemoMasterApplication +3. **启动登录服**:paradogs-demo-login | DemoMasterApplication +4. **启动逻辑服**:paradogs-demo-logic | DemoMasterApplication +5. **启动网关服**:paradogs-demo-gate | DemoMasterApplication +6. **运行简单客户端测试**:paradogs-demo-client | DemoClientApplication + +##### 请求处理操作 +- **@PRController** 声明请求处理类 +- **@PRMsgMapping** 请求映射地址,可加在类和方法上,下例的请求地址映射为 **"[serverType]|misc.hello"** 和 **"[serverType]|misc.helloAsync"** +- **请求参数**:任意类型对象,需要有 **@ProtobufClass** 或 @Protobuf 修饰 +- **返回值**:如果有返回值,会自动将返回值作为回复消息,向发送方进行回复,需要有 **@ProtobufClass** 或 @Protobuf 修饰 +- **异步操作**:由于 Netty 基于 NIO,如果消息处理过程中有阻塞操作,需要改为异步执行,**设置 @PRMsgMapping 的 async 为 true** 表示是一个异步操作方法,一般不怎么使用,常用于服务器内部相互调用 +```java + +@PRController +@PRMsgMapping("misc") +public class LoginController { + @PRMsgMapping("hello") + public GCAck hello(LongWrapper wrapper) { + log.info("hello game !!!"); + return GCAck.success(); + } + @PRMsgMapping(value = "helloAsync", async = true) + public GCAck helloAsync() { + log.info("================ helloAsync game !!!"); + return GCAck.success(); + } +} +``` +```java +@Data +@ProtobufClass +public class LongWrapper { // 消息实体类 + private Long val; +} +``` + +##### RPC 请求操作 +- **@PRClient** 定义一个 RPC 请求类,指定请求的服务器类型 +- **@PRRPCMapping** 指定 RPC 请求的路由地址 +```java +@PRClient("logic") +public interface LogicClient { + + @PRRPCMapping("misc.loadPlayer") + GCAck loadPlayer(LongWrapper uid); + + @PRRPCMapping("misc.firstSyncData") + void firstSyncData(); +} +``` +- 调用方式 +- 注意 RPC **阻塞操作**,需要加异步 +```java +@Slf4j +@PRController +public class GateController { + @Autowired + private LogicClient logicClient; + + @PRMsgMapping(value = "login", async = true) + public GCAck login(CGGateLogin msg) { + logicClient.loadPlayer(new LongWrapper(1L)); + } +} +``` -1. xxxx -2. xxxx -3. xxxx #### 使用说明 +1. 引入对应的服务器支持依赖(logic 服举例) +```maven + + com.paradogs + paradogs-framework-server-starter + +``` +2. 在启动类上添加 @EnableParadogs 注解(logic 服举例) +```java +@EnableParadogs +@SpringBootApplication +public class DemoLogicApplication { + public static void main(String[] args) { + SpringApplication.run(DemoLogicApplication.class, args); + } +} +``` +3. 配置 application.yml +- master: 中心服配置 +```yaml +paradogs: +server: +port: 8888 +type: master +name: master-1 +master: true # 设置为 true 表示为 master 服 +``` +- server: 普通服配置 +```yaml +paradogs: + server: + port: 8090 + type: logic # 服务器类型 + key: logic-1 # 服务器唯一标识 + master: # master 服务器地址 + host: localhost + port: 8888 +``` +- gate: 前端服配置(供客户端直接连接) +```yaml +paradogs: + server: + port: 8001 + type: gate # 服务器类型 + key: gate-1 # 服务器唯一标识 + master: # master 服务器地址 + host: localhost + port: 8888 + clients: # 需要连接的服务器 + - host: localhost + port: 8090 + type: logic # 服务器类型 +``` -1. xxxx -2. xxxx -3. xxxx #### 参与贡献 diff --git a/paradogs-demo/paradogs-demo-client/src/main/java/com/paradogs/demo/client/DemoClientApplication.java b/paradogs-demo/paradogs-demo-client/src/main/java/com/paradogs/demo/client/DemoClientApplication.java index 9e12c9b9c30bf3f2e4d97dcd275b3b3e5907967e..deaaa13770bc63644120eac317b7948ac8296fff 100644 --- a/paradogs-demo/paradogs-demo-client/src/main/java/com/paradogs/demo/client/DemoClientApplication.java +++ b/paradogs-demo/paradogs-demo-client/src/main/java/com/paradogs/demo/client/DemoClientApplication.java @@ -2,10 +2,10 @@ package com.paradogs.demo.client; import com.paradogs.demo.client.demo.Client; import com.paradogs.demo.client.pojo.CGLogin; -import com.paradogs.framework.common.pojo.cg.CGGatewayLogin; -import com.paradogs.framework.common.pojo.gc.GCAllocGateway; +import com.paradogs.framework.common.pojo.cg.CGGateLogin; import com.paradogs.framework.common.pojo.gc.GCApplyGate; import com.paradogs.framework.core.msg.ByteData; +import com.paradogs.framework.core.msg.R; import com.paradogs.framework.core.netty.PRCodec; import com.paradogs.framework.core.utils.ProtoUtils; import io.netty.bootstrap.Bootstrap; @@ -17,6 +17,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -77,15 +78,31 @@ public class DemoClientApplication { channel.pipeline().addLast(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext ctx, ByteData msg) throws Exception { - log.info("Receive: {}", msg); - Client.send(ctx.channel(), "logic|misc.hello", new CGGatewayLogin("123")); + if (msg.getMsgHeader().getRoute().equals("syncData")) { + R result = ProtoUtils.decode(msg.getDataBytes(), R.class); + log.info("Receive: {}", result); + } else { + log.info("Receive: {}", msg); + } } }); } }); Channel gateChannel = client.connect(result.getHost(), result.getPort()).sync().channel(); log.info("Connect Gate success"); - Client.send(gateChannel, "gate|login", new CGGatewayLogin(result.getToken())); + Client.send(gateChannel, "gate|login", new CGGateLogin(result.getToken())); + + Thread.sleep(1000); + new Thread(new Runnable() { + @SneakyThrows + @Override + public void run() { + while (true) { + Client.send(gateChannel, "logic|misc.updateData", new CGGateLogin("123")); + Thread.sleep(199999000); + } + } + }).start(); } }); @@ -94,6 +111,6 @@ public class DemoClientApplication { Channel channel = client.connect("localhost", 80).sync().channel(); - Client.send(channel, "login|applyGate", new CGLogin("yumi", "123")); + Client.send(channel, "login|login", new CGLogin("yumi", "123")); } } diff --git a/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/controller/GateController.java b/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/controller/GateController.java index 12499bce91c49f5f1358e829fa95c0b80395022b..f0b399987e5a6098acd8943485c2e8b47ce242e4 100644 --- a/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/controller/GateController.java +++ b/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/controller/GateController.java @@ -2,20 +2,19 @@ package com.paradogs.demo.gate.controller; import com.paradogs.demo.gate.misc.PlayerOnlineHolder; import com.paradogs.demo.gate.rpc.LogicClient; -import com.paradogs.framework.common.pojo.cg.CGGatewayLogin; +import com.paradogs.framework.common.pojo.cg.CGGateLogin; import com.paradogs.framework.common.pojo.cg.CGPrepareLogin; import com.paradogs.framework.common.pojo.misc.LongWrapper; import com.paradogs.framework.core.annoations.request.PRController; import com.paradogs.framework.core.annoations.request.PRMsgMapping; import com.paradogs.framework.core.msg.GCAck; -import com.paradogs.framework.core.utils.PRAsync; +import com.paradogs.framework.core.msg.PRMsgContextHolder; +import com.paradogs.framework.core.msg.R; +import com.paradogs.framework.core.utils.MsgUtils; +import com.paradogs.framework.gate.GateChannelHolder; +import io.netty.channel.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Async; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; /** * @author: yumi @@ -48,13 +47,27 @@ public class GateController { * @return */ @PRMsgMapping(value = "login", async = true) - public GCAck login(CGGatewayLogin msg) { + public GCAck login(CGGateLogin msg) { PlayerOnlineHolder.WillLoginInfo info = playerOnlineHolder.get(msg.getToken()); if (info != null) { + // 绑定 Channel 所属玩家信息,待优化:登录功能可以放在 gate-starter 模块里 + GateChannelHolder.bindSession(PRMsgContextHolder.getChannel(), new GateChannelHolder.Session(info.getUid())); logicClient.loadPlayer(new LongWrapper(info.getUid())); + playerOnlineHolder.removeToken(msg.getToken()); return GCAck.success(); } return GCAck.fail(); } + /** + * 同步玩家自身数据 + */ + @PRMsgMapping("syncData") + public void syncData(R syncData) { + Channel channel = GateChannelHolder.getPlayerChannel(syncData.getPlayerId()); + if (channel != null) { + MsgUtils.send("syncData", syncData, channel); + } + } + } diff --git a/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/rpc/LogicClient.java b/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/rpc/LogicClient.java index 0ff2a287b90cd34b0c4836a0bfffce712f8634de..3fc2acc195a7ff9c8f563c0270228079145cd960 100644 --- a/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/rpc/LogicClient.java +++ b/paradogs-demo/paradogs-demo-gate/src/main/java/com/paradogs/demo/gate/rpc/LogicClient.java @@ -15,4 +15,7 @@ public interface LogicClient { @PRRPCMapping("misc.loadPlayer") GCAck loadPlayer(LongWrapper uid); + + @PRRPCMapping("misc.firstSyncData") + void firstSyncData(); } diff --git a/paradogs-demo/paradogs-demo-logic/pom.xml b/paradogs-demo/paradogs-demo-logic/pom.xml index 2f654767309c5cd830e2a4bf457cce65652041a8..d480ba78bb5127378c1a3e6de2d6a8aa169fe830 100644 --- a/paradogs-demo/paradogs-demo-logic/pom.xml +++ b/paradogs-demo/paradogs-demo-logic/pom.xml @@ -21,6 +21,10 @@ com.paradogs paradogs-framework-server-starter + + org.springframework.boot + spring-boot-starter-aop + \ No newline at end of file diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/controller/LoginController.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/controller/LoginController.java index ca18e5d570616801023e8fee77076c13033fb768..ccf59144017ee512f092c0c5f6eac0d6dd1010bd 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/controller/LoginController.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/controller/LoginController.java @@ -1,16 +1,18 @@ package com.paradogs.demo.logic.controller; import com.paradogs.demo.logic.event.PlayerLoginEvent; -import com.paradogs.demo.logic.manager.base.PlayerTemplate; +import com.paradogs.demo.logic.misc.PlayerOnlineHolder; +import com.paradogs.demo.logic.misc.PlayerTemplate; +import com.paradogs.framework.common.entity.Role; import com.paradogs.framework.common.pojo.misc.LongWrapper; import com.paradogs.framework.core.annoations.request.PRController; import com.paradogs.framework.core.annoations.request.PRMsgMapping; import com.paradogs.framework.core.msg.GCAck; +import com.paradogs.framework.core.msg.PRMsgContextHolder; import com.paradogs.framework.core.utils.EventUtils; -import com.paradogs.framework.core.utils.PRAsync; +import com.paradogs.framework.core.utils.MsgUtils; import lombok.extern.slf4j.Slf4j; - -import java.util.concurrent.CompletableFuture; +import org.springframework.beans.factory.annotation.Autowired; /** * @author: yumi @@ -22,6 +24,9 @@ import java.util.concurrent.CompletableFuture; @PRMsgMapping("misc") public class LoginController { + @Autowired + private PlayerOnlineHolder playerOnlineHolder; + @PRMsgMapping(value = "loadPlayer", async = true) public GCAck loadPlayer(LongWrapper wrapper) { // 初始化玩家数据 @@ -38,5 +43,25 @@ public class LoginController { return GCAck.success(); } + @PRMsgMapping(value = "helloAsync", async = true) + public GCAck helloAsync() { + log.info("================ helloAsync game !!!"); + return GCAck.success(); + } + + @PRMsgMapping("firstSyncData") + public void firstSyncData() { + System.out.println("1"); + } + + /** + * 打怪测试 + */ + @PRMsgMapping("addExp") + public void kill() { + PlayerTemplate player = playerOnlineHolder.getPlayer(PRMsgContextHolder.getPlayerId()); + player.getRoleManager().addExp(); + } + } diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/event/PlayerLoginEvent.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/event/PlayerLoginEvent.java index ca638a9836ce42ebd9fca88865621b3cc3f185ca..c85f87d2b71fe5dada4c74f5b1589f66dc7a7052 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/event/PlayerLoginEvent.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/event/PlayerLoginEvent.java @@ -1,6 +1,6 @@ package com.paradogs.demo.logic.event; -import com.paradogs.demo.logic.manager.base.PlayerTemplate; +import com.paradogs.demo.logic.misc.PlayerTemplate; import com.paradogs.framework.common.events.base.AnonEvent; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/PlayerManager.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/InventoryManager.java similarity index 56% rename from paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/PlayerManager.java rename to paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/InventoryManager.java index 8b3bd7eebd6e1b48aa8eaa17c524b10ebba5b640..8dcc1d62e7e81b67ce9b3abca0db71a9fe205965 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/PlayerManager.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/InventoryManager.java @@ -1,18 +1,17 @@ package com.paradogs.demo.logic.manager; -import com.paradogs.framework.common.dao.PlayerDao; -import com.paradogs.framework.common.entity.Player; import com.paradogs.demo.logic.manager.base.BaseManager; +import com.paradogs.framework.common.dao.InventoryDao; +import com.paradogs.framework.common.entity.Inventory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; /** * @author: yumi - * @date: 2023/11/23 14:01 + * @date: 2023/11/30 15:21 * @Description: TODO */ -@Scope("prototype") @Component -public class PlayerManager extends BaseManager { - +@Scope("prototype") +public class InventoryManager extends BaseManager { } diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/RoleManager.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/RoleManager.java new file mode 100644 index 0000000000000000000000000000000000000000..c78e53ce3dcd7f838f05e7ae02210aff918e6794 --- /dev/null +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/RoleManager.java @@ -0,0 +1,28 @@ +package com.paradogs.demo.logic.manager; + +import com.paradogs.demo.logic.manager.base.BaseManager; +import com.paradogs.framework.common.dao.RoleDao; +import com.paradogs.framework.common.entity.Role; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * @author: yumi + * @date: 2023/11/30 15:22 + * @Description: TODO + */ +@Component +@Scope("prototype") +public class RoleManager extends BaseManager { + + public void addExp() { + Role role = getData(); + role.setExp(role.getExp() + 100); + if (role.getExp() > 499) { + role.setExp(role.getExp() - 499); + role.setLevel(role.getLevel() + 1); + } + updateData(role); + } + +} diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/BaseManager.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/BaseManager.java index ff08883dbc2ae1e7a1fdd083dd9780b5c284ccff..bea9765acccb3bad4ca41109d9f6b76a655d8fa7 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/BaseManager.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/BaseManager.java @@ -2,9 +2,13 @@ package com.paradogs.demo.logic.manager.base; import com.baomidou.mybatisplus.extension.service.IService; import com.paradogs.framework.common.entity.base.BaseEntity; +import com.paradogs.framework.core.queue.DBUpdatMsg; +import com.paradogs.framework.core.queue.PRQueueHolder; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; /** @@ -13,31 +17,85 @@ import org.springframework.beans.factory.annotation.Autowired; * @Description: TODO */ @Slf4j -public abstract class BaseManager> { +public abstract class BaseManager> { @Autowired private D dao; + @Setter + private E data; + + public E getData() { + E e = null; + try { + e = dao.getEntityClass().newInstance(); + } catch (InstantiationException instantiationException) { + instantiationException.printStackTrace(); + } catch (IllegalAccessException illegalAccessException) { + illegalAccessException.printStackTrace(); + } + BeanUtils.copyProperties(data, e); + return e; + } + + /** + * 数据是否被修改并且未同步到客户端 + */ @Getter @Setter - private T entity; + private boolean dirty; /** * 加载玩家数据 * @param uid */ public void loadData(Long uid) { - this.entity = dao.getById(uid); - if (this.entity == null) { + this.data = dao.getById(uid); + this.dirty = true; + if (this.data == null) { try { - this.entity = dao.getEntityClass().newInstance(); + this.data = dao.getEntityClass().newInstance(); + this.data.setUid(uid); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } - log.debug("Load {}: {}", this.getClass().getSimpleName(), this.entity); + log.debug("Load {}: {}", this.getClass().getSimpleName(), this.data); + } + + /** + * 复制一份数据 + * @return + */ + public E copyData() { + if (this.data == null) { + return null; + } + E copy = null; + try { + copy = dao.getEntityClass().newInstance(); + BeanUtils.copyProperties(this.data, copy); + } catch (InstantiationException | IllegalAccessException e) { + log.error("Error copying data", e); + } + return copy; + } + + /** + * 更新数据,待优化:数据值真实变化时再改变状态位 + * @param data + */ + public void updateData(E data) { + if (!this.data.equals(data)) { + this.data = data; + this.dirty = true; + PRQueueHolder.putMsg(PRQueueHolder.QueueType.DB, new DBUpdatMsg(data.getUid(), dao, data)); + } + } + public void setData(E data) { + updateData(data); } /** diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerOnlineHolder.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerOnlineHolder.java index 4a7d46b2d2e2b772e153d51c41d23463b2059547..09d96252cde94efab33c711d9de3fb2ccfe49b97 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerOnlineHolder.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerOnlineHolder.java @@ -2,7 +2,6 @@ package com.paradogs.demo.logic.misc; import com.paradogs.demo.logic.event.PlayerLoginEvent; import com.paradogs.demo.logic.event.PlayerLogoutEvent; -import com.paradogs.demo.logic.manager.base.PlayerTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -24,6 +23,11 @@ public class PlayerOnlineHolder { */ private Map onlinePlayerMap = new HashMap<>(); + + public PlayerTemplate getPlayer(Long uid) { + return onlinePlayerMap.get(uid); + } + @EventListener(PlayerLoginEvent.class) public void PlayerLoginEventHandler(PlayerLoginEvent event) { onlinePlayerMap.put(event.getUid(), event.getPlayerTemplate()); diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/PlayerTemplate.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerTemplate.java similarity index 51% rename from paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/PlayerTemplate.java rename to paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerTemplate.java index 28ea8b70f258f38ffea5a86f1d666133b8cc6ecd..bba63a00407d902cff0cfad67f0554b2c5c40c5d 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/manager/base/PlayerTemplate.java +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/PlayerTemplate.java @@ -1,10 +1,18 @@ -package com.paradogs.demo.logic.manager.base; +package com.paradogs.demo.logic.misc; -import com.paradogs.demo.logic.manager.PlayerManager; +import com.paradogs.demo.logic.manager.InventoryManager; +import com.paradogs.demo.logic.manager.RoleManager; +import com.paradogs.demo.logic.manager.base.BaseManager; +import com.paradogs.framework.common.entity.base.BaseEntity; +import com.paradogs.framework.core.utils.BeanUtils; import com.paradogs.framework.core.utils.SpringUtils; import lombok.Data; +import lombok.EqualsAndHashCode; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; /** * @author: yumi @@ -19,7 +27,18 @@ public class PlayerTemplate { */ private Long uid; - private PlayerManager playerManager; + /** + * 角色相关 + */ + private RoleManager roleManager; + + /** + * 库存系统 + */ + private InventoryManager inventoryManager; + + + private List managers = new ArrayList<>(); public PlayerTemplate(Long uid) { /** @@ -33,6 +52,7 @@ public class PlayerTemplate { // 加载数据 manager.loadData(uid); field.set(this, manager); + managers.add(manager); } catch (IllegalAccessException e) { e.printStackTrace(); } @@ -40,4 +60,9 @@ public class PlayerTemplate { } } + public List copyData() { + List dataList = managers.stream().map(manager -> manager.copyData()).collect(Collectors.toList()); + return dataList; + } + } diff --git a/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/SyncAspect.java b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/SyncAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..2c761fca251d1709d4bbe80d664cd176f314a1fd --- /dev/null +++ b/paradogs-demo/paradogs-demo-logic/src/main/java/com/paradogs/demo/logic/misc/SyncAspect.java @@ -0,0 +1,72 @@ +package com.paradogs.demo.logic.misc; + +import com.paradogs.demo.logic.manager.base.BaseManager; +import com.paradogs.framework.core.annoations.request.PRMsgMapping; +import com.paradogs.framework.core.msg.PRMsgContextHolder; +import com.paradogs.framework.core.msg.R; +import com.paradogs.framework.core.utils.MsgUtils; +import com.paradogs.framework.core.utils.ReflectUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * @author: yumi + * @date: 2023/11/30 17:55 + * @Description: 检查和同步玩家数据变化的切面 + */ +@Slf4j +@Aspect +@Order(Integer.MAX_VALUE) +@Component +public class SyncAspect { + + @Autowired + private PlayerOnlineHolder onlineHolder; + + /** + * 对 @PRMsgMapping 注解方法切面,用于检查和同步玩家数据变化 + * - @within(com.paradogs.framework.core.annoations.request.PRController) && + * @param joinPoint + * @param msgMapping + * @return + * @throws Throwable + */ + @Around("@annotation(msgMapping)") + public Object aroundPRMsgMappingMethods(ProceedingJoinPoint joinPoint, PRMsgMapping msgMapping) throws Throwable { + Object result = joinPoint.proceed(); // 执行目标方法 + Long uId = PRMsgContextHolder.getPlayerId(); + PlayerTemplate template = onlineHolder.getPlayer(uId); + /** + * 玩家数据发生变化时,同步数据(先发送同步消息再发送回复消息) + * 待优化: + * 1. 目前变化时同步整个类,可以改成同步类中单个字段 + * 2. syncData 消息和 reply 消息合并发送:合并成同一个类或 write() 不 flush ? + */ + if (template != null) { + R syncData = R.success(result); + boolean needSync = false; + for (BaseManager manager : template.getManagers()) { + if (manager.isDirty()) { + ReflectUtils.callSetter(syncData, manager.getData().getClass().getSimpleName(), manager.getData()); + needSync = true; + } + } + // 如果玩家数据变化,则同步玩家数据 + if (needSync) { + syncData.setPlayerId(uId); + MsgUtils.send("gate|syncData", syncData, PRMsgContextHolder.getChannel()); + log.debug("数据变化,同步玩家数据: {}", syncData); + } + // 更新数据状态 + template.getManagers().forEach(manager -> manager.setDirty(false)); + } + + return result; + } + +} diff --git a/paradogs-demo/paradogs-demo-logic/src/main/resources/application.yml b/paradogs-demo/paradogs-demo-logic/src/main/resources/application.yml index 0d96fe13a8c5c11ee77ccb9a0d1639f29f971932..9296e8c438d9a5143d61b4f653d58eb311ad88c6 100644 --- a/paradogs-demo/paradogs-demo-logic/src/main/resources/application.yml +++ b/paradogs-demo/paradogs-demo-logic/src/main/resources/application.yml @@ -22,7 +22,7 @@ mybatis-plus: field-strategy: not_empty table-underline: true configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl # 日志级别配置 logging: diff --git a/paradogs-demo/paradogs-demo-login/src/main/java/com/paradogs/demo/login/controller/LoginController.java b/paradogs-demo/paradogs-demo-login/src/main/java/com/paradogs/demo/login/controller/LoginController.java index d6fd32b7c9b606b5767d98c5b625476b63abb7ce..72b0b7bcd3a647e13d394d10cadecb684029eaf2 100644 --- a/paradogs-demo/paradogs-demo-login/src/main/java/com/paradogs/demo/login/controller/LoginController.java +++ b/paradogs-demo/paradogs-demo-login/src/main/java/com/paradogs/demo/login/controller/LoginController.java @@ -38,7 +38,7 @@ public class LoginController { @Autowired private PlayerDao playerDao; - @PRMsgMapping(value = "applyGate", async = true) + @PRMsgMapping(value = "login", async = true) public GCApplyGate login(CGLogin dto) { Player player = playerDao.getOne(Wrap.lbq() .eq(Player::getAccount, dto.getAccount()) diff --git a/paradogs-framework/paradogs-framework-common/pom.xml b/paradogs-framework/paradogs-framework-common/pom.xml index 1732bc1d94a79969c65358609936c6e899f83ebe..3a1ba23bcea85061870fc602166fa7ef0b585bd1 100644 --- a/paradogs-framework/paradogs-framework-common/pom.xml +++ b/paradogs-framework/paradogs-framework-common/pom.xml @@ -33,6 +33,10 @@ io.netty netty-all + + com.alibaba + easyexcel + \ No newline at end of file diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/InventoryDao.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/InventoryDao.java new file mode 100644 index 0000000000000000000000000000000000000000..8f292c0fca6c6cce43a07d1e83e400d558fe3a37 --- /dev/null +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/InventoryDao.java @@ -0,0 +1,16 @@ +package com.paradogs.framework.common.dao; + +import com.paradogs.framework.common.entity.Inventory; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author yumi + * @since 2023-11-30 + */ +public interface InventoryDao extends IService { + +} diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/PlayerDao.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/PlayerDao.java index 1d5b9128f6ac220b45cf6c59e46b67efc33bcd65..daa43dd181af5e40630f8162496921f64922ceba 100644 --- a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/PlayerDao.java +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/PlayerDao.java @@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.extension.service.IService; *

* * @author yumi - * @since 2023-11-20 + * @since 2023-11-30 */ public interface PlayerDao extends IService { diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/RoleDao.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/RoleDao.java new file mode 100644 index 0000000000000000000000000000000000000000..c74f16e47ffa75970c85d86cffdc78eac44072ad --- /dev/null +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/RoleDao.java @@ -0,0 +1,16 @@ +package com.paradogs.framework.common.dao; + +import com.paradogs.framework.common.entity.Role; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author yumi + * @since 2023-11-30 + */ +public interface RoleDao extends IService { + +} diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/InventoryDaoImpl.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/InventoryDaoImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6bc65f8ab32b5fdd755f217e87545a7e7efb93b8 --- /dev/null +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/InventoryDaoImpl.java @@ -0,0 +1,20 @@ +package com.paradogs.framework.common.dao.impl; + +import com.paradogs.framework.common.entity.Inventory; +import com.paradogs.framework.common.mapper.InventoryMapper; +import com.paradogs.framework.common.dao.InventoryDao; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 服务实现类 + *

+ * + * @author yumi + * @since 2023-11-30 + */ +@Service +public class InventoryDaoImpl extends ServiceImpl implements InventoryDao { + +} diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/PlayerDaoImpl.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/PlayerDaoImpl.java index d7650f97cebeb99b0d0cd936ecb3242f0704aa82..9399c3b872044e5a6dd10b0551b6649f5c75b8e1 100644 --- a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/PlayerDaoImpl.java +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/PlayerDaoImpl.java @@ -12,7 +12,7 @@ import org.springframework.stereotype.Service; *

* * @author yumi - * @since 2023-11-20 + * @since 2023-11-30 */ @Service public class PlayerDaoImpl extends ServiceImpl implements PlayerDao { diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/RoleDaoImpl.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/RoleDaoImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..32e1cb6596b17469e8498cfcdf1c03573c5c6a4b --- /dev/null +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/dao/impl/RoleDaoImpl.java @@ -0,0 +1,20 @@ +package com.paradogs.framework.common.dao.impl; + +import com.paradogs.framework.common.entity.Role; +import com.paradogs.framework.common.mapper.RoleMapper; +import com.paradogs.framework.common.dao.RoleDao; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 服务实现类 + *

+ * + * @author yumi + * @since 2023-11-30 + */ +@Service +public class RoleDaoImpl extends ServiceImpl implements RoleDao { + +} diff --git a/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/data/RoleLevel.java b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/data/RoleLevel.java new file mode 100644 index 0000000000000000000000000000000000000000..5617ce272ba516a6923f2d3c9262df4b840169d1 --- /dev/null +++ b/paradogs-framework/paradogs-framework-common/src/main/java/com/paradogs/framework/common/data/RoleLevel.java @@ -0,0 +1,114 @@ +package com.paradogs.framework.common.data; + +import com.paradogs.framework.common.utils.ExcelUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * RoleLevel class generated by Freemarker. + * @Description: roleLevel(玩家等级).xlsx + */ +@Slf4j +@Component +public class RoleLevel { + + private final static String fileName = "roleLevel(玩家等级).xlsx"; + + /** + * -1 项 + */ + private final static Config config; + + /** + * 数据 map[id] = data + */ + private final static Map dataMap; + + /** + * 项目启动时初始化加载 Excel 配置 + */ + static { + try { + dataMap = new LinkedHashMap<>(); + Config _config = new Config(); + File file = new File("G:/project/me/git/paradogs/paradogs-framework/paradogs-framework-common/src/main/resources/data/roleLevel(玩家等级).xlsx"); + List