Сүлжээний хоцрогдол нөхөх алгоритм бүхий гар буучдад зориулсан баллистик тооцооны механикийг бид хэрхэн хийсэн бэ

Сүлжээний хоцрогдол нөхөх алгоритм бүхий гар буучдад зориулсан баллистик тооцооны механикийг бид хэрхэн хийсэн бэ

Сайн уу, намайг Никита Брижак гэдэг, Pixonic-ийн сервер хөгжүүлэгч. Өнөөдөр би гар утасны олон тоглогчийн хоцролтыг нөхөх талаар ярихыг хүсч байна.

Серверийн хоцрогдлын нөхөн олговрын талаар олон нийтлэл, түүний дотор орос хэл дээр бичсэн. Энэ технологийг 90-ээд оны сүүлээс хойш олон тоглогчийн FPS бүтээхэд идэвхтэй ашиглаж ирсэн тул энэ нь гайхах зүйл биш юм. Жишээлбэл, та үүнийг хамгийн түрүүнд ашиглаж байсан QuakeWorld горимыг санаж болно.

Бид мөн үүнийг гар утасны олон тоглогчийн мэргэн бууч Dino Squad-д ашигладаг.

Энэ нийтлэлд миний зорилго бол аль хэдийн бичсэн зүйлийг мянга дахин давтах биш, харин технологийн стек болон үндсэн тоглоомын онцлогийг харгалзан тоглоомондоо хоцрогдлын нөхөн төлбөрийг хэрхэн хэрэгжүүлсэн талаар ярих явдал юм.

Манай кортекс, технологийн талаар хэдэн үг хэлье.

Dino Squad бол сүлжээний гар утасны PvP мэргэн бууч юм. Тоглогчид төрөл бүрийн зэвсгээр тоноглогдсон үлэг гүрвэлүүдийг удирдаж, 6v6 багаар хоорондоо тулалддаг.

Үйлчлүүлэгч болон сервер хоёулаа Unity дээр суурилдаг. Архитектур нь мэргэн буучдын хувьд нэлээд сонгодог юм: сервер нь авторитар бөгөөд үйлчлүүлэгчийн таамаглал нь үйлчлүүлэгчид дээр ажилладаг. Тоглоомын симуляцийг дотоод ECS ашиглан бичсэн бөгөөд сервер болон үйлчлүүлэгчийн аль алинд нь ашигладаг.

Хэрэв та хоцрогдлын нөхөн олговрын талаар анх удаа сонсож байгаа бол энэ асуудлын талаар товч танилцуулъя.

Олон тоглогчийн FPS тоглоомуудад тоглолтыг ихэвчлэн алсын сервер дээр дуурайдаг. Тоглогчид өөрсдийн оролтыг (товчлуурын тухай мэдээлэл) сервер рүү илгээдэг бөгөөд хариуд нь сервер хүлээн авсан өгөгдлийг харгалзан шинэчилсэн тоглоомын төлөвийг илгээдэг. Энэхүү харилцан үйлчлэлийн схемийн тусламжтайгаар урагшлах товчлуурыг дарах болон тоглогчийн дүр дэлгэцэн дээр шилжих мөч хүртэлх хугацаа нь пингээс үргэлж их байх болно.

Дотоод сүлжээнд энэ саатал (оролтын хоцрогдол гэж нэрлэдэг) анзаарагдахгүй байж болох ч интернетээр тоглох үед дүрийг удирдах үед "мөсөн дээр гулгах" мэдрэмжийг төрүүлдэг. Энэ асуудал нь гар утасны сүлжээнд хоёр дахин хамааралтай бөгөөд тоглогчийн ping 200 мс байх нь маш сайн холболт гэж тооцогддог. Ихэнхдээ ping нь 350, 500 эсвэл 1000 мс байж болно. Дараа нь оролтын хоцрогдолтой хурдан мэргэн бууч тоглох бараг боломжгүй болно.

Энэ асуудлын шийдэл бол үйлчлүүлэгчийн симуляцийн таамаглал юм. Энд үйлчлүүлэгч өөрөө серверээс хариу хүлээхгүйгээр тоглогчийн дүрд оруулсан оролтыг ашигладаг. Хариултыг хүлээн авах үед энэ нь зүгээр л үр дүнг харьцуулж, өрсөлдөгчдийн байр суурийг шинэчилдэг. Энэ тохиолдолд товчлуурыг дарж үр дүнг дэлгэцэн дээр харуулах хоорондох саатал хамгийн бага байна.

Энд байгаа нарийн ширийн зүйлийг ойлгох нь чухал: үйлчлүүлэгч үргэлж сүүлчийн оролтынхоо дагуу өөрийгөө татдаг бөгөөд дайснууд нь серверээс авсан өгөгдлөөс өмнөх төлөвийн дагуу сүлжээний сааталтай байдаг. Өөрөөр хэлбэл, дайсан руу буудах үед тоглогч түүнийг өөртэйгөө харьцуулахад урьд өмнө нь хардаг. Үйлчлүүлэгчийн таамаглалын талаар илүү ихийг олж мэдэх бид өмнө нь бичсэн.

Тиймээс, үйлчлүүлэгчийн таамаглал нь нэг асуудлыг шийдэж, харин нөгөөг нь бий болгодог: хэрэв тоглогч дайсан өмнө нь байсан цэг дээр буудвал сервер дээр яг ижил цэг дээр буудаж байвал дайсан тэр газарт байхаа больсон байж магадгүй юм. Серверийн хоцрогдлын нөхөн төлбөр нь энэ асуудлыг шийдэх оролдлого юм. Зэвсэг буудах үед сервер нь тухайн тоглогчийн буудах үед орон нутагт харсан тоглоомын төлөвийг сэргээж, тэр үнэхээр дайсныг онож чадах эсэхийг шалгадаг. Хэрэв "тийм" гэж хариулсан бол дайсан тухайн үед сервер дээр байхгүй байсан ч цохилтыг тооцно.

Энэхүү мэдлэгээр зэвсэглэсэн бид Dino Squad-д серверийн хоцрогдлын нөхөн төлбөрийг хэрэгжүүлж эхэлсэн. Юуны өмнө бид үйлчлүүлэгчийн харсан зүйлийг сервер дээр хэрхэн сэргээх талаар ойлгох ёстой байсан уу? Мөн яг юуг сэргээх шаардлагатай вэ? Манай тоглоомонд зэвсэг, ур чадварын цохилтыг туяа цацалт, давхцал, өөрөөр хэлбэл дайсны физик мөргөлдөөнтэй харьцах замаар тооцдог. Үүний дагуу бид тоглогчийн орон нутагт "харсан" эдгээр мөргөлдөөнүүдийн байрлалыг сервер дээр хуулбарлах шаардлагатай болсон. Тэр үед бид Unity 2018.x хувилбарыг ашиглаж байсан. Тэнд байгаа физикийн API нь статик, физик ертөнц нь нэг хуулбарт байдаг. Түүний төлөвийг хадгалах, дараа нь хайрцагнаас сэргээх арга байхгүй. Тэгэхээр юу хийх вэ?

Шийдэл нь гадаргуу дээр байсан бөгөөд түүний бүх элементүүдийг бид бусад асуудлыг шийдвэрлэхэд аль хэдийн ашигласан:

  1. Үйлчлүүлэгч бүрийн хувьд бид товчлуурыг дарахад өрсөлдөгчөө хэдэн цагт харсан болохыг мэдэх хэрэгтэй. Бид энэ мэдээллийг оролтын багцад аль хэдийн бичиж, үйлчлүүлэгчийн таамаглалыг тохируулахад ашигласан.
  2. Бид тоглоомын төлөв байдлын түүхийг хадгалах чадвартай байх хэрэгтэй. Үүний дотор бид өрсөлдөгчдийнхөө (тиймээс тэдний мөргөлдүүлэгчдийн) байр суурийг эзлэх болно. Бид сервер дээр аль хэдийн төрийн түүхтэй байсан, бид үүнийг бүтээхэд ашигласан дельта. Бид зөв цагийг мэдсэнээр түүхэн дэх зөв төлөвийг хялбархан олж чадна.
  3. Одоо бид түүхэн дэх тоглоомын төлөвийг гартаа барьж байгаа тул тоглогчийн өгөгдлийг физик ертөнцийн төлөвтэй синхрончлох чадвартай байх хэрэгтэй. Одоо байгаа мөргөлдөөгчид - хөдөлж, алга болсон нь - үүсгэх, шаардлагагүй нь - устгах. Энэ логик нь аль хэдийн бичигдсэн бөгөөд хэд хэдэн ECS системээс бүрдсэн байв. Бид үүнийг нэг Unity процесст хэд хэдэн тоглоомын өрөө барихад ашигласан. Физик ертөнц нь процесс бүрт нэг байдаг тул өрөөнүүдийн хооронд дахин ашиглах шаардлагатай болсон. Симуляци хийхээс өмнө бид физик ертөнцийн төлөвийг "дахин тохируулж", одоогийн өрөөний өгөгдлөөр дахин эхлүүлж, ухаалаг нэгдсэн системээр дамжуулан Unity тоглоомын объектуудыг аль болох дахин ашиглахыг хичээдэг. Үлдсэн зүйл бол өнгөрсөн үеийн тоглоомын төлөвийн ижил логикийг дуудах явдал байв.

Эдгээр бүх элементүүдийг нэгтгэснээр бид физик ертөнцийн төлөв байдлыг зөв цагт эргүүлж чадах "цаг хугацааны машин"-тай болсон. Код нь энгийн болсон:

public class TimeMachine : ITimeMachine
{
     //История игровых состояний
     private readonly IGameStateHistory _history;

     //Текущее игровое состояние на сервере
     private readonly ExecutableSystem[] _systems;

     //Набор систем, расставляющих коллайдеры в физическом мире 
     //по данным из игрового состояния
     private readonly GameState _presentState;

     public TimeMachine(IGameStateHistory history, GameState presentState, ExecutableSystem[] timeInitSystems)
     {
         _history = history; 
         _presentState = presentState;
         _systems = timeInitSystems;  
     }

     public GameState TravelToTime(int tick)
     {
         var pastState = tick == _presentState.Time ? _presentState : _history.Get(tick);
         foreach (var system in _systems)
         {
             system.Execute(pastState);
         }
         return pastState;
     }
}

Үлдсэн зүйл бол энэ машиныг хэрхэн ашиглах, цохилт, чадварыг хялбархан нөхөх явдал байв.

Хамгийн энгийн тохиолдолд, механикууд нь нэг цохилт дээр суурилдаг бол бүх зүйл тодорхой байх шиг байна: тоглогч буудахаасаа өмнө физик ертөнцийг хүссэн төлөв рүү нь эргүүлж, raycast хийх, цохилт эсвэл алдсаныг тоолох, мөн дэлхийг анхны байдалд нь буцаана.

Гэхдээ Dino Squad-д ийм механик маш цөөхөн байдаг! Тоглоомын ихэнх зэвсгүүд нь сум үүсгэдэг - хэд хэдэн симуляцийн хачигт (зарим тохиолдолд хэдэн арван хачиг) нисдэг урт хугацааны сумнууд. Тэдэнтэй юу хийх вэ, тэд хэдэн цагт нисэх ёстой вэ?

В эртний нийтлэл Half-Life сүлжээний стекийн талаар Valve-ийн залуус ижил асуулт асуусан бөгөөд тэдний хариулт нь: сумны хоцрогдлын нөхөн төлбөр нь асуудалтай тул үүнээс зайлсхийх нь дээр.

Бидэнд ийм сонголт байгаагүй: суманд суурилсан зэвсэг нь тоглоомын дизайны гол шинж чанар байв. Тиймээс бид ямар нэг юм бодож олох хэрэгтэй болсон. Бага зэрэг оюуны довтолгооны дараа бид үр дүнтэй мэт санагдсан хоёр хувилбарыг боловсруулсан:

1. Бид сумыг бүтээсэн тоглогчийн цагтай холбоно. Серверийн симуляцийн тэмдэг болгон, тоглогч бүрийн сум бүрт бид физик ертөнцийг үйлчлүүлэгчийн төлөв рүү буцааж, шаардлагатай тооцооллыг хийдэг. Энэ арга нь серверт хуваарилагдсан ачаалал, пуужингийн нисэх хугацааг урьдчилан таамаглах боломжтой болгосон. Урьдчилан таамаглах чадвар нь бидний хувьд онцгой чухал байсан, учир нь бид бүх пуужингууд, тэр дундаа дайсны сумыг үйлчлүүлэгч дээр урьдчилан таамагласан байдаг.

Сүлжээний хоцрогдол нөхөх алгоритм бүхий гар буучдад зориулсан баллистик тооцооны механикийг бид хэрхэн хийсэн бэ
Зураг дээр 30-р тэмдэгт тоглогч пуужин харваж байна: тэр дайсан аль чиглэлд гүйж байгааг харж, пуужингийн ойролцоо хурдыг мэддэг. Орон нутагт тэрээр 33 дахь хачигт оносон байна гэж хардаг. Хоцрогдлын нөхөн олговрын ачаар энэ нь сервер дээр гарч ирэх болно

2. Бид эхний сонголттой адил бүх зүйлийг хийдэг, гэхдээ сумны симуляцийн нэг тэмдэгийг тоолсны дараа бид зогсохгүй, харин серверийн цагийг ойртуулах болгонд ижил серверийн тэмдэг дотор нислэгийг дуурайсаар байна. нэг нэгээр нь тэмдэглэж, коллайдерын байрлалыг шинэчилж байна. Хоёр зүйлийн аль нэг нь болох хүртэл бид үүнийг хийдэг:

  • Сумны хугацаа дууссан. Энэ нь тооцоо дууссан гэсэн үг юм, бид алдсан, эсвэл хит тоолж болно. Мөн энэ нь буудсантай ижил хачиг юм! Бидний хувьд энэ нь нэмэх, хасах аль аль нь байсан. Давуу тал нь - буудлагын тоглогчийн хувьд энэ нь цохилтын хоорондох саатал болон дайсны эрүүл мэндийг бууруулахад ихээхэн нөлөөлсөн. Сул тал нь өрсөлдөгчид нь тоглогч руу буудах үед ижил нөлөө ажиглагдсан: дайсан нь зөвхөн удаан пуужин харвасан бололтой, хохирлыг аль хэдийн тооцсон.
  • Сум серверийн цагт хүрсэн байна. Энэ тохиолдолд түүний симуляци нь хоцрогдлын нөхөн төлбөргүйгээр дараагийн серверийн тэмдэглэгээнд үргэлжлэх болно. Удаан пуужингийн хувьд энэ нь эхний хувилбартай харьцуулахад физикийн буцаалтын тоог онолын хувьд бууруулж чадна. Үүний зэрэгцээ симуляцийн жигд бус ачаалал нэмэгдэв: сервер идэвхгүй байсан эсвэл нэг серверийн хачигт хэд хэдэн суманд зориулж хэдэн арван симуляцийн тэмдэглэгээг тооцоолж байв.

Сүлжээний хоцрогдол нөхөх алгоритм бүхий гар буучдад зориулсан баллистик тооцооны механикийг бид хэрхэн хийсэн бэ
Өмнөх зурган дээрхтэй ижил хувилбар боловч хоёр дахь схемийн дагуу тооцоолсон. Пуужин харвасан үед серверийн цагийг "барьсан" бөгөөд цохилтыг дараагийн хачигт л тоолж болно. 31 дэх хачигт энэ тохиолдолд хоцрогдлын нөхөн олговрыг хэрэглэхээ больсон

Бидний хэрэгжүүлэх явцад эдгээр хоёр хандлага нь зөвхөн хоёр мөр кодоор ялгаатай байсан тул бид хоёуланг нь үүсгэсэн бөгөөд удаан хугацааны туршид зэрэгцээ оршиж байсан. Зэвсгийн механик, сумны хурд зэргээс хамааран бид үлэг гүрвэл бүрийн хувьд нэг юмуу өөр сонголтыг сонгосон. Энд эргэлтийн цэг нь механикийн тоглоомд "Та дайсныг ийм ийм хугацаанд олон удаа цохисон бол ийм ийм урамшуулал аваарай" гэсэн дүр төрх байв. Тоглогч дайсныг цохих үед чухал үүрэг гүйцэтгэсэн аливаа механикч хоёр дахь арга барилтай ажиллахаас татгалзав. Тиймээс бид эхний сонголтыг хийж дуусгасан бөгөөд энэ нь одоо бүх зэвсэг, тоглоомын бүх идэвхтэй чадварт хамаарна.

Тус тусад нь гүйцэтгэлийн асуудлыг хөндөх нь зүйтэй юм. Хэрэв та энэ бүхнийг удаашруулна гэж бодсон бол би хариулна: тийм байна. Эв нэгдэл нь мөргөлдүүлэгчийг хөдөлгөж, асаах, унтраахад нэлээд удаан байдаг. Dino Squad-д "хамгийн муу" тохиолдолд тулалдаанд нэгэн зэрэг хэдэн зуун пуужин байж болно. Сөрөг тус бүрийг тус тусад нь тоолохын тулд коллайдеруудыг хөдөлгөх нь үнэд хүрэхийн аргагүй тансаглал юм. Тиймээс бид физикийн "буцах" тоог багасгах зайлшгүй шаардлагатай байсан. Үүнийг хийхийн тулд бид ECS-д тоглогчийн цагийг бүртгэх тусдаа бүрэлдэхүүн хэсэг үүсгэсэн. Бид үүнийг хоцрогдлын нөхөн төлбөр шаарддаг бүх байгууллагуудад (харваа, чадвар гэх мэт) нэмсэн. Бид ийм аж ахуйн нэгжүүдийг боловсруулж эхлэхээсээ өмнө тэдгээрийг кластер болгон нэгтгэж, кластер бүрт нэг удаа физик ертөнцийг буцаан шилжүүлдэг.

Энэ үе шатанд бид ерөнхийдөө ажилладаг системтэй болсон. Түүний код нь арай хялбаршуулсан хэлбэрээр:

public sealed class LagCompensationSystemGroup : ExecutableSystem
{
     //Машина времени
     private readonly ITimeMachine _timeMachine;

     //Набор систем лагкомпенсации
     private readonly LagCompensationSystem[] _systems;
     
     //Наша реализация кластеризатора
     private readonly TimeTravelMap _travelMap = new TimeTravelMap();

    public LagCompensationSystemGroup(ITimeMachine timeMachine, 
        LagCompensationSystem[] lagCompensationSystems)
     {
         _timeMachine = timeMachine;
         _systems = lagCompensationSystems;
     }

     public override void Execute(GameState gs)
     {
         //На вход кластеризатор принимает текущее игровое состояние,
         //а на выход выдает набор «корзин». В каждой корзине лежат энтити,
         //которым для лагкомпенсации нужно одно и то же время из истории.
         var buckets = _travelMap.RefillBuckets(gs);

         for (int bucketIndex = 0; bucketIndex < buckets.Count; bucketIndex++)
         {
             ProcessBucket(gs, buckets[bucketIndex]);
         }

         //В конце лагкомпенсации мы восстанавливаем физический мир 
         //в исходное состояние
         _timeMachine.TravelToTime(gs.Time);
     }

     private void ProcessBucket(GameState presentState, TimeTravelMap.Bucket bucket)
     {
         //Откатываем время один раз для каждой корзины
         var pastState = _timeMachine.TravelToTime(bucket.Time);

         foreach (var system in _systems)
         {
               system.PastState = pastState;
               system.PresentState = presentState;

               foreach (var entity in bucket)
               {
                   system.Execute(entity);
               }
          }
     }
}

Үлдсэн зүйл бол дэлгэрэнгүй мэдээллийг тохируулах явдал байв.

1. Хөдөлгөөний хамгийн их зайг цаг хугацаанд нь хэр хэмжээгээр хязгаарлахыг ойлгох.

Мобайл сүлжээ муутай нөхцөлд тоглоомыг аль болох хүртээмжтэй болгох нь бидний хувьд чухал байсан тул бид түүхийг 30 тэмдэгтийн зөрүүгээр (20 Гц давтамжтай) хязгаарласан. Энэ нь тоглогчдод маш өндөр ping дээр ч өрсөлдөгчөө цохих боломжийг олгодог.

2. Аль объектыг цаг хугацаанд нь хөдөлгөж, аль нь хөдөлгөж болохгүйг тодорхойлох.

Бид мэдээж өрсөлдөгчдөө хөдөлгөж байна. Гэхдээ жишээлбэл, суурилуулж болох эрчим хүчний бамбай нь тийм биш юм. Онлайн мэргэн буучдад ихэвчлэн хийдэг шиг хамгаалалтын чадварыг нэн тэргүүнд тавих нь дээр гэж бид шийдсэн. Хэрэв тоглогч одоо бамбайгаа аль хэдийн байрлуулсан бол өнгөрсөн үеийн хоцролтыг нөхсөн сумууд дундуур нь нисэх ёсгүй.

3. Үлэг гүрвэлийн чадварыг нөхөх шаардлагатай эсэхийг шийдэх: хазах, сүүл цохих гэх мэт. Бид юу хэрэгтэйг шийдэж, сумтай ижил дүрмийн дагуу боловсруулдаг.

4. Хоцролтын нөхөн төлбөр хийгдэж байгаа тоглогчийн мөргөлдүүлэгчийг юу хийхийг тодорхойлох. Нэг ёсондоо тэдний байр суурь өнгөрсөн үе рүү шилжих ёсгүй: тоглогч сервер дээр байгаа тэр цаг хугацаандаа өөрийгөө харах ёстой. Гэсэн хэдий ч бид бууддаг тоглогчийн мөргөлдөөнийг эргүүлж өгдөг бөгөөд үүнд хэд хэдэн шалтгаан бий.

Нэгдүгээрт, энэ нь кластержилтыг сайжруулдаг: бид ойр дотны пингтэй бүх тоглогчдын хувьд ижил физик төлөвийг ашиглаж болно.

Хоёрдугаарт, бүх цацраг туяа, давхцал дээр бид чадвар эсвэл сум эзэмшдэг тоглогчийн мөргөлдөөнийг үргэлж оруулдаггүй. Dino Squad-д тоглогчид буудлагын стандартаар стандарт бус геометртэй үлэг гүрвэлүүдийг удирддаг. Хэдийгээр тоглогч ер бусын өнцгөөр харваж, сумны зам нь тоглогчийн үлэг гүрвэлийн мөргөлдүүлэгчийг дайран өнгөрч байсан ч сум үүнийг үл тоомсорлох болно.

Гуравдугаарт, бид үлэг гүрвэлийн зэвсгийн байрлал эсвэл чадварыг ашиглах цэгийг ECS-ийн өгөгдлийг ашиглан хоцролтыг нөхөхөөс өмнө тооцдог.

Үүний үр дүнд хоцрогдол нөхсөн тоглогчийн мөргөлдүүлэгчдийн бодит байрлал нь бидний хувьд чухал биш тул бид илүү үр бүтээлтэй, нэгэн зэрэг энгийн замыг сонгосон.

Сүлжээний хоцролтыг зүгээр л арилгах боломжгүй, зөвхөн далдлах боломжтой. Хувцаслах бусад аргуудын нэгэн адил серверийн хоцрогдлын нөхөн олговор нь давуу талтай байдаг. Энэ нь буудаж буй тоглогчийн зардлаар буудаж буй тоглогчийн тоглоомын туршлагыг сайжруулдаг. Дино багийн хувьд энд сонголт илт байсан.

Мэдээжийн хэрэг, энэ бүгдийг серверийн кодын нарийн төвөгтэй байдал нь програмистууд болон тоглоомын дизайнеруудын аль алинд нь төлөх ёстой байв. Хэрэв өмнө нь симуляци нь системийн энгийн дараалсан дуудлага байсан бол хоцрогдлын нөхөн олговортойгоор дотор нь үүрлэсэн гогцоо, мөчрүүд гарч ирэв. Түүнтэй ажиллахад тохиромжтой болгохын тулд бид бас маш их хүчин чармайлт гаргасан.

2019 оны хувилбарт (мөн магадгүй арай эрт) Unity бие даасан физик үзэгдэлд бүрэн дэмжлэг нэмсэн. Бид шинэчлэгдсэний дараа бараг тэр даруй сервер дээр хэрэгжүүлсэн, учир нь бид бүх өрөөнд нийтлэг байдаг физик ертөнцөөс хурдан ангижрахыг хүссэн.

Бид тоглоомын өрөө болгонд өөрийн гэсэн физик дүр зургийг өгсөн бөгөөд ингэснээр симуляцийг тооцоолохын өмнө хөрш зэргэлдээх өрөөний мэдээллээс дүр зургийг "цэвэрлэх" шаардлагагүй болсон. Нэгдүгээрт, энэ нь бүтээмжийг мэдэгдэхүйц нэмэгдүүлэх боломжийг олгосон. Хоёрдугаарт, программист тоглоомын шинэ элементүүдийг нэмэхдээ дүр зургийг цэвэрлэх кодонд алдаа гаргасан тохиолдолд үүссэн бүхэл бүтэн ангиллын алдаанаас ангижрах боломжтой болсон. Ийм алдааг засахад хэцүү байсан бөгөөд тэдгээр нь ихэвчлэн нэг өрөөний үзэгдэл дэх биет объектуудын төлөв байдлыг нөгөө өрөөнд "урсдаг" байв.

Үүнээс гадна бид физик үзэгдлүүдийг физик ертөнцийн түүхийг хадгалахад ашиглаж болох эсэхийг судалж үзсэн. Өөрөөр хэлбэл, нөхцөлт байдлаар өрөө бүрт нэг үзэгдэл биш, харин 30 үзэгдэл хуваарилж, түүхийг хадгалах циклийн буфер хийх хэрэгтэй. Ерөнхийдөө энэ сонголт амжилттай болсон боловч бид үүнийг хэрэгжүүлээгүй: энэ нь бүтээмжийн галзуу өсөлтийг харуулаагүй, харин эрсдэлтэй өөрчлөлтүүдийг шаарддаг. Ийм олон үзэгдэлтэй удаан хугацаанд ажиллахад сервер хэрхэн ажиллахыг таамаглахад хэцүү байсан. Тиймээс бид дүрмийг дагаж мөрдсөн: "Хэрэв энэ нь эвдэрч чадахгүй бол түүнийг засах хэрэггүй".

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх