[真机Bug]解决服务器强制定位玩家位置后NPC加载超时

2024-06-15 04:52

本文主要是介绍[真机Bug]解决服务器强制定位玩家位置后NPC加载超时,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题复现

image.png
图1 玩家在指定任务交付地点发现NPC未出现
image.png
这是一个剧情演出的任务,在播放TV结束后,角色会被强制位置到一个指定地点。而NPC的加载来源于 【场景分块加载】和【玩家的视野区(本质玩家位置)】.

  • 场景分块加载是资源优化的一种手段。对于大型地图(类似河阳城主城),由于玩家途经的位置有限。没有必要把所有GameObject放在一个scene当中。而是将一个scene按绝对位置切分为8块、16块甚至更多。保证渲染质量。
  • 视野区是一种加载物体优化的一种手段。可以对照视锥体剔除的概念理解,对于系统判断在离玩家坐标比较远的位置的物体可以不加载,如果已加载。可以让其失活进入对象池。最大程度减少hierarchy列表中可见物体的数量,从而保证渲染质量。

问题排查

首先对于这个问题,我优先想到的是检查场景分块加载的逻辑。因为最终定的位置离初始任务位置比较远,这部分的场景是后续分块加载的。那么有一种可能性是场景在TV快要结束的时候才被加载,人物加载是后于场景加载的。那么人物加载可能会延期。
于是我在场景分块加载的管理器中打了日志,标识场景id 和时间。发现,其实在播TV的前3s场景已经完成加载了,而TV总共有10s,在剩余7s的时间之内应该正常加载完成npc吧。让我们来看看加载NPC的细节。

using ViewObjIdMap = std::map<int32,bool> // obj id - 是否可见

bool Obj_Player::Tick_ViewNpc()
{Packet::GC_CREATE_NPC_PAK pak;for(auto it = m_viewNPCIdMap.begin() ; it !=m_viewNPCIdMap.end(); it++){if(IsInSight(it->first)){//如果在视野内,插入到创建map里m_viewCurNpcIdMap.insert(std::make_pair(it->first,true));//消息包插入待创建npc数据pak.m_PacketData.add_npcdata();curCount++;//一批最大创建数量(10)if(curCount >= VIEW_NPC_MAX_COUNT){braek;} } }if(curCount > 10){sendPacket(pak);//发GC_CREATE_NPC_PAK创建的包for(auto it = m_viewCurNPCIdMap.begin() ; it !=m_viewCurNPCIdMap.end(); it++){//设置每个NPC位置,发GC_MOVE的包,状态同步}}}

上面是服务器Tick里的部分逻辑,可以看出npc的创建依赖于

  1. m_viewCurNpcIdMap 是否插入了有效id
  2. m_viewCurNpcIdMap的位置,是在第几批创建,我们可以推算,一次创建10,一次tick是1000ms,那么7s正常是可以创建70 个npc实例,那么对于需求来说是完全足够的。这还是挤在单一场景中。
  3. 创建了,但是同步位置出错,导致不可见(已在客户端排除)

所以问题范围缩小到判断m_viewCurNpcIdMap的内容。

于是我在所以insert m_viewCurNpcIdMap的位置断了点。逐帧调试,在字典添加的时候打印一下日志
image.png
发现在14:25:22 ~14:25:29 这里有点奇怪,首先是没有插入别的有效id,然后耽搁了非常多时
发现扫描的id是不变的。
这说明什么呢。说明玩家的位置要么是没有变化,要么是以前已经到达的位置( ps:已经达到过的位置npc已经被标记,不会再次进入map.由于篇幅限制,这里不再展示扫描部分的代码。重点在于理解)

于是我又打印了玩家的位置,发现其在这个时间段,玩家在朝着起点位置移动,移动了一段时间后,才被强制定位到目标位置。
那么就可以解释的通了,正是因为玩家没有第一时间定位,导致玩家的服务器位置没有及时更新,那么依赖于玩家服务器位置的视野扫描在这一时间段扫描的还是旧位置,那么目标NPC便不会在这段时间被纳入字典,也不会创建了。

问题分析

那么为什么会在执行强制位置的时候往回走呢?初步推测这多半跟自动寻路有关系。
先看看强制位置部分的逻辑是怎么做的

void Obj_Char::ForceSetScene(ScenePos val,bool bMoveToPos ,int32 type)
{SetScenePos(val);if(IsSceneValid()){//设置新位置,准备发包给客户端Packet::GC_FORCE_STEPOS_PAK pak;pak.m_packetData.set_serverid(GetId());pak.m_packetData.set_posX(m_ScenePos.m_fX);pak.m_packetData.set_posY(m_ScenePos.m_fY);pak.m_packetData.set_posZ(m_ScenePos.m_fZ);//状态同步GetrScene().BroadCast_InSight_Inclue(pak,GetId());}if(IsPlayer()){Obj_Player& rPlayer = dynamic_cast<Obj_Player&>(*this);//玩家强制设置位置后,手动改变消息包的版本号,//防止接受到的位置之前的CG_MOVE消息包,导致位置异常。rPlayer.IncMovePakVersion();}}

然鹅好像没有发现什么跟寻路有关的东西,于是我又换了一种思路,从获取玩家位置的引用地方查,终于。。
找到了这么一个地方。

if(rRealEndPos!=GetScenePos())
{bool bMove1 = IsMoveing();StopMove(true,false);m_TargetPos = rRealEndPosl;m_fStopRange = 0.01f;m_PathCont.CleanUp();m_PahtCont.PushBack(PathNode(GetScenePos(),rRealEndPos))//---
}

发现如果m_PathCont缓存不为空,并且当前位置没有校验成功,会朝目标位置移动。所以如果在ForceSetScene的时候m_PathCont 不为空,而这一帧的时候客户端的实际位置又和服务器位置不一样(正常,因为服务器这边强改了位置,要通知客户端改本地的locationPos嘛,符合位置校验没有成功的情况,而m_PathCont 数据又没有清空,此时玩家的【服务器位置】会朝原始位置修正。而为什么修正一段时间后,又成功的定位到了目标位置,可以推测这时刻客户端正确收到了GC_FORCE_STEPOS_PAK的消息,修改了自身的位置,此时服务器校验通过,【服务器位置】变化中止]),这也就解释了为什么实际NPC是延迟加载出来 而不是完全加载不出。
image.png
这里方便阅读做一个补充。
(【客户端位置】就是unity工程中玩家的自身坐标它既依赖于服务器位置消息包的数据而变化(寻路、状态同步),又可以通过自身改变从而影响【服务器位置】,比如客户端主动的行为(按键等等))上文说的位置全是【服务器位置】

问题解决

在ForceSetScene 类似的服务器主动大范围修改玩家位置的地方之前,将m_PathCont 位置缓存清空即可。这样保证了下一帧服务器不会触发位置修正。而在客户端正确收到位置消息包从而改变【客户端位置】后,正常向服务器发送CG_MOVE消息的时候再校验。

这篇关于[真机Bug]解决服务器强制定位玩家位置后NPC加载超时的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062479

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

速盾高防cdn是怎么解决网站攻击的?

速盾高防CDN是一种基于云计算技术的网络安全解决方案,可以有效地保护网站免受各种网络攻击的威胁。它通过在全球多个节点部署服务器,将网站内容缓存到这些服务器上,并通过智能路由技术将用户的请求引导到最近的服务器上,以提供更快的访问速度和更好的网络性能。 速盾高防CDN主要采用以下几种方式来解决网站攻击: 分布式拒绝服务攻击(DDoS)防护:DDoS攻击是一种常见的网络攻击手段,攻击者通过向目标网

速盾:直播 cdn 服务器带宽?

在当今数字化时代,直播已经成为了一种非常流行的娱乐和商业活动形式。为了确保直播的流畅性和高质量,直播平台通常会使用 CDN(Content Delivery Network,内容分发网络)服务器来分发直播流。而 CDN 服务器的带宽则是影响直播质量的一个重要因素。下面我们就来探讨一下速盾视角下的直播 CDN 服务器带宽问题。 一、直播对带宽的需求 高清视频流 直播通常需要传输高清视频