[业务系统]人物坐骑系统介绍I

image.png

1.问题描述

旧版本的坐骑系统依赖于人物装备了【法宝】(一种装备类型),装备了法宝的人物变拥有了【幻化】坐骑的能力,即在人物装备栏中的【外观】中会有已经幻化和未幻化(解锁)的坐骑。
如果玩家至少幻化一种坐骑(动物外观),那么玩家在使用坐骑按钮后变成【骑乘】形态,如果没有解锁任何一种坐骑。外观默认使用【法宝】骑乘的状态。
后续,玩家可以在坐骑选择界面手动选择使用【法宝】还是已经解锁的动物作为坐骑外观。
image.pngimage.png
两种坐骑外观

【骑乘状态】可以转化为【飞行状态】,处在飞行状态时,向上滑动左侧摇杆会使玩家向上飞行。
【飞行状态】向下滑动转化为【骑乘状态】,【骑乘状态】再次点击按钮为坐骑。

新版本的需求变化为坐骑的【幻化】不依赖于装备【法宝】了,未装备法宝,无法飞行。

2.问题分析

客户端发起

先从上坐骑的事情回调部分开始调试。行为是通过客户端发起,对于【申请】性质的行为一般是服务器做校验,更新服务器共享内存组,判断是否需要持久化(如果需要,在GameServer进程的DBRoutine线程中在定期心跳包中与DBAgent进程通信,持久化存储主线程接收到的新数据字段。这部分是游戏的数据管理进程做的,不是本文重点)
image.png
现在出现了一个问题:
游戏的自动寻路系统在导航阶段,会根据当前位置与目标点的距离和高度差 ,通过状态机选择是否需要骑乘坐骑再寻路。也就是除了按钮回调事件,在update中可能也会调用到UseSkillMount的逻辑,
而原先在客户端本地UseSkillMount条件筛选中,玩家必须装备法宝才有后面的步骤。现在新需求,上坐骑与法宝取消了绑定关系。那么如果玩家此时没有幻化坐骑,那么一旦开启任务自动寻路,会一直弹“未幻化坐骑,不可骑乘”的提示字。
所以需要设置一个flag做区分,在发包的时候告诉服务器。这一帧是玩家点击按钮使用坐骑,而不是导航系统自动上马使用坐骑,把逻辑分开就不会一直走错误判断了

public string UseSkillMount_WithError(bool isPlayerClick = false)
{//-----错误条件筛选--//code zoneCG_MOUNT_MOUNT_PAK pak = new CG_MOUNT_MOUNT_PAK();pak.data.MountID = isPlayerClick ? -1 : 0; // 传0有特殊含义,意思就是让服务器决定自动坐骑//-1表示由玩家发起(非导航系统)if (GlobeVar._AutoGameConfig.IsOpenGetInfo){pak.data.MountEffect = PlatformHelper.ReqSource();pak.data.MountMCount = PlatformHelper.ReqCount();pak.data.MountHColor = PlatformHelper.ReqOption();pak.data.MountBColor = PlatformHelper.ReqContent();pak.data.MountFColor = PlatformHelper.ReqSubType();int data = 0;
//--机器适配的宏-省略
#if UNITY_IPHONE && !UNITY_EDITORpak.data.MountVersion = data;
#elsepak.data.MountData = data;
#endif}pak.SendPacket();
}

服务器校验和计算

接下来在服务器工程的 HandlePacket重载函数,参数列表是CG_MOUNT_MOUNT 中找到解析包的部分大概是下面这样

int32_t nMountID =  rPacket.mountID();
if(nMountID < -1)
{return PACKET_EXE_CONTINUE;
}
int32_t real_nMountID =  AutoMountID(nMountID);

看看服务器是怎么判断当前选取哪个坐骑的

int32_t Obj_Player::AutoMountID(int32_t nMountID)
{//1.参数有效直接使用这个参数,查表上指定坐骑//2.如果有幻化坐骑,并且在包裹里,那么直接使用幻化的坐骑//差异性判断:/*如果是自动任务:那么先检查当前默认坐骑ID是否为空(保存的是上一次幻化坐骑,或者使用法宝的ID)如果为空,先遍历坐骑缓存池的全部ID,如果有不为空则使用若缓存池为空,那么只剩下一种情况就是购买了法宝但从未使用,即没有幻化。保险起见,直接返回法宝ID如果是-1那么不可上坐骑(实际是不可能的,因为要保证导航系统的稳定可靠)如果是玩家发起的行为那么只需要检测坐骑背包是否有坐骑,没有就返回当前装备栏的法宝ID,如果是-1.那么不可上坐骑*/}

接下来如果没有return,说明服务器拿到了合法的ID。

private bool  Mount_Mount(int mountID)
{//1.判断坐骑是在包里还是当前装备的法宝//2.有效性检测//3.如果是绑定系统主人,则解除所有人的绑定关系//4.重置状态(解除隐身 -- 解除对话状态 -- 打断采集 -- 打断技能行为)//5.判断有无效果追加(如果在空中换坐骑,则附加一次空中加速)SendMountData();BroadCast_MountData();
}

接下来服务器回包给客户端,主要是表明接受到的ID是合法且有效的。回传当前玩家绑定的服务器ID 和合法坐骑ID号

void Obj_Player::SendMountData()
{__SOL_TRACE;if(IsSceneVaild() == false){return;}Packets::GC_MOUNT_DATA_PAK pak;pak.m_PacketData.set_objserverid(GetID());pak.m_PacketData.set_mountid(m_CurMountID());SendPacket(pak);SOL_TRACE__;
}

客户端变更表现

接下来在客户端DataHandler类中找到Receive的方法

public static void ReceivePacket(GC_MOUNT_DATA packet){int nObjServerID = packet.ObjServerID;int nMountID = packet.MountID;int EnterSceneServerID = GameManager.PlayerDataPool.CreateMainPlayerCache.m_ServerID;// 切场景缓存if ( EnterSceneServerID == nObjServerID ){GameManager.PlayerDataPool.CreateMainPlayerCache.m_MountID = nMountID;}else{Obj_Char obj = ObjManager.FindObjCharInScene(nObjServerID);if ( obj ){if ( obj.IsPlayer()){Obj_Player Player = obj as Obj_Player;if (Player != null){if(Player.IsInJump()){Player.ResetJumpState();Player.RideOrUnMount(nMountID,false);}else{Player.RideOrUnMount(nMountID);}}}}}}

我们发现如果接受到的ServerID 绑定了有效的玩家后,就开始判断玩家是否可以上坐骑(跳跃过程中显然是不可以上坐骑的,得等动画播放结束后。但游戏为了玩家体验,直接选择重置状态然后立即上坐骑)
这里还发现,上下马的客户端收包位置是一样的。可以确定服务器只是做了数据方面的校验和计算。那么唯一ID怎么标识,玩家是上马还是下马呢。
合法的mountID一定大于0,等于0是客户端发起计算请求,如果上马合法,服务器一单会回传一个大于0的MountID。
所以,客户端只需要判断如果mountID <0,那么说明是下马的行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/268032.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于R语言的分位数回归技术应用

回归是科研中最常见的统计学研究方法之一&#xff0c;在研究变量间关系方面有着极其广泛的应用。由于其基本假设的限制&#xff0c;包括线性回归及广义线性回归在内的各种常见的回归方法都有三个重大缺陷&#xff1a;(1)对于异常值非常敏感&#xff0c;极少量的异常值可能导致结…

(全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF

研究生英语读写教程基础级教师用书PDF 研究生英语读写教程提高级教师用书PDF pdf下载&#xff08;完整版下载&#xff09; &#xff08;1&#xff09;研究生英语读写教程基础级教师用书PDF &#xff08;2&#xff09;研究生英语读写教程基提高级教师用书PDF

【C++那些事儿】深入理解C++类与对象:从概念到实践(中)| 默认构造函数 | 拷贝构造函数 | 析构函数 | 运算符重载 | const成员函数

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C那些事儿 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 1. 类的6个默认成员函数2. 构造函数2.1 概念2.2 特性 3. 析构函数3.1 概念3.2 特性 4. 拷贝…

GO-接口

1. 接口 在Go语言中接口&#xff08;interface&#xff09;是一种类型&#xff0c;一种抽象的类型。 interface是一组method的集合&#xff0c;接口做的事情就像是定义一个协议&#xff08;规则&#xff09;&#xff0c;只要一台机器有洗衣服和甩干的功能&#xff0c;我就称它…

基于springboot+vue的工厂车间管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

初阶数据结构之---栈和队列(C语言)

引言 在顺序表和链表那篇博客中提到过&#xff0c;栈和队列也属于线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连…

【操作系统(Operator System)】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、概念 二、结构示意图 三、尝试理解操作系统 系统调用和库函数概念 承上启下 总结 前言 世上有两种耀眼的光芒&#xff0c;一种是正在升起的太阳&#xff…

【Go语言】Go语言中的字典

Go语言中的字典 字典就是存储键值对映射关系的集合&#xff0c;在Go语言中&#xff0c;需要在声明时指定键和值的类型&#xff0c;此外Go语言中的字典是个无序集合&#xff0c;底层不会按照元素添加顺序维护元素的存储顺序。 如下所示&#xff0c;Go语言中字典的简单示例&…

FRM模型十三:互换定价(二)

定义一个互换&#xff0c;本金为1e7&#xff0c;7年后到期 固定端&#xff1a;利率2.5%,每年付息一次 浮动端&#xff1a;Libor6M,每半年付息一次 import QuantLib as ql from prettytable import PrettyTable# 定义全局时间&#xff1a;当前日期&#xff0c;下一个结算日&…

【Mybatis】快速入门 基本使用 第一期

文章目录 Mybatis是什么&#xff1f;一、快速入门&#xff08;基于Mybatis3方式&#xff09;二、MyBatis基本使用2.1 向SQL语句传参2.1.1 mybatis日志输出配置2.1.2 #{}形式2.1.3 ${}形式 2.2 数据输入2.2.1 Mybatis总体机制概括2.2.2 概念说明2.2.3 单个简单类型参数2.2.4 实体…

计算机网络|Socket

文章目录 Socket并发socket Socket Socket是一种工作在TCP/IP协议栈上的API。 端口用于区分不同应用&#xff0c;IP地址用于区分不同主机。 以下是某一个服务器的socket代码。 其中with是python中的一个语法糖&#xff0c;代表当代码块离开with时&#xff0c;自动对s进行销毁…

将python程序打包为exe格式

1. 安装pyinstaller winr打开命令窗口 输入&#xff1a; pip install pyinstaller输入命令后会自动安装pyinstaller 2. 打包 进入你的代码所在位置&#xff0c;输入cmd 在弹出的窗口中输入 pyinstaller --onefile your_script.pyyour_script.py修改为你需要打包的程序名字 …

Sqli-labs靶场第19关详解[Sqli-labs-less-19]自动化注入-SQLmap工具注入

Sqli-labs-Less-19 通过测试发现&#xff0c;在登录界面没有注入点&#xff0c;通过已知账号密码admin&#xff0c;admin进行登录发现&#xff1a; 返回了Referer &#xff0c;设想如果在Referer 尝试加上注入语句&#xff08;报错注入&#xff09;&#xff0c;测试是否会执行…

简单网站模板1(HTML)

想要拥有自己的网站&#xff0c;却不知该如何才能简约好看&#xff0c;接下来分享一种自己搭建的网站模板&#xff0c;希望大家喜欢。 展示图&#xff1a; CODE: <!DOCTYPE html> <html> <head><title>我的网站</title><style>body {fo…

【详识JAVA语言】面向对象程序三大特性之二:继承

继承 为什么需要继承 Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物对象&#xff0c;则可以用来表示现实中的实体&#xff0c;但是 现实世界错综复杂&#xff0c;事物之间可能会存在一些关联&#xff0c;那在设计程序是就需要考虑。 比如&…

黑马点评-短信登录业务

原理 模型如下 nginx nginx基于七层模型走的事HTTP协议&#xff0c;可以实现基于Lua直接绕开tomcat访问redis&#xff0c;也可以作为静态资源服务器&#xff0c;轻松扛下上万并发&#xff0c; 负载均衡到下游tomcat服务器&#xff0c;打散流量。 我们都知道一台4核8G的tomca…

微服务API网关---APISIX

最近在做微服务调研&#xff0c;看到了apisix这个网关&#xff0c;于是进行了初步了解一下。 微服务是指&#xff0c;将大型应用分解成多个独立的组件&#xff0c;其中每个组件都各自的负责对应项目。 系统的架构大致经历了&#xff1a;单体应用架构–> SOA架构 -->微服务…

(六)Dropout抑制过拟合与超参数的选择--九五小庞

过拟合 即模型在训练集上表现的很好&#xff0c;但是在测试集上效果却很差。也就是说&#xff0c;在已知的数据集合中非常好&#xff0c;再添加一些新数据进来效果就会差很多 欠拟合 即模型在训练集上表现的效果差&#xff0c;没有充分利用数据&#xff0c;预测准确率很低&a…

SpringCache【缓存接口返回值信息】【前端访问后端,后端访问数据库(可以缓存这个过程,前端访问后端,保存记录,下次访问直接返回之前的数据)】

SpringCache 针对不同的缓存技术需要实现不同的CacheManager&#xff1a;注解入门程序CachePut注解CacheEvict注解Cacheable注解 Spring Cache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能&#xff0c;大大…

Appium手机Android自动化

目录 介绍 什么是APPium&#xff1f; APPium的特点 环境准备 adb(android调试桥)常用命令 appium图形化简单使用 连接手机模拟器 使用appium桌面端应用程序 ​编辑 整合java代码测试 环境准备 引入所需依赖 书写代码简单启动 ​编辑 Appium元素定位 id定位 介…