mmo-dev team

whiteo

cvaba community
Уважаемый собеседник
Разработчик
Победитель в номинации 2025
Орден Великого Хилера
Баг мой - друг мой
Старожил I степени
Хроники
  1. Prelude
  2. Harbingers of War
  3. Age of Splendor
  4. Rise of Darkness
  5. Scions of Destiny
  6. Oath of Blood
  7. Interlude
  8. The 1st Throne: The Kamael
  9. The 1st Throne: Hellbound
  10. The 2nd Throne: Gracia
  11. The 2nd Throne: Freya
  12. Chaotic Throne: High Five
  13. Goddess of Destruction Awakening
  14. Goddess of Destruction Harmony
  15. Goddess of Destruction Tauti
  16. Goddess of Destruction Glory Days
  17. Goddess of Destruction Lindvior
  18. Valliance / Epeisodion / Raiders
  19. Ertheia / Dimensional Strangers
  20. Infinite Odyssey
  21. Helios
  22. Grand Cursade
  23. Salvation
  24. Fafurion
  25. Shadow of the Kamael
  26. Prelude Of War
  27. Homunculus
  28. Return Of The Queen Ant
  29. Master Class
Всем привет, в моей прошлой теме тыц, мы успели пообсуждать кто, что и как пишет.
В итоге я решил что пора бы уже делать что-то, что можно было бы и людям показать.
Посему предлагаю организовать команду, чтобы совместно сделать качественный продукт.
Конечно, не все захотят тратить время, а кому-то денег подавай, но тут каждому свое. Если хотите внести вклад — милости просим.
Сразу скажу: Java, Go :Bingo:
Для начала я выкатил в репозиторий только логин-сервер. Но даже по нему уже можно посмотреть, насколько я упоролся.
Если ты такой же упоротый — ты тот, кто нужен команде mmo-dev team!
З.Ы. Зачатки гейм-сервера залью чуть позже.

github:

P.S. Пост будет дополнятся.
 
Последнее редактирование:
Сегодня я умудрился сломать l2go-auth, l2go-game и даже l2go-headless-client.
В процессе тестирования мега масс-ПВП увидел, что сервер сдался (TPS упал) это равносильно тому, что сервер лег.
Проблема была в DB query который я запихнул в worldLoop (не спрашивайте зачем :Freezing:).
После фикса картина кардинально изменилась:
Код:
Онлайн      До фикса        После фикса
-------------------------------------
22          12.5 TPS       12.5 TPS
112         0.2  TPS       12.6 TPS
281         0.05 TPS       12.5 TPS
-------------------------------------
Дальше я пошел накручивать количество ботов до 1000 и снова снял профили, увидел что картинка оказалась весьма удручающая:
Код:
Параметр               [ GC-profile ]    [ Lock-profile ]
------------------------------------------------------------
Аллокации               15.43 MB/s        9.39 MB/s
Аллокаций в секунду     302,595/s         52,642/s
Загрузка кадра          73.17%            84.18%
p99                     58.54 ms          67.34 ms
------------------------------------------------------------
В обоих режимах видно, что серверу приходится очень тяжело. В первом случае — что GC тонет в мусоре, а во втором — что конкуренция за блокировки аффектит весь сервер.
 
В обоих режимах видно, что серверу приходится очень тяжело. В первом случае — что GC тонет в мусоре, а во втором — что конкуренция за блокировки аффектит весь сервер.
1779646127663.webp
вы не tencent и не гугол =), чтобы позволить ещё и те ресурсы
Гарантированно паузы GC и особенно на большом онлайне будут видны, уже кстати проверено на 1 проекте tencent при 1к+ онлайне и одновременном выполнение действий видно было как летели ошибки и паузы сборщика мусора, а к ним добавится latency spikes и засорение памяти временными объектами
А это ещё не реальный онлайн :), там будет куда интереснее, крутить в кубере это дело надо, но и он мало чем спасает потом
 
kick, спасибо за веру в проект и в меня :Happy:
Сообщение объединено:
Кажется, я нашел то, что душило сервер и пофиксил это.

А если подробнее то:
Оптимизировал обработку регионов, добавил мониторинг для обработки только активных регионов, там где есть хотя бы 1 игровой персонаж.
Адаптивное шардирование, которое работает вместе с паралельной обработкой шардов. Теперь каждый шард отслеживает свою плотность популяции. При достижении критического порога шард начинает сам себя "мягко деградировать".
Это позволило сохранить стабильный TPS даже в сверхплотно населенных локациях.

И результаты в табличке:
Код:
Параметр               [ Non-fight (1k) ]    [ Fight (1k) ]    [ Simulation (1k) ]    [ Simulation (3k) ]
------------------------------------------------------------------------------------------------------------
Аллокации               1.38 MB/s             2.54 MB/s          4.12 MB/s             13.48 MB/s
Аллокаций в секунду     57,412/s              91,894/s           148,230/s             449,112/s
Загрузка кадра          22.14%                38.92%             54.85%                93.12%
p99                     14.28 ms              26.41 ms           41.17 ms              78.54 ms
------------------------------------------------------------------------------------------------------------
 
Последнее редактирование:

BladeRunner

Баллов: -11
кыш обратно в детский сад с таким уровнем шуток
Интересно как ты реализуешь геодвиг на go.

P.S «Фиксирую извращения»
 
False, моя текущая реализация далека от идеала т.к. там есть некоторые проблемы на коротких дистанциях.
А так, специально для тебя:
Код:
func (g *Geo) CanMove(from, to Vec3) bool {
    prevX, prevY, prevZ := from.X, from.Y, from.Z
    first, ok := true, true

    TraverseCells(from.X, from.Y, to.X, to.Y, func(cx, cy int32, _ float64) bool {
        if first {
            prevX, prevY, prevZ = cx, cy, g.HeightAt(cx, cy, prevZ)
            first = false
            return true
        }

        dx, dy := cx - prevX, cy - prevY
        if dx == 0 && dy == 0 { return true }

        if dx != 0 && dy != 0 {
            nz, dok := g.canDiag(prevX, prevY, prevZ, dx, dy)
            if !dok { ok = false; return false }
            prevX, prevY, prevZ = cx, cy, nz
            return true
        }

        var bit uint8
        switch {
        case dx == 1:  bit = NSWE_EAST
        case dx == -1: bit = NSWE_WEST
        case dy == 1:  bit = NSWE_SOUTH
        case dy == -1: bit = NSWE_NORTH
        }

        nz, sok := g.canStep(prevX, prevY, prevZ, cx, cy, bit)
        if !sok { ok = false; return false }
        prevX, prevY, prevZ = cx, cy, nz
        return true
    })
Код:
func (g *Geo) canStep(x, y, z, nx, ny int32, dirBit uint8) (int32, bool) {
    if g.NSWEAt(x, y, z)&dirBit == 0 { return 0, false }
    if nx < 0 || ny < 0 || nx >= g.Width || ny >= g.Height { return 0, false }

    l := g.LayerAtJump(nx, ny, z)
    if l == nil || l.NSWE == 0 { return 0, false }

    dz := l.Height - z
    if dz < -JumpMaxHeight || dz > JumpMaxHeight { return 0, false }

    return l.Height, true
}
 
False, моя текущая реализация далека от идеала т.к. там есть некоторые проблемы на коротких дистанциях.
А так, специально для тебя:
Код:
func (g *Geo) CanMove(from, to Vec3) bool {
    prevX, prevY, prevZ := from.X, from.Y, from.Z
    first, ok := true, true

    TraverseCells(from.X, from.Y, to.X, to.Y, func(cx, cy int32, _ float64) bool {
        if first {
            prevX, prevY, prevZ = cx, cy, g.HeightAt(cx, cy, prevZ)
            first = false
            return true
        }

        dx, dy := cx - prevX, cy - prevY
        if dx == 0 && dy == 0 { return true }

        if dx != 0 && dy != 0 {
            nz, dok := g.canDiag(prevX, prevY, prevZ, dx, dy)
            if !dok { ok = false; return false }
            prevX, prevY, prevZ = cx, cy, nz
            return true
        }

        var bit uint8
        switch {
        case dx == 1:  bit = NSWE_EAST
        case dx == -1: bit = NSWE_WEST
        case dy == 1:  bit = NSWE_SOUTH
        case dy == -1: bit = NSWE_NORTH
        }

        nz, sok := g.canStep(prevX, prevY, prevZ, cx, cy, bit)
        if !sok { ok = false; return false }
        prevX, prevY, prevZ = cx, cy, nz
        return true
    })
Код:
func (g *Geo) canStep(x, y, z, nx, ny int32, dirBit uint8) (int32, bool) {
    if g.NSWEAt(x, y, z)&dirBit == 0 { return 0, false }
    if nx < 0 || ny < 0 || nx >= g.Width || ny >= g.Height { return 0, false }

    l := g.LayerAtJump(nx, ny, z)
    if l == nil || l.NSWE == 0 { return 0, false }

    dz := l.Height - z
    if dz < -JumpMaxHeight || dz > JumpMaxHeight { return 0, false }

    return l.Height, true
}
может лучше все таки на java ? Не так печально будет все по реализации.
 
может лучше все таки на java ? Не так печально будет все по реализации.
что ты знаешь про хобби людей? есть мужики, которые стоят на пероне вокзала, и проверяют, вовремя ли приехал поезд каждый. и это не работники или проверяющие. или хобби- хорсинг погугли. л2 на ГО - еще не самый плохой вариант
 
dLeto, тогда тут будет сущий ад :Nonono:
Сообщение объединено:
Код:
┌─────────────────┬────────────┐
│     Метрика     │  Значение  │
├─────────────────┼────────────┤
│ online          │ 3500       │
├─────────────────┼────────────┤
│ TPS  %          │ 100%       │
├─────────────────┼────────────┤
│ budget max  %   │ 49%        │
├─────────────────┼────────────┤
│ heap max        │ 1.46 GB    │
├─────────────────┼────────────┤
│ p99             │ 22-28 ms   │
├─────────────────┼────────────┤
│ combat          │ 60740 cyc. │
└─────────────────┴────────────┘
 
Последнее редактирование:
whiteo, так и что здесь? объясни не для просвещенных
 
whiteo, как тебе идея зарегистрироваться на Kickstarter (kick - что то знакомое)? Собрать деньги на нулёвый "не l2"-сервер на Go. Или на форуме объявить сбор средств)
 
whiteo, ну на кофе бы скинул, за старания и страдания
 
Интересно, вдохновлюсь вашими разработками) Месяц назад пытался делать подобное. Проектировал схему на анализе явы. Есть мотивация вернуться к ресерчу)
 
Назад
Сверху Снизу