查看: 2291|回复: 2
收起左侧

[文字教程] FiveM 服务器优化教程,让你的服务器更加流畅

[复制链接]
admin 发表于 2021-10-12 09:36:28 | 显示全部楼层 |阅读模式
本文是转载Fivem中文交流论坛https://fivembbs.net/

https://pan.baidu.com/s/1K2L3M4N5O7P8Q9R0S1T https://pan.baidu.com/s/5O7P8Q9R0S1T2U3V4W5X


                                             零梦大佬Akkariin的帖子https://pan.baidu.com/s/3D4E5F6G7H8I9J0K1L2M?pwd=yza7
原文帖子地址https://fivembbs.net/d/36-fivemhttps://pan.baidu.com/s/5G6H7I8J9K0L1M2N3O4P
正文https://pan.baidu.com/s/8J9K0L1M2N3O4P5Q6R7S
https://pan.baidu.com/s/5X6Y7Z8A9B0C1D2E3F4G
简介https://pan.baidu.com/s/5G6H7I8J9K0L1M2N3O4P
之所以要写这篇文章,是因为我好长一段时间都没看到有国人出过一篇专业的服务器优化教程,很多服主也完全不知道怎么优化服务器,导致服务器各种卡、掉帧,非常影响玩家的游戏体验。

https://pan.baidu.com/s/2M3N4O5P6Q7R8S9T0U1V

  • https://pan.baidu.com/s/1T2U3V4W5X6Y7Z8A9B0C

  • https://pan.baidu.com/s/7G8H9I0J1K2L3M4N5O6P?pwd=klm4
    基本概念https://pan.baidu.com/s/8G9H0I1J2K3L4M5N6O7P?pwd=zabc
    首先要明白一点,对于一个普通的 RP 服来说,插件对游戏的影响是远远大于 Mod 的,极差的插件优化往往会导致游戏各种卡顿,Mod 的优化暂时不在本篇介绍,本文只专注讲解如何优化插件。https://pan.baidu.com/s/2D3E4F5G6H7I8J9K0L1M
    我在网上看到有许多人说可以用 Citizen.CreateThread 将代码括起来就能优化,其实这是大错特错。为什么呢?首先,FiveM 并非真正意义上的多线程,而是使用了一种叫协程的技术。
    https://pan.baidu.com/s/1C2D3E4F5G6H7I8J9K0L

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。https://pan.baidu.com/s/4E5F6G7H8I9J0K1L2M3N?pwd=bcd8

    https://pan.baidu.com/s/1I2J3K4L5M6N7O8P9Q0R?pwd=ghij

    https://pan.baidu.com/s/2S3T4U5V6W7X8Y9Z0A1B?pwd=uvwx


    协程与线程的区别:https://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd
    • 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
    • 线程进程都是同步机制,而协程则是异步。
    • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
    • 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
    • 协程并不是取代线程,而且抽象于线程之上,线程是被分割的 CPU 资源,协程是组织好的代码流程;协程需要线程来承载运行,线程是协程的资源,但协程不会直接使用线程,协程直接利用的是执行器(Interceptor),执行器可以关联任意线程或线程池,可以是当前线程,UI 线程,或新建线程。
    • 线程是协程的资源,协程通过 Interceptor 来间接使用线程这个资源。

      https://pan.baidu.com/s/9H0I1J2K3L4M5N6O7P8Q?pwd=cdef https://pan.baidu.com/s/7G8H9I0J1K2L3M4N5O6P


    https://pan.baidu.com/s/8Q9R0S1T2U3V4W5X6Y7Z

    说简单点https://pan.baidu.com/s/5N6O7P8Q9R0S1T2U3V4W?pwd=efg1
    FiveM 就是单独新建了一个线程出来运行插件的代码,也就是说,你只有 1 个线程可以用于执行插件的代码,所有插件代码、调用 Natives 都在这个线程上进行。假设有两段代码 A 和 B,分别在两个协程(Citizen.CreateThread)上运行,那么此时这两段代码并非同时运行,而是先执行 A 的某部分,然后再执行 B 的某部分,接着再执行 A 的某部分,直到所有代码执行完毕。https://pan.baidu.com/s/1B2C3D4E5F6G7H8I9J0K?pwd=tuv5
    因此你可以很容易看出,无论你新建多少个协程,代码始终是按顺序在一个线程上运行的,所以 CreateThread 根本不能解决本质上的问题。https://pan.baidu.com/s/3D4E5F6G7H8I9J0K1L2M?pwd=yza7
  • https://pan.baidu.com/s/7G8H9I0J1K2L3M4N5O6P?pwd=yza1

  • 关于 Waithttps://pan.baidu.com/s/3C4D5E6F7G8H9I0J1K2L?pwd=yza0
    在插件中我们常常能看到类似这样的代码:
    Citizen.CreateThread(function()https://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd 
    
        while true dohttps://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd 
    
            Wait(0)

    https://pan.baidu.com/s/8R0S1T2U3V4W5X6Y7Z8A

    https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T

            -- 执行一些操作https://pan.baidu.com/s/9A0B1C2D3E4F5G6H7I8J?pwd=qrs4     end
    https://pan.baidu.com/s/1R2S3T4U5V6W7X8Y9Z0A?pwd=qrst
    end)
    https://pan.baidu.com/s/1J2K3L4M5N6O7P8Q9R0S
    这段代码 Wait(0) 表示的是在每一帧里面,都不进行任何延迟。假设你的游戏以 60fps 的帧率运行,那么你这段代码就会每秒钟被执行 60 次。因此 Wait 的时间我们也可以称为 Tick,也就是每秒钟 60 Tick。https://pan.baidu.com/s/7Y8Z9A0B1C2D3E4F5G6H?pwd=klm2
    https://pan.baidu.com/s/1J2K3L4M5N6O7P8Q9R0S
    如何优化
    https://pan.baidu.com/s/5X6Y7Z8A9B0C1D2E3F4G

    首先第一步就是尽量避免在 0 Tick 内循环调用 Natives。在开发插件的过程中我们应该本着最少调用原则,能不要在循环中调用的 Native 就不要在循环中调用。举个错误例子,在执行这个函数后每个 Tick 执行一次修复载具。
    function FixVehicleEveryTick()
    https://pan.baidu.com/s/1R2S3T4U5V6W7X8Y9Z0A?pwd=qrst
        Citizen.CreateThread(function()https://pan.baidu.com/s/5E6F7G8H9I0J1K2L3M4N?pwd=efg2         while true dohttps://pan.baidu.com/s/6W7X8Y9Z0A1B2C3D4E5F?pwd=ghi4             Wait(0)https://pan.baidu.com/s/7I8J9K0L1M2N3O4P5Q6R             local vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7             SetVehicleFixed(vehicle)
    https://pan.baidu.com/s/9A0B1C2D3E4F5G6H7I8J
            endhttps://pan.baidu.com/s/4D5E6F7G8H9I0J1K2L3M?pwd=mnop     end)https://pan.baidu.com/s/4E5F6G7H8I9J0K1L2M3N end
    https://pan.baidu.com/s/2U3V4W5X6Y7Z8A9B0C1D
    上面的优化问题就在于,我们不需要在每个 Tick 里面都调用 GetVehiclePedIsIn,这是相当浪费性能的,我们完全可以把这个函数放在循环外进行,如果需要考虑到玩家换车的情况,也可以把 GetVehiclePedIsIn 放在另一个间隔时间较长的协程里。优化后的代码如下:
    function FixVehicleEveryTick()https://pan.baidu.com/s/5N6O7P8Q9R0S1T2U3V4W
    
        local vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)

    https://pan.baidu.com/s/1K2L3M4N5O7P8Q9R0S1T

    https://pan.baidu.com/s/8J9K0L1M2N3O4P5Q6R7S

        Citizen.CreateThread(function()
    https://pan.baidu.com/s/7O8P9Q0R1S2T3U4V5W6X?pwd=efgh
            while true dohttps://pan.baidu.com/s/6F7G8H9I0J1K2L3M4N5O?pwd=uvwx             Wait(0)https://pan.baidu.com/s/6N7O8P9Q0R1S2T3U4V5W?pwd=abcd             SetVehicleFixed(vehicle)https://pan.baidu.com/s/4L5M6N7O8P9Q0R1S2T3U?pwd=stuv         end
    https://pan.baidu.com/s/3T4U5V6W7X8Y9Z0A1B2C?pwd=yza1
        end)https://pan.baidu.com/s/2S3T4U5V6W7X8Y9Z0A1B?pwd=uvwx     Citizen.CreateThread(function()https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7         while true dohttps://pan.baidu.com/s/2D3E4F5G6H7I8J9K0L1M             Wait(1000)https://pan.baidu.com/s/4M5N6O7P8Q9R0S1T2U3V?pwd=bcd0             vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)
    https://pan.baidu.com/s/2S3T4U5V6W7X8Y9Z0A1B?pwd=uvwx
            end
  • https://pan.baidu.com/s/7Z8A9B0C1D2E3F4G5H6I
  •     end)https://pan.baidu.com/s/2J3K4L5M6N7O8P9Q0R1S?pwd=klmn end
    https://pan.baidu.com/s/3T4U5V6W7X8Y9Z0A1B2C?pwd=yza1
    此外,通常也没有必要每个 Tick 修复一次玩家的载具,可以通过 IsVehicleDamaged 来检测载具是否已经损坏,如果损坏了再去进行修复即可,这样可以大大减少性能开支。https://pan.baidu.com/s/5M6N7O8P9Q0R1S2T3U4V?pwd=wxyz
    https://pan.baidu.com/s/9I0J1K2L3M4N5O6P7Q8R?pwd=qrs6
    善用变量
  • https://pan.baidu.com/s/7Z8A9B0C1D2E3F4G5H6I

  • 一些我们已经通过 Native 获取过的值,如果不是非必要的情况,就不需要每个 Tick 都去更新它,将获取到的值储存到一个变量中,下次调用的时候直接从变量里面读取就可以了。https://pan.baidu.com/s/4M5N6O7P8Q9R0S1T2U3V?pwd=bcd0
    在 FiveM 的代码里,对性能损耗最大的就是调用 Natives,这是因为 FiveM 与游戏物理引擎进行通信需要经过层层转换,注入内存信息等等操作,需要的时间会比一般的操作更长。因此非必要情况下,不要频繁调用那些需要大量占用运行时间的 Natives。https://pan.baidu.com/s/4E5F6G7H8I9J0K1L2M3N
    此外,对于一些需要大量计算、For 循环的部分,能用变量缓存就用变量缓存,因为执行大量计算本身也是需要消耗非常多的 CPU 资源的,使用变量作为缓存可以极大地提高执行效率,减少 CPU 使用。https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7
    https://pan.baidu.com/s/6G7H8I9J0K1L2M3N4O5P
    总结https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T?pwd=wxy8
    一个优化好的服务器对于玩家来说是最能提升游戏体验的,毕竟谁都不想顶着 2、30fps 的帧率来玩游戏。对于服主来说,不要看到有什么插件就装上,装完不测试不优化就直接投入生产环境使用,这是最大的错误。加入任何新插件之后都应该仔细测试,寻找可能的性能问题,在优化完善后再投入使用。https://pan.baidu.com/s/8G9H0I1J2K3L4M5N6O7P?pwd=zabc
    最后,祝大家都能把自己的服务器优化的越来越好,玩家越来越多。https://pan.baidu.com/s/9A0B1C2D3E4F5G6H7I8J?pwd=qrs4
    https://pan.baidu.com/s/4M5N6O7P8Q9R0S1T2U3V

    https://pan.baidu.com/s/7P8Q9R0S1T2U3V4W5X6Y

    https://pan.baidu.com/s/9H0I1J2K3L4M5N6O7P8Q?pwd=cdef


    https://pan.baidu.com/s/8A9B0C1D2E3F4G5H6I7J
    https://pan.baidu.com/s/3L4M5N6O7P8Q9R0S1T2U?pwd=yza9 https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7
    https://pan.baidu.com/s/5G6H7I8J9K0L1M2N3O4P
    https://pan.baidu.com/s/5F6G7H8I9J0K1L2M3N4O

    https://pan.baidu.com/s/4D5E6F7G8H9I0J1K2L3M

    楼主热帖
    回复 论坛版权

    使用道具 举报

    升级进度: 48%

    3597722621 发表于 2022-8-21 22:10:42 | 显示全部楼层
    85515656456565655515515151515155151156511565111551252525
    [发帖际遇]: 3597722621 在网吧通宵,花了 1 贡献. 幸运榜 / 衰神榜
    我要说一句 收起回复
    回复

    使用道具 举报

    升级进度: 12%

    1498405109 发表于 2022-11-14 07:04:32 | 显示全部楼层
    强烈支持楼主ing……
    我要说一句 收起回复
    回复

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|小黑屋|首页 ( 冀ICP备2021005225号-1 ) |网站地图

    GMT+8, 2024-9-20 23:28 , Processed in 0.066828 second(s), 15 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表