|
@@ -4,13 +4,17 @@ import com.incubator.common.env.Environment;
|
|
|
import com.incubator.common.game.AbstractService;
|
|
|
import com.incubator.common.log4j.Log4jUtil;
|
|
|
import com.incubator.common.net.Connection;
|
|
|
+import com.incubator.common.net.NetClient;
|
|
|
import com.incubator.common.net.NetServer;
|
|
|
+import com.incubator.common.net.netty.client.NettyClient;
|
|
|
import com.incubator.common.net.netty.handler.websocket.binary.WebSocketServerBinaryAdapterHandler;
|
|
|
import com.incubator.common.net.netty.server.NettyServer;
|
|
|
import com.incubator.common.thread.NamedThreadFactory;
|
|
|
import com.incubator.common.util.PropertiesUtil;
|
|
|
import com.incubator.core.net.http.HttpRequestHandler;
|
|
|
import com.incubator.core.quartz.QuartzServer;
|
|
|
+import com.incubator.core.quartz.QuartzTask;
|
|
|
+import com.incubator.game.listener.CenterClientListener;
|
|
|
import com.incubator.game.listener.HttpInnerListener;
|
|
|
import com.incubator.core.net.ws.NetHandler;
|
|
|
import com.incubator.core.net.handler.InitalizerHttpServerHandler;
|
|
@@ -36,6 +40,7 @@ import java.util.*;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
public class GGame extends AbstractService {
|
|
|
|
|
@@ -154,29 +159,78 @@ public class GGame extends AbstractService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 1.初始化Properties配置
|
|
|
+ * 1. 初始化 Properties 配置
|
|
|
*
|
|
|
- * @throws Exception
|
|
|
+ * @throws Exception 如果配置加载失败
|
|
|
*/
|
|
|
public void initProperties() throws Exception {
|
|
|
- logger.info("初始化Properties配置...");
|
|
|
- SERVER_SETTINGS = new PropertiesUtil(env.getConfDir() + "/" + CONFIG_FILE);
|
|
|
- DB_SETTINGS = new PropertiesUtil(env.getConfDir() + "/" + DB_FILE);
|
|
|
+ logger.info("开始加载 Properties 配置...");
|
|
|
|
|
|
- SERVER_ID = Integer.parseInt(SERVER_SETTINGS.getProperty("SERVER_ID", "1001"));
|
|
|
-
|
|
|
- BIND_HOST = SERVER_SETTINGS.getProperty("BIND_HOST", "0.0.0.0");
|
|
|
- BIND_PORT = Integer.parseInt(SERVER_SETTINGS.getProperty("BIND_PORT", "9000"));
|
|
|
+ try {
|
|
|
+ // 加载服务器配置
|
|
|
+ SERVER_SETTINGS = loadProperties(CONFIG_FILE);
|
|
|
+ DB_SETTINGS = loadProperties(DB_FILE);
|
|
|
+
|
|
|
+ // 读取服务器配置
|
|
|
+ SERVER_ID = getIntProperty(SERVER_SETTINGS, "SERVER_ID", 1001);
|
|
|
+ BIND_HOST = getStringProperty(SERVER_SETTINGS, "BIND_HOST", "0.0.0.0");
|
|
|
+ BIND_PORT = getIntProperty(SERVER_SETTINGS, "BIND_PORT", 9000);
|
|
|
+ BIND_HTTP_HOST = getStringProperty(SERVER_SETTINGS, "BIND_HTTP_HOST", "0.0.0.0");
|
|
|
+ BIND_HTTP_PORT = getIntProperty(SERVER_SETTINGS, "BIND_HTTP_PORT", 9001);
|
|
|
+ CENTER_HOST = getStringProperty(SERVER_SETTINGS, "CENTER_HOST", "0.0.0.0");
|
|
|
+ CENTER_PORT = getIntProperty(SERVER_SETTINGS, "CENTER_PORT", 4000);
|
|
|
+ DIR_GAME_DATA = getStringProperty(SERVER_SETTINGS, "DIR_GAME_DATA", "");
|
|
|
+
|
|
|
+ logger.info("Properties 配置加载完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("加载 Properties 配置失败: {}", e.getMessage(), e);
|
|
|
+ throw new Exception("Properties 配置加载失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- BIND_HTTP_HOST = SERVER_SETTINGS.getProperty("BIND_HTTP_HOST", "0.0.0.0");
|
|
|
- BIND_HTTP_PORT = Integer.parseInt(SERVER_SETTINGS.getProperty("BIND_HTTP_PORT", "9001"));
|
|
|
+ /**
|
|
|
+ * 加载 Properties 文件
|
|
|
+ *
|
|
|
+ * @param fileName 文件名
|
|
|
+ * @return Properties 对象
|
|
|
+ * @throws Exception 如果加载失败
|
|
|
+ */
|
|
|
+ private PropertiesUtil loadProperties(String fileName) throws Exception {
|
|
|
+ String filePath = env.getConfDir() + "/" + fileName;
|
|
|
+ logger.info("加载配置文件: {}", filePath);
|
|
|
+ return new PropertiesUtil(filePath);
|
|
|
+ }
|
|
|
|
|
|
- CENTER_HOST = SERVER_SETTINGS.getProperty("CENTER_HOST", "0.0.0.0");
|
|
|
- CENTER_PORT = Integer.parseInt(SERVER_SETTINGS.getProperty("CENTER_PORT", "4000"));
|
|
|
+ /**
|
|
|
+ * 获取 String 类型属性值
|
|
|
+ *
|
|
|
+ * @param properties Properties 对象
|
|
|
+ * @param key 属性键
|
|
|
+ * @param defaultValue 默认值
|
|
|
+ * @return 属性值(如果属性不存在,则返回默认值)
|
|
|
+ */
|
|
|
+ private String getStringProperty(PropertiesUtil properties, String key, String defaultValue) {
|
|
|
+ return properties.getProperty(key, defaultValue);
|
|
|
+ }
|
|
|
|
|
|
- DIR_GAME_DATA = SERVER_SETTINGS.getProperty("DIR_GAME_DATA", "");
|
|
|
+ /**
|
|
|
+ * 获取 int 类型属性值
|
|
|
+ *
|
|
|
+ * @param properties Properties 对象
|
|
|
+ * @param key 属性键
|
|
|
+ * @param defaultValue 默认值
|
|
|
+ * @return 属性值(如果属性不存在或格式错误,则返回默认值)
|
|
|
+ */
|
|
|
+ private int getIntProperty(PropertiesUtil properties, String key, int defaultValue) {
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(properties.getProperty(key, String.valueOf(defaultValue)));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ logger.warn("属性 {} 格式错误,使用默认值 {}", key, defaultValue);
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* 3.初始化游戏数据
|
|
|
*/
|
|
@@ -209,75 +263,206 @@ public class GGame extends AbstractService {
|
|
|
// }
|
|
|
|
|
|
/**
|
|
|
- * 4.todo 初始化定时器任务
|
|
|
- **/
|
|
|
+ * 4. 初始化定时器任务
|
|
|
+ */
|
|
|
private void initQuartzTask() {
|
|
|
- logger.info("初始化定时任务...");
|
|
|
+ logger.info("开始初始化定时任务...");
|
|
|
+ try {
|
|
|
+ QuartzServer quartzServer = new QuartzServer();
|
|
|
+
|
|
|
+ // 定期刷新数据库任务
|
|
|
+ addScheduledTask(quartzServer, new FlushDB(), "刷新数据库任务");
|
|
|
+
|
|
|
+ // 每日刷新任务
|
|
|
+ addScheduledTask(quartzServer, new RefreshNewDay(), "每日刷新任务");
|
|
|
+
|
|
|
+ // 如果需要添加其他任务,可以在此处扩展
|
|
|
+ // addScheduledTask(quartzServer, new OtherTask(), "其他任务");
|
|
|
+
|
|
|
+ logger.info("定时任务初始化完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("初始化定时任务时发生错误: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加单个定时任务
|
|
|
+ * @param quartzServer Quartz 任务管理器
|
|
|
+ * @param job 任务对象
|
|
|
+ * @param taskDescription 任务描述(用于日志输出)
|
|
|
+ */
|
|
|
+ private void addScheduledTask(QuartzServer quartzServer, QuartzTask job, String taskDescription) {
|
|
|
try {
|
|
|
- QuartzServer task = new QuartzServer();
|
|
|
- task.addJob(new FlushDB());
|
|
|
- task.addJob(new RefreshNewDay());
|
|
|
+ quartzServer.addJob(job);
|
|
|
+ logger.info("{} 已成功注册", taskDescription);
|
|
|
} catch (Exception e) {
|
|
|
- logger.error("初始化定时任务出错...{}", e.getMessage());
|
|
|
+ logger.error("{} 注册失败: {}", taskDescription, e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * 5.初始化消息事件
|
|
|
+ * 5. 初始化消息事件
|
|
|
*/
|
|
|
private void initHandler() {
|
|
|
logger.info("初始化消息事件...");
|
|
|
- File f = new File(env.getConfDir() + "/" + EVENT_FILE);
|
|
|
- if (f.exists() && f.isFile()) {
|
|
|
- try {
|
|
|
- FileInputStream inputStream = new FileInputStream(f);
|
|
|
- SAXReader saxReader = new SAXReader();
|
|
|
- Document document = saxReader.read(inputStream);
|
|
|
- Element root = document.getRootElement();
|
|
|
- List<?> elements = root.elements("onDate");
|
|
|
- String _key = null;
|
|
|
- for (Object element : elements) {
|
|
|
- Element e = (Element) element;
|
|
|
- String clazz = e.attributeValue("handleClass");
|
|
|
-
|
|
|
- _key = e.attributeValue("id");
|
|
|
- if (StringUtils.isNotEmpty(_key)) {
|
|
|
- int id = Integer.parseInt(_key);
|
|
|
- handlers.put(id, (NetHandler) Class.forName(clazz).newInstance());
|
|
|
+
|
|
|
+ // 获取事件配置文件路径
|
|
|
+ File eventFile = new File(env.getConfDir() + "/" + EVENT_FILE);
|
|
|
+ if (!eventFile.exists() || !eventFile.isFile()) {
|
|
|
+ logger.warn("事件配置文件未找到,跳过消息事件初始化: {}", EVENT_FILE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try (FileInputStream inputStream = new FileInputStream(eventFile)) {
|
|
|
+ // 使用 SAXReader 解析 XML 配置
|
|
|
+ SAXReader saxReader = new SAXReader();
|
|
|
+ Document document = saxReader.read(inputStream);
|
|
|
+ Element root = document.getRootElement();
|
|
|
+ List<?> elements = root.elements("onDate");
|
|
|
+
|
|
|
+ for (Object elementObj : elements) {
|
|
|
+ Element element = (Element) elementObj;
|
|
|
+
|
|
|
+ // 获取消息事件的处理类名
|
|
|
+ String handlerClass = element.attributeValue("handleClass");
|
|
|
+ if (StringUtils.isEmpty(handlerClass)) {
|
|
|
+ logger.warn("配置中缺少 handleClass 属性,跳过此消息事件配置: {}", element.asXML());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化 WebSocket 消息事件
|
|
|
+ String idAttr = element.attributeValue("id");
|
|
|
+ if (StringUtils.isNotEmpty(idAttr)) {
|
|
|
+ try {
|
|
|
+ int id = Integer.parseInt(idAttr);
|
|
|
+ NetHandler handlerInstance = (NetHandler) Class.forName(handlerClass).getDeclaredConstructor().newInstance();
|
|
|
+ handlers.put(id, handlerInstance);
|
|
|
+ logger.info("已注册 WebSocket 消息事件: id={}, handlerClass={}", id, handlerClass);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ logger.error("注册 WebSocket 消息事件失败: id={}, handlerClass={}, 错误: {}", idAttr, handlerClass, ex.getMessage(), ex);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- _key = e.attributeValue("http");
|
|
|
- if (StringUtils.isNotEmpty(_key)) {
|
|
|
- httpHandlers.put(_key, (HttpRequestHandler) Class.forName(clazz).newInstance());
|
|
|
+ // 初始化 HTTP 消息事件
|
|
|
+ String httpAttr = element.attributeValue("http");
|
|
|
+ if (StringUtils.isNotEmpty(httpAttr)) {
|
|
|
+ try {
|
|
|
+ HttpRequestHandler httpHandlerInstance = (HttpRequestHandler) Class.forName(handlerClass).getDeclaredConstructor().newInstance();
|
|
|
+ httpHandlers.put(httpAttr, httpHandlerInstance);
|
|
|
+ logger.info("已注册 HTTP 消息事件: http={}, handlerClass={}", httpAttr, handlerClass);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ logger.error("注册 HTTP 消息事件失败: http={}, handlerClass={}, 错误: {}", httpAttr, handlerClass, ex.getMessage(), ex);
|
|
|
}
|
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
- logger.error("初始化消息事件出错 : {}", e.getMessage());
|
|
|
}
|
|
|
+ logger.info("消息事件初始化完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("初始化消息事件时发生异常: {}", e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* 6.初始化网络服务
|
|
|
**/
|
|
|
+// private void initNetService() {
|
|
|
+// logger.info("初始化网络服务...");
|
|
|
+// // websocket端口
|
|
|
+// NetServer publicServer = new NettyServer(GGame.BIND_HOST, GGame.BIND_PORT,
|
|
|
+// new WebSocketServerBinaryAdapterHandler("/ws",
|
|
|
+// new InitalizerProtocolHandler(new PublicListener())));
|
|
|
+// publicServer.start();
|
|
|
+//
|
|
|
+// // http端口
|
|
|
+// NetServer innerHttpServer = new NettyServer(GGame.BIND_HTTP_HOST, GGame.BIND_HTTP_PORT,
|
|
|
+// new InitalizerHttpServerHandler(new HttpInnerListener()));
|
|
|
+// innerHttpServer.start();
|
|
|
+//
|
|
|
+// // 开启连接中控服务端
|
|
|
+//// NetClient centerClient = new NettyClient(GGame.CENTER_HOST, GGame.CENTER_PORT,
|
|
|
+//// new WebSocketServerBinaryAdapterHandler("/ws", new InitalizerProtocolHandler(new CenterClientListener())));
|
|
|
+//// centerClient.enableReconnect(scheduleExec, TimeUnit.SECONDS.toMillis(5));
|
|
|
+//// centerClient.setName("centerClient");
|
|
|
+//// centerClient.start();
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 6. 初始化网络服务
|
|
|
+ */
|
|
|
private void initNetService() {
|
|
|
- logger.info("初始化网络服务...");
|
|
|
- // websocket端口
|
|
|
- NetServer publicServer = new NettyServer(GGame.BIND_HOST, GGame.BIND_PORT,
|
|
|
- new WebSocketServerBinaryAdapterHandler("/ws",
|
|
|
- new InitalizerProtocolHandler(new PublicListener())));
|
|
|
+ logger.info("开始初始化网络服务...");
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 初始化 WebSocket 服务
|
|
|
+ initializeWebSocketServer();
|
|
|
+ // 初始化 HTTP 服务
|
|
|
+ initializeHttpServer();
|
|
|
+ // 初始化中控连接服务(可选)
|
|
|
+// initializeCenterService();
|
|
|
+ logger.info("网络服务初始化完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("初始化网络服务时发生错误: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化 WebSocket 服务
|
|
|
+ */
|
|
|
+ private void initializeWebSocketServer() throws Exception {
|
|
|
+ logger.info("初始化 WebSocket 服务...");
|
|
|
+ NetServer publicServer = new NettyServer(
|
|
|
+ BIND_HOST,
|
|
|
+ BIND_PORT,
|
|
|
+ new WebSocketServerBinaryAdapterHandler(
|
|
|
+ "/ws",
|
|
|
+ new InitalizerProtocolHandler(new PublicListener())
|
|
|
+ )
|
|
|
+ );
|
|
|
publicServer.start();
|
|
|
+ logger.info("WebSocket 服务启动成功,地址: {}:{}", BIND_HOST, BIND_PORT);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化 HTTP 服务
|
|
|
+ */
|
|
|
+ private void initializeHttpServer() throws Exception {
|
|
|
+ logger.info("初始化 HTTP 服务...");
|
|
|
+ NetServer httpServer = new NettyServer(
|
|
|
+ BIND_HTTP_HOST,
|
|
|
+ BIND_HTTP_PORT,
|
|
|
+ new InitalizerHttpServerHandler(new HttpInnerListener())
|
|
|
+ );
|
|
|
+ httpServer.start();
|
|
|
+ logger.info("HTTP 服务启动成功,地址: {}:{}", BIND_HTTP_HOST, BIND_HTTP_PORT);
|
|
|
+ }
|
|
|
|
|
|
- // http端口
|
|
|
- NetServer innerHttpServer = new NettyServer(GGame.BIND_HTTP_HOST, GGame.BIND_HTTP_PORT,
|
|
|
- new InitalizerHttpServerHandler(new HttpInnerListener()));
|
|
|
- innerHttpServer.start();
|
|
|
-
|
|
|
- // 开启连接中控服务端
|
|
|
-// NetClient centerClient = new NettyClient(GGame.CENTER_HOST, GGame.CENTER_PORT,
|
|
|
-// new WebSocketServerBinaryAdapterHandler("/ws", new InitalizerProtocolHandler(new CenterClientListener())));
|
|
|
-// centerClient.enableReconnect(scheduleExec, TimeUnit.SECONDS.toMillis(5));
|
|
|
-// centerClient.setName("centerClient");
|
|
|
-// centerClient.start();
|
|
|
+ /**
|
|
|
+ * 初始化中控服务(可选功能)
|
|
|
+ */
|
|
|
+ private void initializeCenterService() {
|
|
|
+ if (StringUtils.isEmpty(CENTER_HOST) || CENTER_PORT <= 0) {
|
|
|
+ logger.warn("中控服务地址未配置,跳过初始化...");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info("初始化中控服务...");
|
|
|
+ try {
|
|
|
+ NetClient centerClient = new NettyClient(
|
|
|
+ CENTER_HOST,
|
|
|
+ CENTER_PORT,
|
|
|
+ new WebSocketServerBinaryAdapterHandler(
|
|
|
+ "/ws",
|
|
|
+ new InitalizerProtocolHandler(new CenterClientListener())
|
|
|
+ )
|
|
|
+ );
|
|
|
+ centerClient.enableReconnect(scheduleExec, TimeUnit.SECONDS.toMillis(5));
|
|
|
+ centerClient.setName("CenterClient");
|
|
|
+ centerClient.start();
|
|
|
+ logger.info("中控服务连接成功,地址: {}:{}", CENTER_HOST, CENTER_PORT);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("中控服务连接失败: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
}
|