Organizations

  • 序列化处理 现在已经可以通过配置来生成 ActorSystem, 但是现在需要引入 Protobuf 来做序列化传输. 默认 pekko 传输都是依赖 java-serialization 默认序列化做传输, 如果你成功启动服务传输的时候会出现以下提示: [ERROR] [08/28/2025 11:29:54.811] [fortress-cluster-pekko.remote.default-remote-dispatcher-5] [Encoder(pekko://fortress-cluster)] Failed to serialize message [ActorSelectionMessage(io.fortress.common.event.ConnectedEvent)]. java.io.NotSerializableException: No configured serialization-bindings for class [io.fortress.common.event.ConnectedEvent] 看起来传输的消息结构只需要实现 java.io.Serializable 并且追加以下配置即可: # Actor 序列化允许采用 Java 默认处理 fortress.actor.settings.pekko.actor.allow-java-serialization=on 这里虽然传输成功, 但是默认是会提示警告: [WARN] [SECURITY][08/28/2025 12:01:31.345] [fortress-cluster-pekko.remote.default-remote-dispatcher-14] [org.apache.pekko.serialization.Serialization(pekko://fortress-cluster)] Using the Java serializer for class [io.fortress.common.event.ConnectedEvent] which is not recommended because of performance implications. Use another serializer or disable this warning using the setting 'pekko.
    fortress Java Created Thu, 28 Aug 2025 19:34:47 +0800
  • 功能初始化 这里首先需要配置 common 子项目的功能, 一切基于 protobuf 生成的代码也是由 common 项目构建生成. pom.xml 的配置如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 父依赖 --> <parent> <groupId>io.fortress</groupId> <artifactId>boot</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <!-- 子属性 --> <modelVersion>4.0.0</modelVersion> <artifactId>fortress-common</artifactId> <name>Fortress Common Module</name> <description>Fortress utilities and models</description> <packaging>jar</packaging> <!-- 第三方依赖 --> <dependencies> <!-- 通用字符串、集合等工具类 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <!-- 通用编码哈希工具 --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <!-- Quarkus 核心依赖 --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-core</artifactId> </dependency> <!-- Quarkus 容器依赖 --> <dependency> <groupId>io.
    fortress Java Created Wed, 27 Aug 2025 20:06:01 +0800
  • 项目初始化 这里主要面向的游戏服务端相关业务, 但是本质上也可以看作设计 RPC 系统, 具体的依赖如下: maven-wrapper: 包管理系统, 不要用 gradle 做项目管理, 坑太多了不好填 java21: 采用 21 版本主要是准备承接后续大更新 24 版本 pekko: 需要搭建 actor 节点集群开发, akka 已经转商业授权, 所以采用 pekko 开源版本 protobuf: 客户端交换消息的方式采用 protobufV3, pekko 内部集群序列化传输消息也支持 quarkus: redhat 出的开发框架, 需要用到 容器管理/WebSocket服务/Web服务 功能并且支持打包生成原生可执行文件 mariadb-jpa: mariadb数据库和 ORM 框架, 用于挂载和落地玩家数据实体到数据库之中 这部分相关的官方文档可以先自行前往官网查阅: pekko protobuf quarkus hibernate-orm quarkus-native 之所以采用 quarkus 作为主要开发框架是基于以下几点: 支持原生应用生成 容器和云原生支持 启动快和内存占用小 轻量化依赖扩展 官方提供高并发WebSocket实现 业务开发需要比较轻量化的容器管理 之后就是设计项目目录结构: # io.fortress 是项目包名, 这里采用 quarkus 工具链初始化 --- /.mvn( maven-wrapper 目录 ) --- /wrapper/maven-wrapper.
    fortress Java Created Tue, 26 Aug 2025 20:08:58 +0800
  • “我想做个游戏” 这是我从业这么多年看到最多也是最麻烦的需求, 很多时候老板们头脑一热想入局游戏研发就会提出这样的需求, 但是真正入局之后就会发现问题重重直到后续项目组分崩离析. 首先大部分提出这种需求的语境情况, 就是要做出 能够持续运营的手机游戏; 现在游戏开发已经是高度细分化产业, 抛开 单机游戏 和 独立游戏 , 前者基本上需要有一定大厂背书和稳定投资, 后者只适合小规模个人所以排除在外. 商业化游戏研发立项基本需要做好以下心理准备: 抗风险能力: 需要接受首个游戏并不满足预期, 大部分初创首个游戏成绩不理想才是常态 团队磨合: 很多时候起步的时候肯定是磕磕碰碰, 很多时候创立团队就想一步登天做爆款只能在梦里出现 成本控制: 很多时候就是低估算游戏方面投入, 初创游戏团队需要比成熟团队更加舍得花钱才能获得更好人才和资源 盈利模式: 游戏必须在立项就要考虑到基本付费模式, 必须提前想好怎么才能让研发投入能够快速回收成本 同时我也见过不少这种想法: 买套游戏源代码换皮不就行了? 游戏研发哪有这么复杂, 一定是你水平不行 首先需要说明游戏源代码项目很多 不包括售后, 都是开源代码改改之后上架卖课被大量分发出来的产物, 这种代码基本上和从头开发没什么区别, 运气好的时候编译版本正好在游戏编辑器兼容范围可以打包出来; 运气不好的项目可能是N年前陈年代码, 新版本编辑器根本无法出游戏包, 甚至内部插件已经找不到支持进行正常开发. 更别说有些游戏是游戏公司离职人员自己 夹带 出来的, 根本无法确定美术素材等是否被注册过专利, 直接冒用这方面游戏美术素材到时候著作所有人告又是一堆麻烦事. 有的游戏项目其实立项十分久远(我曾经接触最早是 2017 年的 unity3d 项目, 甚至客户端都没办法正常运行), 那时候的开发语言和环境可能完全没办法跑的(基于 centos6 已经被官方淘汰的系统, 如果升级高版本直接报错无法运行), 这种老代码做兼容和二次开发极其痛苦, 甚至连官方镜像和第三方资源包都不在提供维护了, 说是运行在 bug 之上都不为过. 如果买套源码改改就能顺利跑通商业化游戏所有流程, 那为什么市场上还有这么多失败的游戏项目组 接下来就是相对比较细致的游戏立项问题, 在开始动工的时候尽可能考虑一下: 研发什么类型游戏? - 卡牌|回合制|MMORPG|二次元…., 需要确定类型才能按照这些游戏人群画像去 ‘借鉴学习’ 相关游戏公司竞品 游戏平台是哪些?
    架构 Created Fri, 22 Aug 2025 19:43:52 +0800
  • 在很多第三方支付渠道都是只采用状态码返回响应, 像是比较常见微信和支付宝方面: # https://pay.weixin.qq.com/doc/v3/merchant/4012081709 # 微信响应公共错误码, 以 HTTP 响应码做主题 200 - Success - 请求成功 400 - PARAM_ERROR - 参数错误 400 - INVALID_REQUEST - HTTP 请求不符合微信支付 APIv3 接口规则 400 - APPID_MCHID_NOT_MATCH - AppID和mch_id不匹配 400 - INVALID_REQUEST - 无效请求 400 - MCH_NOT_EXISTS - 商户号不存在 401 - SIGN_ERROR - Sign 验证不通过 403 - NO_AUTH - 商户无权限 403 - OUT_TRADE_NO_USED - 商户订单号重复 403 - RULE_LIMIT - 业务规则限制 429 - FREQUENCY_LIMITED - 频率超限 500 - SYSTEM_ERROR - 系统异常,请稍后重试 # https://opendocs.
    架构 Created Wed, 20 Aug 2025 21:07:30 +0800
  • 记录下海外第三方支付开发的一些关键点, 常见的海外第三方开发推荐按照以下方式处理. 时间戳记录 统一采用 UTC 的时间戳处理, 避免采用服务器地区时间戳导致的跨时区异常, 日常使用的时间戳获取: Java: System.currentTimeMillis() Python: round(time.time() * 1000) .Net: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() PHP: round(microtime(true) * 1000) 并且推荐时间戳记录记录在数据库当中采用毫秒级, 可以精确到具体高精度时间. 唯一订单号 这里推荐数据库的订单号类型为 varchar(32) 或者 varchar(64) 且可以设置为数据库表主键, 具体生成时间相关格式订单如下: /** * PHP生成和时间关联尽可能防止碰撞的订单号 * @return string */ function order(): string { $microtime = microtime(true); $millisecond = round($microtime * 1000); // 获取毫秒 $microseconds = $microtime - intval($microtime); // 获取微秒段 $pos1 = sprintf("%04d", $microseconds * 10000); // 提取4位毫秒 $pos2 = sprintf("%04d", mt_rand(1, 9999)); // 随机提取 0001-9999 $pos3 = sprintf("%04d", mt_rand(1, 9999));// 随机提取 0001-9999 $pos4 = sprintf("%04d", mt_rand(1, 9999));// 随机提取 0001-9999 $pos5 = sprintf("%02d", mt_rand(1, 99));// 随机提取 01-99 return date('YmdHis', intval($microtime)) .
    架构 Created Sun, 10 Aug 2025 15:31:01 +0800
  • 最近需要用到部署 SDK 支付服务网关服务器, 需要对不同第三方支付商的开发包有所支持; 一般第三方的支付商对 Java 方面支持最多, 可以节约时间省下从底层编写发起网络请求的代码. 本来打算直接采用 springboot 直接构建 web 接口即可, 但是现在 springboot 越来越臃肿且庞大, 有时候启动服务的时候也很缓慢, 所以打算采用别的框架处理这方面独立服务. 也就是在这个时间发现 Java 当中轻量级的框架: quarkus 甚至可以依靠 GraalVM | Mandrel 将程序打包成原生可执行文件(依赖Java21+), 方便直接把可执行二进制丢到服务器运行 如果从0开始可以按照官方文档处理: 创建你的第一个应用程序 不过我习惯还是采用 IDEA 初始化构建, 并且因为要和 Android 客户端环境尽可能匹配而采用 gradle 管理( build.gradle.kts ): // 声明插件 plugins { java id("io.quarkus") } // 第三方库 repositories { mavenCentral() mavenLocal() } // 加载全局项目当中配置 val quarkusPlatformGroupId: String by project val quarkusPlatformArtifactId: String by project val quarkusPlatformVersion: String by project // 第三方包 dependencies { implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")) // Web 配置 implementation("io.
    Java Created Sat, 09 Aug 2025 19:30:30 +0800
  • 最近后续项目可能要做 Android 客户端对接, 为了前后端统一后续可能采用 gradle + java 方案, 所以先做好一定知识积累方便后续从 maven 转为 gradle. gradle 主要有两种方式: 全局二进制命令行 : https://gradle.org/releases 下载 GRADLE_HOME 和 GRADLE_HOME/bin 设为全局命令 Gradle Wrapper: 把二进制放置在项目之中, 加入版本库保证所有团队成员使用相同版本构建和启动 建议采用 Gradle Wrapper 方式, 这样可以避免团队成员可能因为不同版本导致构建打包问题, 打包可以用以下配置提高构建性能: 启用构建缓存:org.gradle.caching=true 配置适当的 JVM 内存:org.gradle.jvmargs=-Xmx2g 使用并行构建:org.gradle.parallel=true 目前 gradle 引入两种打包构建脚本: Gradle-Groovy: 更像是传统脚本语言, 采用空格隔开作为每个参数 Gradle-Kotlin: 类型安全并且对于客户端支持更加稳健, 官方比较推荐的打包脚本 Gradle-Kotlin 创建初始化之后会默认带有两个打包文件: build.gradle.kts: 打包构建脚本 settings.gradle.kts: 属性参数清单 之前 gradle 在国内远不如 maven, 我这边采用 IDEA 直接初始化, 主要看下 build.gradle.kts 配置说明: // 声明项目采用的打包语言 plugins { id("java") } // 打包程序包名 group = "com.
    Java Created Sat, 09 Aug 2025 15:51:12 +0800
  • 最近需要填坑处理原来海外的天坑, 基本上处理掉前期的比较基础部分, 还缺少部分估计也是要消耗不少时间处理. 按照目前的节奏针对现有问题做好分类规划: 抽离单独的支付平台(已完成, 待优化) 构建海外游戏发行平台(已完成, 待优化) 游戏业务SDK中心(已完成, 待优化) 整合后台管理中心(未完成, 更新中) 因为引入现代 composer 依赖, 所以避免很多问题只能从头做起, 开发效率上面也比较快; 但是中间很多问题都没有做细致处理优化, 后续对于已完成的项目要调整优化下. 支付平台 支付平台最好是单独抽离出做个中心服务, 除非万不得已不要把服务放置整合在一起; 这部分带来的影响很大, 因为作为发行中心的流量本身很巨大, 有时候简单的 php 任务进程可能没办法即时响应. 并且支付系统是带有定时回调处理( notify ), 如果整合成单机可能后续回调 CPU 抢占影响到服务器执行效率 目前流量较少所以采用单机负载, 后续看情况已经预留好可能会拆分支付订单模块的准备 因为目前支付平台是不对外开放的, 都是内部发行的支付系统传递的唯一订单号( reference_id ), 对订单号没有做唯一判断处理, 只是因为默认内部使用就就没有什么大问题, 后续需要补充更新这方面限制. 海外发行平台 这部分实际上考核很久, 主要就是在于作为 H5 海外的游戏平台 ‘容器’ 页面功能, 让游戏渲染在本身 iframe 之中, 大部分还是前端设计界面的问题. 特别需要注意的是海外支付的 embedded 方式, 这种方式就是引入第三方支付的JS-SDK, 在创建订单之后需要把会话参数传递给 JS-SDK, 后续 JS-SDK 会在 body 内插个节点渲染支付窗口. 这样虽然看起来效果还是挺不错的, 但是内部有很多问题: 第三方 CDN 不稳定, 引入第三方的 JS-SDK 可能连通性有问题, 直接卡死在等待加载的资源之中 插入节点和 css 样式出现冲突, 有的插入之后的样式名和类名在项目有出现冲突的样式 引发事件绑定异常, 有的SDK库带有动态事件绑定, 可能会直接导致游戏事件混乱 但是不可否认直接在页面内部弹窗唤起的交互效果好很多, 不过最后弹出新窗口去第三方页面支付, 支付完成再跳转会发行对外开发的订单完成窗口去执行 window.
    架构 Created Thu, 31 Jul 2025 20:50:52 +0800
  • 对于H5游戏发行来说, 除了服务端接口对接之外, 还需要暴露给游戏客户端JS库来引入, 主要流程如下: H5 游戏客户端拿到 h5.js 引入到游戏项目的页面之中 客户端需要接入对应发行实现接口, 目前没办法直接调用到那些功能 需要要求CP搭建好测试网站, 用来渲染游戏H5游戏页面 需要在发行方把CP搭建好和接入好SDK的H5游戏地址填写到后台配置游戏地址字段里面 发行方会生成游戏容器地址, 内部采用 iframe 渲染CP的游戏界面 对于客户端的调用功能实际上采用 PostMessage 跨页面推送所有事件 这就是 H5 在发行当中的流程, 那么我们首先要准备我们自己的发行游戏容器入口网站, 还有自己编写 JS-SDK 库文件: container.html: 发行的宿主网站, 也就是提供 iframe 功能的页面 game.html: CP游戏研发搭建并且接入我们发行的H5游戏主站 h5-sdk.js: 我们自己发行的JS功能集成库 注意: container 内部涉及到很多 iframe 调用机制和超时监听机制 简单用页面来梳理的话, 大概内部的结构如下: <html> <body> <!-- 授权容器: 作为发行方首先需要渲染的容器, 提供常用的注册授权机制 --> <div id="authority-container"> <!-- 内部不采用 iframe, 直接渲染页面即可 --> </div> <!-- 页面浮动的角标工具栏容器, 登录完成提供负责账号切换和退出的边栏窗口功能 --> <div id="toolbar-container"> <!-- 内部不采用 iframe, 直接渲染页面即可 --> </div> <!
    架构 Created Sat, 19 Jul 2025 01:18:29 +0800