Organizations

56 results for Java
  • H5游戏服务端(六) 对接完客户端协议之后, 基本上暂时可以没什么需要与客户端对接的; 接下来则是对接策划工具了, 更进一步说是 excel 表导出工具, 用来映射成类表格式, 表格的格式: 第一行: 转化的字段名, 该字段只允许英文字母等特殊符号, 用来给静态类设定名称 第二行: 转化的类型, 用来给强类型数据转化声明, 这里可以采用 JSON 类型风格处理 设定下表格风格如下, 这里以设定场景地图 场景配置#SceneTable.csv 方式: id resource name award 标识 场景 名称 解锁奖励 0 res://Scenes/Login/Main.tscn 登录页面 [] 1 res://Scenes/Home/Main.tscn 玩家首页 [“100_1”,“200_2”] 2 res://Scenes/CityLight/Main.tscn 游戏城镇A [“100_1”,“200_2”] 3 res://Scenes/CityMoon/Main.tscn 游戏城镇B [“100_1”,“200_2”] 这里就是比较简单的配置表工具, 预留前三列作为数据配置转化风格, 注意 id 是 int 类型且唯一存在, 最后转化成 Java 结果类: /** * 场景配置 */ public class SceneTable { /** * 场景配置 - 数据行 */ public static class Row { public int id; public String resource; public String[] award; } /** * 静态数据数据行 */ public static final Map<Integer, Row> Rows = new HashMap<>() {{ put(1, new Row() {{ id = 1; resource = "res://Scenes/Login/Main.
    H5游戏服务端 Java Created Sat, 27 Jan 2024 23:02:57 +0800
  • H5游戏服务端(五) 消息通讯功能已经完成了, 现在需要优化对应常量配置保存, 现在重构下之前所需方法: /** * 访问状态常量表 */ public class LogicStatus { /** * 无状态 */ public static final int None = 0; /** * 已授权状态 */ public static final int Authorized = 1; /** * 程序内部传递, 不对外暴露 */ public static final int Program = 2; /** * 游戏中状态 */ public static final int Gaming = 3; } 之前的玩家信息重新构建, 改为状态常量处理: /** * 玩家信息 Actor */ @EnableActor(owner = PlayerLogic.class) public class PlayerLogic extends ActorConfigurer { /// 其他代码, 略 /** * 玩家追加游戏货币 - 用于测试 * 现在这里 state 该有常量处理, 只有登录和游戏中才能被访问 * Example: { "value":302,"args":{ }} * * @param runtime 运行时 * @param session 会话 * @param args 参数 */ @ActorMapping(value = 302, state = {LogicStatus.
    H5游戏服务端 Java Created Sat, 27 Jan 2024 12:53:47 +0800
  • H5游戏服务端(四) 之前已经演示出账号挂载体系, 但是没有涉及数据库落地情况, 所以这里单独篇章介绍应该怎么处理数据实体落地. 这里采用 Spring 集成的 ORM(Object Relational Mapping) 处理, 方便将定义的实体写入数据库, 比较常用的 ORM 有: MyBatis: 这个相对国内用的比较多, 比较灵活可以手写 SQL, 更加接近于原生底层处理. JPA: 外国相对用的比较多, 映射类对象更加彻底, 性能方便可能有所损耗但学习方便. 这里采用 JPA 方式, 方便引入数据库驱动相关: <!-- 集成库对象 --> <dependencies> <!-- 其他略 --> <!-- JPA ORM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MariaDB 驱动 --> <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>3.1.4</version> </dependency> <!-- Lombok, 节约编写 getter/setter 时间, 但是有性能损耗 --> <!-- 这里实际上来说看你侧重于开发效率还是性能效率, 如果性能要求高不推荐引入 Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> </dependencies> 这里 MariaDB 驱动可以更换成其他比如 mysql|postgresql, Lombok 有性能损耗引入方面需要看自己需求处理
    H5游戏服务端 Java Created Wed, 24 Jan 2024 15:19:34 +0800
  • H5游戏服务端(三) 网络游戏和单机游戏差异很大, 除了游戏逻辑代码之外还需要关注服务器状态, 最明显就是要登录授权在线|维护网络请求心跳等情况. 这里先从登录授权开始, 这里需要第三方SDK的配合, 具体流程: HTTP 请求第三方SDK验证授权: SDK服务端发起 OAuth 授权获取 access_token 验证之类信息 第三方授权后在SDK服务器生成账号: SDK服务端拿到 access_token 在数据库生成账号在 Redis 登记凭证, 最后 UID+Token 返回客户端 客户端接收授权码后连接游戏服务端: 客户端拿到 UID+Token 连接提交给游戏服务端, 游戏服务端验证 Redis 授权是否一致 游戏服务端创建玩家服务器数据实体: 读取策划配置的玩家初始化状态写入到游戏数据库之中, 这里和Web端数据库读写有些差异 游戏服务端装载数据实体检测心跳: 把数据实体挂载服务内存当中, 并且检测网络心跳, 这里心跳也算是思考点确定服务端还是客户端发起心跳 游戏客户端监听登录完成事件等待切换场景: 之前只做过 Web 端可能会被影响到认为消息请求后必定响应, 从而等待 Websocket 响应 这里有些关键点会针对说明下, 因为这里面不同人处理方式都不一样, 比如 Redis 和数据库之类并不是必选而是需要自己考虑. 问题1: 为什么游戏服务端不合并SDK服务端功能? 在现代商业化游戏之中, 应用下载平台 和 游戏AD推广 也是关键组成部分, 比如最明显 bilibili 联运平台登录时候会调度登录进入游戏; 在这过程之中第三方通讯会通知返回告诉你已经授权, 游戏服务端集成SDK功能需要提供HTTP服务, 这时候对端口发起 DDOS 会影响游戏服务端; 同时游戏广告服务需要追踪转化, 也就是需要知道玩家在点击广告到最终自己SDK服务器创建账号整体转化流程, 才能按需给广告商切换玩家流量池付费. 游戏服务端尽可能单一, 集成 Web 功能相当于引入未可知问题, 加大被网络攻击风险并拖慢进程效率, 并且SDK服务端需要频繁重启调试追加功能
    H5游戏服务端 Java Created Mon, 22 Jan 2024 14:10:31 +0800
  • 游戏分工 这个篇章不涉及技术相关内容, 主要说明开发游戏内部分工情况, 约等于开发商业游戏的杂谈: SDK接入: 负责运营后台|第三方接入, 包括后台活动|物品发放|公告发布|授权登录等 游戏服务端: 负责维护游戏网络架构功能, 对接策划|客户端|后台等处理同时, 还有的需要兼任服务器运维部署等相关 服务器运维: 负责管理公司内部云服务器, 有时候需要搭建内网在线版本库和部署测试服|正式服|数据库等 游戏客户端: 负责实现游戏玩法, 有时候需要开发客户端工具给策划验证游戏内部数值等, 同时有时候需要处理安卓/iOS商店上架发包等 产品策划: 负责游戏玩法开发和数值调整防止在线游戏内部投入产出奔溃, 有时候需要和运营协调节日活动促进玩家回流在线等 原画美术: 负责游戏美术和 UI 绘制, 有的公司会本家预留 2|3 个美术人员剩下采用外包美术, 拿到外包美术资源之后由本家美术做资源差分等修改 市场运营: 负责游戏上架之后统计游戏流水和玩家在线分析用户流程, 对接策划分析怎么推出游戏内部活动, 客服收集反馈|BUG移交运营来移交技术解决 法务财务: 目前国内上架游戏需要公司主体用于报税和申请版号, 游戏内购支付SDK主体也只公司不对个人开放, 还有美术版权|和谐|报账等问题 只要做游戏商业化上面都是绕不开的点, 需要清楚知道内部流程和应该负责的要点, 而且游戏公司都是以工作室单位来针对自己产品线独立开发( 也存在互相工作室 ‘外借’ 技术人员帮忙开发 ) 项目管理 如果需要把控项目, 那么需要对整体项目可以没精通所有流程但必须有所涉猎整体, 因为需要把控项目 deadline(最后期限). 这里需要说下之前所在游戏公司项目管理就比较灾难, 那时候公司把控项目由产品经理担任; 不过由于产品经理缺乏经验导致外包美术延误几个星期, 期间产品经理和美术外包扯皮没协调好这个版本服务端/客户端应该做的事, 也由于没穿插时间去申请版号|商户导致整个项目组上线都跌跌撞撞. 项目管理协调是重中之重的事, 而主程要么客户端要么服务端担任要么两者都有各自担任, 只有接触到最前线才能用自身经验解决问题. 项目开发一般分 小版本 和 大版本 发布版本: 小版本: 节日临时活动|限时活动|日常周期赛季奖励发放 大版本: 游戏玩法更新|客户端换皮资源|内核组件更新 小版本更新 常规来说 1-2周(最长3周) 内处理即可, 比如简单临时节日需要让美术更新资源和追加简单可以复用玩法等只需要热更新即可的小补丁.
    H5游戏服务端 Java Created Fri, 19 Jan 2024 16:33:29 +0800
  • 搭建环境 对于 H5 游戏来说没有太多代码业务热更新的情况, 所以 skynet 挂载 lua 实现业务热更新的场景可以删减; Websocket 协议内部数据发包已经确定好, 每条消息都是获取取用就行( 不需要类似 int32[status] + int32[length] + data[bytes] 二进制消息封包 ). 虽然 Websocket 数据相比于 TCP/UDP 层面来说性能不高( 链接时带上了 HTTPS 头的数据包头信息 ), 但是其方便调试特性可以方便做调试从而所见即所得( 包括现在本地建立 html 文件就能编写客户端, 并且 PostMan 之类调试客户端也支持这种方式 ) 所以采用 H5 作为游戏服务端入门来说相对简单, 不用担心过多繁重概念带来的心智负担就可以出成品( 当然后续进阶则需要从底层开始了解 ). 对于服务端入门来说最好采用 WebSocket + JSON 来负载游戏传输, 虽然业界普遍采用 TCP/UDP + GoogleProtoBuf 二进制传输, 但是二进制序列化数据排错和字节位封包/大小端网络序列处理的困难都是直接劝退掉大部分新人开发. 这里采用 Java11+SpringBoot3 开发, 因为 Java 的库比较成熟可以直接引入调用, Spring 内部也集成容器对象方便管理. 这里先引入 Actor 和 Websocket 库处理: <dependencies> <!-- Websocket 库 --> <dependency> <groupId>org.
    H5游戏服务端 Java Created Fri, 19 Jan 2024 13:59:21 +0800
  • Actor消息队列化 这里需要先查看些基础内容: 基础Actor原理 Actor框架配置 Actor集成框架 这里说明下怎么集成 SpringBoot 涉及自己的 Actor 消息传递问题, 这里先集成需要的库: <dependencies> <!-- Websocket --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- Actor --> <dependency> <groupId>com.meteorcat.spring.boot</groupId> <artifactId>actor-spring-boot-starter</artifactId> <version>1.0.15-SNAPSHOT</version> </dependency> <!-- Hotfix --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- Configuration --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- Test Unit --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> 这里设计个纯文本交互游戏服务端, 主要是没有美术素材所以直接设计文本放置游戏, 这样用文本方便描述效果. 加载 WebSocket 配置处理: @Configuration @EnableWebSocket public class WebsocketConfig implements WebSocketConfigurer { /** * 访问路径 */ @Value("${websocket.
    Java Created Thu, 18 Jan 2024 14:48:26 +0800
  • Actor框架配置 这里需要先查看 基础Actor原理 之前编写基础的 Actor 框架, 其中忘了解释 RPC(Remote Procedure Call,远程过程调用) 概念, 它允许计算机程序跨网络使用过程或函数. RPC 使得一个计算机程序能够调用另一个计算机程序的函数, 就像在本地执行一样. 虽然 RPC 常用在分布式计算当中, 但是在游戏服务端当中也是很常见的存在 还有关于 Actor 设计优缺点问题, 先是设计的优点: 可扩展性: 可以利用网关来转发到对应其他计算服务来分布发送给其他服务器处理任务 容错性: 每个 Actor 都是独自声明的模块, 单个 Actor 内部系统奔溃并不会干扰到其他 Actor 对象 并发性: 每个 Actor 都有各自线程池负责调度, 多个 Actor 对象可以被线程同时运行 模块化: 每个 Actor 都可以被视为一个独立的模块, 互相之间可以通过内部推送消息队列转发任务 但是也带来了缺点: 复杂性: 相比其他同步架构, Actor 引入线程池/消息队列/互不干扰/读写锁设计等, 在设计过程当中带来更多心智负担. 性能损耗: Actor 引入了消息队列和读写锁, 相比传统加锁之后执行多出了少许性能占用 测试难度: 实现很多概念带来的就是很难对其进行测试调试, 如果 IDE 不对其支持断点调试等操作会让人抓狂( skynet 的业务调试就是限定Linux/Unix调试, 对 Lua 调试也是只能手动输出分析 ). 不可拒绝: Actor 只负责接收消息且不会去管什么数据是否正确, 对于 Actor 来说只管取出数据转发而不管数据对不对.
    Java Created Thu, 11 Jan 2024 14:24:19 +0800
  • SpringBoot+WebSocket构建 Actor Actor 是种业务驱动的设计模式, 将业务封装成各自业务代码私有领域封装在内部而不对外暴露执行; 具体就是将业务功能类任务挂载在内存之中, 等待被唤起调用触发通知内部回调触发. skyent 作为游戏服务端内部就是采用 actor 模式处理功能业务. 这里基于 Java 的 SpringBoot 内部工具, 可以实现出简单的 Actor 模式, 但是首先必须要对以下内容有所了解: 泛型与反射 自定义注解 注意虽然这里是 WebSocket+Actor, 但是这两种是相互独立出来不会耦合在一起, 也就是 WebSocket 仅仅作为组件, 后续可以集成 netty 来用 tcp/udp 替换传输层. 这里参考下 skynet 挂载服务流程, 查看 actor 是怎么挂载上去的: local skynet = require("skynet") --- 声明出 Actor 内部指令 local CMD = {} --- 封装 Actor.init() 方法 function CMD.init() skynet.error("initialization") end --- 启用挂载出初始化服务 skynet.start(function() -- 注册 Actor 内部指令 skynet.dispatch("lua", function(session, address, cmd, .
    Java Created Fri, 05 Jan 2024 20:40:38 +0800
  • Java泛型反射 基本上所有现代化语言都有泛型实现, 最大的实现就是容器对象: Set<T> List<T> Map<KEY,VALUE> 注入此类容器对象, 这种类型在 Java 当中虽然有 List<Object> 和 List<T> 两种方式, 但是请注意在 Object 是全局对象类型! (Object value = 100) 和 (int value = 100) 两者一个是对象类型, 一个是值类型需要区分出来, 后续编译器则是直接帮助值类型转化为对象类型. 如果没有泛型反射, 那么需要处理不同类型如: List<String> List<Integer> List<Long> …其他相关类型扩展 后续衍生的泛型就是为了这样处理从而生成模板代码: /** * T 就是泛型类模板, 用于替换成自定义泛型, 也就是 MyList<String>/ MyList<Integer> 都能自动生成. */ public class MyList<T> { private T[] array; private int size; } 这样就能直接通过 MyList<String> myList = new MyList<String>() 生成模板代码, 编写一次万能匹配, 可以通过编译器保证了类型安全: 这就是 泛型. 这种泛型推断可以方便快捷衍生出集成接口: /** * 比较接口, 要求对数组实现 * @param <T> */ public interface Comparable<T> { /** * 返回负数: 当前实例比参数o小 * 返回0: 当前实例与参数o相等 * 返回正数: 当前实例比参数o大 */ int compareTo(T o); } // 这样就能对自己的自定义类对象处理比较大小操作 public class SelfClass implements Comparable<SelfClass> { private int value; /** * 让其去比较两者 * @param other 其他实例 * @return int */ public int compareTo(SelfClass other) { return this.
    Java Created Thu, 04 Jan 2024 16:22:14 +0800