• Будьте внимательны, не попадайтесь на уловки мошенников и при возможности используйте наш сервис. Также ознакомьтесь - Рекомендации по защите от мошенников.
  • Из-за обновления GTA 5 (был добавлен новый патч) может временно не работать вход в RAGE Multiplayer.

    Ошибка: Ваша версия Grand Theft Auto V не поддерживается RAGE Multiplayer.
    ERROR: Your game version is not supported by RAGE Multiplayer.

    Данная ошибка говорит о том, что GTA V обновилась до новой версии (GTA Online тоже). Вам необходимо обновить саму игру в главном меню вашего приложения (Steam / Epic Games / Rockstar Games).
    Если после этого RAGE:MP все равно не работает - вам нужно дождаться выхода патча для самого мультиплеера (обычно это занимает от нескольких часов до нескольких дней).

    Новости и апдейты Rockstar Games - https://www.rockstargames.com/newswire/
    Статус всех служб для Rockstar Games Launcher и поддерживаемых игр: https://support.rockstargames.com/ru/servicestatus


    Grand Theft Auto 5 (+ GTA Online) последний раз были обновлены:

Разработка Backend разработчик [C#/TS]

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147
Backend-разработчик
2020 - настоящее время
Разработка игровых скриптов, модов и серверов в RAGE MP.
  • Технологический стек: .NET (C#), JavaScript (+ TypeScript), SQL, Vue.
  • Отличное знание RAGE MP API и основ синхронизации.
  • Опыт в написании кастомных решений для синхронизации и обхода ограничений платформы.
  • Специализация на .NET, но также работал с клиентской частью на C# / JS / TS, предпочитая TypeScript за строгую типизацию.
  • Выполнение специфического кейса FULL C# gamemode, где серверная, клиентская и UI части были реализованы исключительно на C#.
  • Опыт работы с объектно-ориентированным программированием и гибридными подходами.
  • Реализация и поддержка технического кода для разработчиков (из команды)

Компетенции​

  • Кодирование:
    • Опыт в рефакторинге и ревью кода
    • Опыт в работе с легаси-кодом.
    • Умение оптимизировать код по мере необходимости.
    • Шаманство с рефлексией.
    • Написание статических анализаторов (требовалось для автоматического контроля кода других разработчиков из команды).
    • Патчинг кода библиотек в рантайме.
  • Командная работа:
    • Интересуюсь работой в команде.
    • Возможность работы в одиночку (за исключением фронтенда) при необходимости.

Условия и требования​

  • График: 5/2 (8 часов в день, гибкий график).
  • Удаленная работа.
  • Заработная плата: от 160 000 рублей. (Готов обсудить менее сумму с соответствующей нагрузкой.)

Ссылки:
Большая часть моих реализаций выполнялись под NDA, в свободном доступе их нет. Постараюсь скидывать сюда ссылки на видео-демонстрации разных сценариев, если найду или смогу записать.
 
Последнее редактирование:

Harland David Sanders

🍔 ChefBurger
Команда форума
High developer
10 Сен 2020
3,933
3,158
259
160к мало вроде не?
 

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147

Harland David Sanders

🍔 ChefBurger
Команда форума
High developer
10 Сен 2020
3,933
3,158
259
Да, это минимальная оплата. Разумеется будет обговариваться сумма больше в зависимости от задач, от позиции в команде и от ответственности.
тогда какие задачи примерно входят в график 5\2 по 8 часов в день? по твоему мнению
 

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147
тогда какие задачи примерно входят в график 5\2 по 8 часов в день? по твоему мнению
Задачи относящиеся только к разработке. То есть, я не занимаюсь менторством, ревью кода, не слежу за продом. (Не говорю, что не могу этим заниматься, а лишь обосновываю деятельность за минимальную плату)
Больше задач (разнотипных), шире зона ответственности – плата выше. Но я всегда брал меньше в основном. Поэтому о каких-то космических цифрах речи не идёт.
 
Реакции: Harland David Sanders

MADARAdev

Гений
media
FrontEnd developer
30 Дек 2020
781
301
146
29
Очень крут!
Работы классные!

Так крутить бланты только он могет.
 
Реакции: JJIGolem

enotit

Высший разум
High developer
BackEnd developer
13 Ноя 2020
1,820
611
187
22
На самом деле грустно видеть такого уровня специалиста в этом разделе, я думал как пирожки разлетиться.
Единственный разработчик (!= кодер), которого я советую в любом случае. Его профессиональные и личные навыки великолепны, хотя профессиональные, конечно, преобладают.
 
Реакции: JJIGolem

MoonFusion

Старожил
BackEnd developer
14 Июн 2021
392
262
149
Не смог пройти мимо, к сожалению для моего личного времени.
Что меня тут задержало? Вилка 160к, хвалебные отзывы, решаю углубится в твою профессиональную деятельность.

Если кому то интересно просто моё мнение и выводы на основе этого "Углубления", либо если кому то просто не интересны технические занудства, рекомендую сразу перейти к главе III.

Глава I - Portfolio ( YouTube )

Решаю поверхностно изучить работы автора, захожу на его первое актуальное видео, система автобусника. Достаточно примитивная система в качестве демонстрационной, но все же она одна из самых свежих и по этому показательных. Изучив видео в глаза сразу бросаются маркеры установленные на +1 по Z от земли, что как бы уже намекает на уровень реализации, далее видим как автобус подъезжает к первой остановке и наблюдаем самый спорный момент реализации системы разработчиком за 160.000 рублей в месяц, поведение NPC. Все дёргано, криво, если NPC не успевает дойти, его телепортирует в транспорт. Слишком очевидная последовательность действий, там просто поочередно вызываются таски у NPC, что выглядит очень топорно, причем даже такая реализация в лоб все равно каким то образом допускает то что NPC толкают друг друга. Сразу префаером предполагаю что никакой синхронизации нормальной там нет ( почему я так решил, узнаем в главе II ).

Изучил ещё пару видео, ничего интересного, или хотя бы сложного я там не увидел, все на уровне задач начинающего разработчика, по этому сразу перейдем к более интересной части этого разбора.

Глава II - GitHub.

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

rage-custom-weapon-damage

Ремарка. Я понимаю что система была написана 4 года назад, но автор 10 месяцев назад её актуализировал, по этому будем считать её свежей, даже если автор так не считает.
Так же далее будем смотреть динамику на более актуальных репах.

Демонстрация этой системы была также на YouTube по этому начнём с неё. Задумка системы простая, обеспечить возможность гибкой настройки урона оружия, переопределяя стандартный урон. Для реализации такой системы нужно обеспечить всего три основные вещи, возможность гибкой настройки, самое переопределение урона, а так же синхронизацию этого всего дела сервером для безопасности, звучит просто, разберём что мы увидели.

К сожалению автор по всей видимости на момент написания системы ещё не был знаком с TypeScript ( или не захотел внедрять в такую простую систему ), изучив остальные репозитория я не увидел примеров систем с TypeScript в целом, по этому далее на это внимания обращать не будем.

Первое что попалось в глаза, файл конфигурации системы. Файл вида JS object в котором присутствует несколько уровней вложенности, что уже как бы не совсем удобно для его конфигурации, но пик неудобства тут это то что ключ конфигурируемого оружия является хэшем оружия, а не его названием по типу "Pistol", думаю объяснять почему это очень неудобно объяснять не нужно, автору советую изучить тему маппинга для таких случаев. Разделение на конкретный хэш оружия и на группу оружия выглядит нормальным решением.

Идём в основной файл системы. defaultPercent - почему-то находится не в конфигурационном файле, что выглядит странно при его наличии.

Вся система находится в одном файле, что очень неудобно при масштабировании, автору советую делить код как минимум на два слоя, контроллер и бизнес логика, причём бизнес логику при необходимости делить так же на модули.

В методе encode мы видим throw new Error, который в дальнейшем при вызове этого метода нигде не обрабатывается, что является критической ошибкой при разработке любого уровня сложности системы, необработанные ошибки всего сложно читаемы, автору же советую использовать либо try catch при вызове методов которые могут дрогнуть ошибку, либо использовать mp.console.logError, что в этом кейсе более логично.

Очень много "magic numbers" в коде, по типу bondeIndex головы.

Почему то урон в голову у нас делится на 10, хотя в комментариях к коду автор вроде как хотел увеличить урон в голову, не совсем понятно.

Но это все мелочи, основной вопрос. Где синхронизация урона с сервером? Почему автор доверяет клиенту и предопределяет урон только на стороне клиента? По хорошему на клиенте мы должны были собирать информацию о выстреле на клиенте, после чего отправить эти данные на сервер для валидации этого урона и уже после этого отправлять на клиент новое состояние игрока ( HP ). Критический момент реализации.

rage-driftmode-freeroam / custom radio commit ( 10-5m ago )

Идём далее, к более интересному и свежему. У автора есть игровой мод с открытым исходным кодом, немного изучив репозиторий первое что кинулось в глаза - бинарники в гите, зачем? Непонятно. Никогда так не делайте, добавляйте бинарники в gitignore, если же там нужно специфическая версия билда либо указывайте её версию, либо заливайте билд отдельно.

Сосредоточимся на самом свежем что автор добавил в мод, систему костюмного радио, разберём сначала серверную часть.

Использование var считается устаревшей практикой, крайне рекомендую использовать let. Хотя далее автор все же использует let, не совсем понятно зачем использовать var в таком случае, если автор в курсе что существует let/const.

Теперь самое критичное, производительность кода и сама бизнес логика, это полный пиздец мягко говоря. Во первых - это совсем не читабельно и не масштабируемо, процедурный код без намёка на модульность, очень плохо. о производительности все ещё хуже, объясню кратко как работает его система, по сути есть какие то звуки которые должны проигрываться для машин, код написан так что каждые 50 ms ( 20~ раз в секунду ) код проходится по всем машинам на сервере, затем для каждого игрока на сервере идёт проверка находится ли он в слушателях, после чего игрок может добавится в слушатели, скорость выполнения O(N * M) где N машины, M игроки, это ОЧЕНЬ непроизводительный код, не продакшн уровня. Причём внутри самих циклов используются медленные indexOf, includes. Так же при отключении игрока он не удаляется со слушателей. Ещё прикол, итерация идёт по всем машинам, даже если звук есть у 1-2 машин, хранится serverSounds, но итерируемся мы по всем машинам, архитектурный абсурд. Я очень многое опускаю, выделяю основные моменты.

JavaScript:
var serverSounds = {};

// every 50ms update volume for all players in veh range
setInterval(function () {
    setVehPosition();
}, 50);

function setVehPosition() {
    mp.vehicles.forEach((veh) => {
        if (!(veh.id in serverSounds) || serverSounds[veh.id].paused) return;

        let maxRange = serverSounds[veh.id].range;

        serverSounds[veh.id].listeners.forEach(player => {
            let dist = veh.dist(player.position);

            if (dist > maxRange) {
                let idx = serverSounds[veh.id].listeners.indexOf(player);
                serverSounds[veh.id].listeners.splice(idx, 1);
                player.call('destroySound', [veh.id]);
            } else {
                let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
                volume = volume < 0 ? 0 : volume;
                player.call('setSoundVolume', [veh.id, volume * volume]);
            }
        });

        mp.players.forEachInRange(veh.position, maxRange, (player) => {
            if (serverSounds[veh.id].listeners.includes(player)) return;

            let dist = veh.dist(player.position);
            let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
            volume = volume < 0 ? 0 : volume;

            serverSounds[veh.id].listeners.push(player);
            player.call(
                'createSound',
                [JSON.stringify(serverSounds[veh.id]), volume * volume]
            );
        });

        if (serverSounds[veh.id].trackLength <= serverSounds[veh.id].startTime) {
            serverSounds[id].listeners.forEach(player => {
                player.call('destroySound', [id]);
            });
            delete serverSounds[id];
            return;
        }

        serverSounds[veh.id].startTime += 50;
    });
}

Ладно, идём дальше. Клиентская часть, тут вообще ад, код читать почти невозможно но я постарался.
Про полное отсутвие обработки ошибок и валидации уже говорить не нужно, это у автора в каждой системе.

Радиостанции объявлены ТРИ РАЗА в разных местах:
  • radioStation. js (строки 6-61)
  • cef/music_browser/index.html (строки 14-135)
  • Вероятно где-то на серверной стороне
Небезопасные HTTP потоки, автор явно не думает о безопасности своего проекта.
"http://ep128.hostingradio.ru: 8030/ep128",
"http://80.82.43.248:8000/shanson",

Безумные математические операции, посмотрите и попробуйте понять что тут происходит, такое даже бесплатный ChatGPT не выдаст.

JavaScript:
// index.js строки 24-33
let s = cam_vector.x*(car_pos.y-cam_pos.y) - cam_vector.y*(car_pos.x-cam_pos. x),
    a = 1;
if(s > 0) a = -1
else if(s < 0) a = 1
else a = 0;
let pan = Math.sqrt(1-(dx / dy).toFixed(3)*(dx / dy).toFixed(3))*a;

Тут явно видно что автор не знает о существовании промисов, за 160 тысяч как будто нужно было бы изучить асинхронное программирование в JS.

JavaScript:
// radioController.js - строки 48-56
for (let i = 0; i < 100 && radioStationName != stationName; i++) {
    mp.game.audio.setRadioToStationName(stationName);
    await mp.game.waitAsync(1);
}

Я бы мог ещё долго продолжать, но тут попросту нечего разбирать, общий уровень автора как разработчика был мне понятен ещё на северной части, тут я просто решил показать забавные моменты, указывающие на реальный уровень разработчика. Идём к заключению.

Глаза III - Заключение.

Если кто-то доверился мне и решил прочитать сразу заключение, вы ничего не потеряли и сэкономили своё время.
Потратив где-то час я могу прийти к выводу что данный разработчик находится на уровне Junior, не понимает основ и принципов программирования, абсолютно не разбирается в архитектуре backend приложений, ничего не слышал о high-load и оптимизации, и за 5 лет своей профессиональной/любительской деятельности не развился от слова совсем.
Крайне не рекомендую доверять ему сложную работу, все что вы получите в итоге - код который: невозможно масштабировать, неработоспособный в продакшене, нечитабельный и просто плохой. Так же ясное дело его резюме в данной теме абсолютно не соответствует реальности.

Автору же рекомендую не стоять на месте, более глубокого изучать программирование, больше практиковаться и нормально отнестись к критике.
 
Реакции: Vermilion и Valdemar

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147
Не смог пройти мимо, к сожалению для моего личного времени.
Что меня тут задержало? Вилка 160к, хвалебные отзывы, решаю углубится в твою профессиональную деятельность.

Если кому то интересно просто моё мнение и выводы на основе этого "Углубления", либо если кому то просто не интересны технические занудства, рекомендую сразу перейти к главе III.

Глава I - Portfolio ( YouTube )

Решаю поверхностно изучить работы автора, захожу на его первое актуальное видео, система автобусника. Достаточно примитивная система в качестве демонстрационной, но все же она одна из самых свежих и по этому показательных. Изучив видео в глаза сразу бросаются маркеры установленные на +1 по Z от земли, что как бы уже намекает на уровень реализации, далее видим как автобус подъезжает к первой остановке и наблюдаем самый спорный момент реализации системы разработчиком за 160.000 рублей в месяц, поведение NPC. Все дёргано, криво, если NPC не успевает дойти, его телепортирует в транспорт. Слишком очевидная последовательность действий, там просто поочередно вызываются таски у NPC, что выглядит очень топорно, причем даже такая реализация в лоб все равно каким то образом допускает то что NPC толкают друг друга. Сразу префаером предполагаю что никакой синхронизации нормальной там нет ( почему я так решил, узнаем в главе II ).

Изучил ещё пару видео, ничего интересного, или хотя бы сложного я там не увидел, все на уровне задач начинающего разработчика, по этому сразу перейдем к более интересной части этого разбора.

Глава II - GitHub.

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

rage-custom-weapon-damage

Ремарка. Я понимаю что система была написана 4 года назад, но автор 10 месяцев назад её актуализировал, по этому будем считать её свежей, даже если автор так не считает.
Так же далее будем смотреть динамику на более актуальных репах.

Демонстрация этой системы была также на YouTube по этому начнём с неё. Задумка системы простая, обеспечить возможность гибкой настройки урона оружия, переопределяя стандартный урон. Для реализации такой системы нужно обеспечить всего три основные вещи, возможность гибкой настройки, самое переопределение урона, а так же синхронизацию этого всего дела сервером для безопасности, звучит просто, разберём что мы увидели.

К сожалению автор по всей видимости на момент написания системы ещё не был знаком с TypeScript ( или не захотел внедрять в такую простую систему ), изучив остальные репозитория я не увидел примеров систем с TypeScript в целом, по этому далее на это внимания обращать не будем.

Первое что попалось в глаза, файл конфигурации системы. Файл вида JS object в котором присутствует несколько уровней вложенности, что уже как бы не совсем удобно для его конфигурации, но пик неудобства тут это то что ключ конфигурируемого оружия является хэшем оружия, а не его названием по типу "Pistol", думаю объяснять почему это очень неудобно объяснять не нужно, автору советую изучить тему маппинга для таких случаев. Разделение на конкретный хэш оружия и на группу оружия выглядит нормальным решением.

Идём в основной файл системы. defaultPercent - почему-то находится не в конфигурационном файле, что выглядит странно при его наличии.

Вся система находится в одном файле, что очень неудобно при масштабировании, автору советую делить код как минимум на два слоя, контроллер и бизнес логика, причём бизнес логику при необходимости делить так же на модули.

В методе encode мы видим throw new Error, который в дальнейшем при вызове этого метода нигде не обрабатывается, что является критической ошибкой при разработке любого уровня сложности системы, необработанные ошибки всего сложно читаемы, автору же советую использовать либо try catch при вызове методов которые могут дрогнуть ошибку, либо использовать mp.console.logError, что в этом кейсе более логично.

Очень много "magic numbers" в коде, по типу bondeIndex головы.

Почему то урон в голову у нас делится на 10, хотя в комментариях к коду автор вроде как хотел увеличить урон в голову, не совсем понятно.

Но это все мелочи, основной вопрос. Где синхронизация урона с сервером? Почему автор доверяет клиенту и предопределяет урон только на стороне клиента? По хорошему на клиенте мы должны были собирать информацию о выстреле на клиенте, после чего отправить эти данные на сервер для валидации этого урона и уже после этого отправлять на клиент новое состояние игрока ( HP ). Критический момент реализации.

rage-driftmode-freeroam / custom radio commit ( 10-5m ago )

Идём далее, к более интересному и свежему. У автора есть игровой мод с открытым исходным кодом, немного изучив репозиторий первое что кинулось в глаза - бинарники в гите, зачем? Непонятно. Никогда так не делайте, добавляйте бинарники в gitignore, если же там нужно специфическая версия билда либо указывайте её версию, либо заливайте билд отдельно.

Сосредоточимся на самом свежем что автор добавил в мод, систему костюмного радио, разберём сначала серверную часть.

Использование var считается устаревшей практикой, крайне рекомендую использовать let. Хотя далее автор все же использует let, не совсем понятно зачем использовать var в таком случае, если автор в курсе что существует let/const.

Теперь самое критичное, производительность кода и сама бизнес логика, это полный пиздец мягко говоря. Во первых - это совсем не читабельно и не масштабируемо, процедурный код без намёка на модульность, очень плохо. о производительности все ещё хуже, объясню кратко как работает его система, по сути есть какие то звуки которые должны проигрываться для машин, код написан так что каждые 50 ms ( 20~ раз в секунду ) код проходится по всем машинам на сервере, затем для каждого игрока на сервере идёт проверка находится ли он в слушателях, после чего игрок может добавится в слушатели, скорость выполнения O(N * M) где N машины, M игроки, это ОЧЕНЬ непроизводительный код, не продакшн уровня. Причём внутри самих циклов используются медленные indexOf, includes. Так же при отключении игрока он не удаляется со слушателей. Ещё прикол, итерация идёт по всем машинам, даже если звук есть у 1-2 машин, хранится serverSounds, но итерируемся мы по всем машинам, архитектурный абсурд. Я очень многое опускаю, выделяю основные моменты.

JavaScript:
var serverSounds = {};

// every 50ms update volume for all players in veh range
setInterval(function () {
    setVehPosition();
}, 50);

function setVehPosition() {
    mp.vehicles.forEach((veh) => {
        if (!(veh.id in serverSounds) || serverSounds[veh.id].paused) return;

        let maxRange = serverSounds[veh.id].range;

        serverSounds[veh.id].listeners.forEach(player => {
            let dist = veh.dist(player.position);

            if (dist > maxRange) {
                let idx = serverSounds[veh.id].listeners.indexOf(player);
                serverSounds[veh.id].listeners.splice(idx, 1);
                player.call('destroySound', [veh.id]);
            } else {
                let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
                volume = volume < 0 ? 0 : volume;
                player.call('setSoundVolume', [veh.id, volume * volume]);
            }
        });

        mp.players.forEachInRange(veh.position, maxRange, (player) => {
            if (serverSounds[veh.id].listeners.includes(player)) return;

            let dist = veh.dist(player.position);
            let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
            volume = volume < 0 ? 0 : volume;

            serverSounds[veh.id].listeners.push(player);
            player.call(
                'createSound',
                [JSON.stringify(serverSounds[veh.id]), volume * volume]
            );
        });

        if (serverSounds[veh.id].trackLength <= serverSounds[veh.id].startTime) {
            serverSounds[id].listeners.forEach(player => {
                player.call('destroySound', [id]);
            });
            delete serverSounds[id];
            return;
        }

        serverSounds[veh.id].startTime += 50;
    });
}

Ладно, идём дальше. Клиентская часть, тут вообще ад, код читать почти невозможно но я постарался.
Про полное отсутвие обработки ошибок и валидации уже говорить не нужно, это у автора в каждой системе.

Радиостанции объявлены ТРИ РАЗА в разных местах:
  • radioStation. js (строки 6-61)
  • cef/music_browser/index.html (строки 14-135)
  • Вероятно где-то на серверной стороне
Небезопасные HTTP потоки, автор явно не думает о безопасности своего проекта.
"http://ep128.hostingradio.ru: 8030/ep128",
"http://80.82.43.248:8000/shanson",

Безумные математические операции, посмотрите и попробуйте понять что тут происходит, такое даже бесплатный ChatGPT не выдаст.

JavaScript:
// index.js строки 24-33
let s = cam_vector.x*(car_pos.y-cam_pos.y) - cam_vector.y*(car_pos.x-cam_pos. x),
    a = 1;
if(s > 0) a = -1
else if(s < 0) a = 1
else a = 0;
let pan = Math.sqrt(1-(dx / dy).toFixed(3)*(dx / dy).toFixed(3))*a;

Тут явно видно что автор не знает о существовании промисов, за 160 тысяч как будто нужно было бы изучить асинхронное программирование в JS.

JavaScript:
// radioController.js - строки 48-56
for (let i = 0; i < 100 && radioStationName != stationName; i++) {
    mp.game.audio.setRadioToStationName(stationName);
    await mp.game.waitAsync(1);
}

Я бы мог ещё долго продолжать, но тут попросту нечего разбирать, общий уровень автора как разработчика был мне понятен ещё на северной части, тут я просто решил показать забавные моменты, указывающие на реальный уровень разработчика. Идём к заключению.

Глаза III - Заключение.

Если кто-то доверился мне и решил прочитать сразу заключение, вы ничего не потеряли и сэкономили своё время.
Потратив где-то час я могу прийти к выводу что данный разработчик находится на уровне Junior, не понимает основ и принципов программирования, абсолютно не разбирается в архитектуре backend приложений, ничего не слышал о high-load и оптимизации, и за 5 лет своей профессиональной/любительской деятельности не развился от слова совсем.
Крайне не рекомендую доверять ему сложную работу, все что вы получите в итоге - код который: невозможно масштабировать, неработоспособный в продакшене, нечитабельный и просто плохой. Так же ясное дело его резюме в данной теме абсолютно не соответствует реальности.

Автору же рекомендую не стоять на месте, более глубокого изучать программирование, больше практиковаться и нормально отнестись к критике.
Всё бы ничего, если бы вся критика не относилась к черновому, старому коду.

'rage-drift-mode' — это на самом деле якобы "полигон" поверх паблик-сборки от xday, в котором проводились лишь тесты, и нет продакш кода, отполированного кода.

Скрипт по урону, это вообще древняя ерунда, которая с тех и не поддерживается 😂
 
  • Durka
Реакции: MoonFusion

MoonFusion

Старожил
BackEnd developer
14 Июн 2021
392
262
149
Я намеренно взял твои относительно свежие коммиты, это тот код который ты писал не так давно. Особенно показателен код серверной части Custom Radio. И никакая «полировка» там не поможет, это очень плохой код, правда. Если у тебя есть что сказать, перед этим покажи какой то по твоему мнению актуальный «отполированный» код, потому что все что у тебя есть в открытом доступе в том числе из свежего подпадает под определение плохого кода.
 

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147
Я намеренно взял твои относительно свежие коммиты, это тот код который ты писал не так давно. Особенно показателен код серверной части Custom Radio. И никакая «полировка» там не поможет, это очень плохой код, правда. Если у тебя есть что сказать, перед этим покажи какой то по твоему мнению актуальный «отполированный» код, потому что все что у тебя есть в открытом доступе в том числе из свежего подпадает под определение плохого кода.
Код касаемо радио в паблик-гите это наброски, которые собраны изучая мод для сингла гта5, файвм скрипт, чттбы разобраться с нативками и воспроизведением звука в html.

Актуальный код в проекте MajorkaRp, который моментально воспроизводит радиостанцию без задержек и без использовании каких-либо библиотек для воспроизведения звука. Код чуть постарее в DsProject, с иным подходом к воспроизведению. Если хочешь почекать как работает, то на указанных серверах сможешь проверить. Правда с DsProject я ушел давно и не знаю оставили кастомрадио там или нет. Но вот на MajorkaRp точно должны быть.

На паблик открытого кода у меня нет. Мой продакшн код видели разработчики работавшие со мной вместе, к примеру @ncwdev, @enotit, @koltr.

Ты проделал душераздирающее разоблачение, но увы, потратил лишь свое время зря, повозившись в черновом, старом коде.

Если ты хотел оценить мою компетентность или хотел дать мне работу, то мог просто предложить оплачиваемое тестовое, в котором будет актуальный код, дабы отбросить сразу речи про "старый код" и на полной уверенности провести оценку.
 

MoonFusion

Старожил
BackEnd developer
14 Июн 2021
392
262
149
Код касаемо радио в паблик-гите это наброски, которые собраны изучая мод для сингла гта5, файвм скрипт, чттбы разобраться с нативками и воспроизведением звука в html.

Актуальный код в проекте MajorkaRp, который моментально воспроизводит радиостанцию без задержек и без использовании каких-либо библиотек для воспроизведения звука. Код чуть постарее в DsProject, с иным подходом к воспроизведению. Если хочешь почекать как работает, то на указанных серверах сможешь проверить. Правда с DsProject я ушел давно и не знаю оставили кастомрадио там или нет. Но вот на MajorkaRp точно должны быть.

На паблик открытого кода у меня нет. Мой продакшн код видели разработчики работавшие со мной вместе, к примеру @ncwdev, @enotit, @koltr.

Ты проделал душераздирающее разоблачение, но увы, потратил лишь свое время зря, повозившись в черновом, старом коде.

Если ты хотел оценить мою компетентность или хотел дать мне работу, то мог просто предложить оплачиваемое тестовое, в котором будет актуальный код, дабы отбросить сразу речи про "старый код" и на полной уверенности провести оценку.
Я думаю что работу я провел не зря, и она явно была в первую очередь направленна не на тебя, а на твоих потенциальных клиентов. Хотел ограничить пулл людей которых ты можешь ввести в заблуждение своим очень хорошо сочиненным резюме.
Ну и да, писать про «черновые» варианты «для тестов» — кринж полнейший, для каких бы целей ты это не писал это отображает твой уровень как разработчика, увы.
 

JJIGolem

Гений
High developer
BackEnd developer
19 Окт 2020
251
309
147
Я думаю что работу я провел не зря, и она явно была в первую очередь направленна не на тебя, а на твоих потенциальных клиентов. Хотел ограничить пулл людей которых ты можешь ввести в заблуждение своим очень хорошо сочиненным резюме.
Ну и да, писать про «черновые» варианты «для тестов» — кринж полнейший, для каких бы целей ты это не писал это отображает твой уровень как разработчика, увы.
Окей, спасибо за твою работу, умница.
 

enotit

Высший разум
High developer
BackEnd developer
13 Ноя 2020
1,820
611
187
22
Не смог пройти мимо, к сожалению для моего личного времени.
Что меня тут задержало? Вилка 160к, хвалебные отзывы, решаю углубится в твою профессиональную деятельность.

Если кому то интересно просто моё мнение и выводы на основе этого "Углубления", либо если кому то просто не интересны технические занудства, рекомендую сразу перейти к главе III.

Глава I - Portfolio ( YouTube )

Решаю поверхностно изучить работы автора, захожу на его первое актуальное видео, система автобусника. Достаточно примитивная система в качестве демонстрационной, но все же она одна из самых свежих и по этому показательных. Изучив видео в глаза сразу бросаются маркеры установленные на +1 по Z от земли, что как бы уже намекает на уровень реализации, далее видим как автобус подъезжает к первой остановке и наблюдаем самый спорный момент реализации системы разработчиком за 160.000 рублей в месяц, поведение NPC. Все дёргано, криво, если NPC не успевает дойти, его телепортирует в транспорт. Слишком очевидная последовательность действий, там просто поочередно вызываются таски у NPC, что выглядит очень топорно, причем даже такая реализация в лоб все равно каким то образом допускает то что NPC толкают друг друга. Сразу префаером предполагаю что никакой синхронизации нормальной там нет ( почему я так решил, узнаем в главе II ).

Изучил ещё пару видео, ничего интересного, или хотя бы сложного я там не увидел, все на уровне задач начинающего разработчика, по этому сразу перейдем к более интересной части этого разбора.

Глава II - GitHub.

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

rage-custom-weapon-damage

Ремарка. Я понимаю что система была написана 4 года назад, но автор 10 месяцев назад её актуализировал, по этому будем считать её свежей, даже если автор так не считает.
Так же далее будем смотреть динамику на более актуальных репах.

Демонстрация этой системы была также на YouTube по этому начнём с неё. Задумка системы простая, обеспечить возможность гибкой настройки урона оружия, переопределяя стандартный урон. Для реализации такой системы нужно обеспечить всего три основные вещи, возможность гибкой настройки, самое переопределение урона, а так же синхронизацию этого всего дела сервером для безопасности, звучит просто, разберём что мы увидели.

К сожалению автор по всей видимости на момент написания системы ещё не был знаком с TypeScript ( или не захотел внедрять в такую простую систему ), изучив остальные репозитория я не увидел примеров систем с TypeScript в целом, по этому далее на это внимания обращать не будем.

Первое что попалось в глаза, файл конфигурации системы. Файл вида JS object в котором присутствует несколько уровней вложенности, что уже как бы не совсем удобно для его конфигурации, но пик неудобства тут это то что ключ конфигурируемого оружия является хэшем оружия, а не его названием по типу "Pistol", думаю объяснять почему это очень неудобно объяснять не нужно, автору советую изучить тему маппинга для таких случаев. Разделение на конкретный хэш оружия и на группу оружия выглядит нормальным решением.

Идём в основной файл системы. defaultPercent - почему-то находится не в конфигурационном файле, что выглядит странно при его наличии.

Вся система находится в одном файле, что очень неудобно при масштабировании, автору советую делить код как минимум на два слоя, контроллер и бизнес логика, причём бизнес логику при необходимости делить так же на модули.

В методе encode мы видим throw new Error, который в дальнейшем при вызове этого метода нигде не обрабатывается, что является критической ошибкой при разработке любого уровня сложности системы, необработанные ошибки всего сложно читаемы, автору же советую использовать либо try catch при вызове методов которые могут дрогнуть ошибку, либо использовать mp.console.logError, что в этом кейсе более логично.

Очень много "magic numbers" в коде, по типу bondeIndex головы.

Почему то урон в голову у нас делится на 10, хотя в комментариях к коду автор вроде как хотел увеличить урон в голову, не совсем понятно.

Но это все мелочи, основной вопрос. Где синхронизация урона с сервером? Почему автор доверяет клиенту и предопределяет урон только на стороне клиента? По хорошему на клиенте мы должны были собирать информацию о выстреле на клиенте, после чего отправить эти данные на сервер для валидации этого урона и уже после этого отправлять на клиент новое состояние игрока ( HP ). Критический момент реализации.

rage-driftmode-freeroam / custom radio commit ( 10-5m ago )

Идём далее, к более интересному и свежему. У автора есть игровой мод с открытым исходным кодом, немного изучив репозиторий первое что кинулось в глаза - бинарники в гите, зачем? Непонятно. Никогда так не делайте, добавляйте бинарники в gitignore, если же там нужно специфическая версия билда либо указывайте её версию, либо заливайте билд отдельно.

Сосредоточимся на самом свежем что автор добавил в мод, систему костюмного радио, разберём сначала серверную часть.

Использование var считается устаревшей практикой, крайне рекомендую использовать let. Хотя далее автор все же использует let, не совсем понятно зачем использовать var в таком случае, если автор в курсе что существует let/const.

Теперь самое критичное, производительность кода и сама бизнес логика, это полный пиздец мягко говоря. Во первых - это совсем не читабельно и не масштабируемо, процедурный код без намёка на модульность, очень плохо. о производительности все ещё хуже, объясню кратко как работает его система, по сути есть какие то звуки которые должны проигрываться для машин, код написан так что каждые 50 ms ( 20~ раз в секунду ) код проходится по всем машинам на сервере, затем для каждого игрока на сервере идёт проверка находится ли он в слушателях, после чего игрок может добавится в слушатели, скорость выполнения O(N * M) где N машины, M игроки, это ОЧЕНЬ непроизводительный код, не продакшн уровня. Причём внутри самих циклов используются медленные indexOf, includes. Так же при отключении игрока он не удаляется со слушателей. Ещё прикол, итерация идёт по всем машинам, даже если звук есть у 1-2 машин, хранится serverSounds, но итерируемся мы по всем машинам, архитектурный абсурд. Я очень многое опускаю, выделяю основные моменты.

JavaScript:
var serverSounds = {};

// every 50ms update volume for all players in veh range
setInterval(function () {
    setVehPosition();
}, 50);

function setVehPosition() {
    mp.vehicles.forEach((veh) => {
        if (!(veh.id in serverSounds) || serverSounds[veh.id].paused) return;

        let maxRange = serverSounds[veh.id].range;

        serverSounds[veh.id].listeners.forEach(player => {
            let dist = veh.dist(player.position);

            if (dist > maxRange) {
                let idx = serverSounds[veh.id].listeners.indexOf(player);
                serverSounds[veh.id].listeners.splice(idx, 1);
                player.call('destroySound', [veh.id]);
            } else {
                let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
                volume = volume < 0 ? 0 : volume;
                player.call('setSoundVolume', [veh.id, volume * volume]);
            }
        });

        mp.players.forEachInRange(veh.position, maxRange, (player) => {
            if (serverSounds[veh.id].listeners.includes(player)) return;

            let dist = veh.dist(player.position);
            let volume = serverSounds[veh.id].volume * (1 - (dist / maxRange));
            volume = volume < 0 ? 0 : volume;

            serverSounds[veh.id].listeners.push(player);
            player.call(
                'createSound',
                [JSON.stringify(serverSounds[veh.id]), volume * volume]
            );
        });

        if (serverSounds[veh.id].trackLength <= serverSounds[veh.id].startTime) {
            serverSounds[id].listeners.forEach(player => {
                player.call('destroySound', [id]);
            });
            delete serverSounds[id];
            return;
        }

        serverSounds[veh.id].startTime += 50;
    });
}

Ладно, идём дальше. Клиентская часть, тут вообще ад, код читать почти невозможно но я постарался.
Про полное отсутвие обработки ошибок и валидации уже говорить не нужно, это у автора в каждой системе.

Радиостанции объявлены ТРИ РАЗА в разных местах:
  • radioStation. js (строки 6-61)
  • cef/music_browser/index.html (строки 14-135)
  • Вероятно где-то на серверной стороне
Небезопасные HTTP потоки, автор явно не думает о безопасности своего проекта.
"http://ep128.hostingradio.ru: 8030/ep128",
"http://80.82.43.248:8000/shanson",

Безумные математические операции, посмотрите и попробуйте понять что тут происходит, такое даже бесплатный ChatGPT не выдаст.

JavaScript:
// index.js строки 24-33
let s = cam_vector.x*(car_pos.y-cam_pos.y) - cam_vector.y*(car_pos.x-cam_pos. x),
    a = 1;
if(s > 0) a = -1
else if(s < 0) a = 1
else a = 0;
let pan = Math.sqrt(1-(dx / dy).toFixed(3)*(dx / dy).toFixed(3))*a;

Тут явно видно что автор не знает о существовании промисов, за 160 тысяч как будто нужно было бы изучить асинхронное программирование в JS.

JavaScript:
// radioController.js - строки 48-56
for (let i = 0; i < 100 && radioStationName != stationName; i++) {
    mp.game.audio.setRadioToStationName(stationName);
    await mp.game.waitAsync(1);
}

Я бы мог ещё долго продолжать, но тут попросту нечего разбирать, общий уровень автора как разработчика был мне понятен ещё на северной части, тут я просто решил показать забавные моменты, указывающие на реальный уровень разработчика. Идём к заключению.

Глаза III - Заключение.

Если кто-то доверился мне и решил прочитать сразу заключение, вы ничего не потеряли и сэкономили своё время.
Потратив где-то час я могу прийти к выводу что данный разработчик находится на уровне Junior, не понимает основ и принципов программирования, абсолютно не разбирается в архитектуре backend приложений, ничего не слышал о high-load и оптимизации, и за 5 лет своей профессиональной/любительской деятельности не развился от слова совсем.
Крайне не рекомендую доверять ему сложную работу, все что вы получите в итоге - код который: невозможно масштабировать, неработоспособный в продакшене, нечитабельный и просто плохой. Так же ясное дело его резюме в данной теме абсолютно не соответствует реальности.

Автору же рекомендую не стоять на месте, более глубокого изучать программирование, больше практиковаться и нормально отнестись к критике.
прикольно конечно докопаться до опенсурс кода, при чём некоторые системки (например, кастомный урон, а может только он и есть), являются единственным примером в интернетике.
Товарищ несколько лет работал под nda, дела до гитов нет. Мне, например, тоже не столь хочется трогать код в свободное время за бесплатно, есть ещё другие увлечения, личная жизнь. Писать огромную систему
Касаемо архитектуры в системах, а не сервиса / приложения. Ощущение, что ты кодишь максимально стерильно, что всё работает предвидено (особенно в rage). Основная же соль подобного - протестить гипотезу/поработать с механизмом. Если правильно выстроить механизмы в проекте, то всё подобное, что ты выкатил - должно быть в обёртке, а уже от этого плясать.
Очень много "magic numbers" в коде, по типу bondeIndex головы.

Почему то урон в голову у нас делится на 10, хотя в комментариях к коду автор вроде как хотел увеличить урон в голову, не совсем понятно.

Но это все мелочи, основной вопрос. Где синхронизация урона с сервером? Почему автор доверяет клиенту и предопределяет урон только на стороне клиента? По хорошему на клиенте мы должны были собирать информацию о выстреле на клиенте, после чего отправить эти данные на сервер для валидации этого урона и уже после этого отправлять на клиент новое состояние игрока ( HP ). Критический момент реализации.
Вот это хохма для людей, знающих чуть больше, чем вывести hello world на паскале. На нормальном проекте, всё подобное вынесено в модули, где и лежат конфиги с подобным.
Может и есть смысл ТСу показать что-то в опенсурс, но я очень надеюсь, что его перекупят быстрее и будет заниматься полезным.

И в конце:
находится на уровне Junior
системы разработчиком за 160.000 рублей в месяц,
а притензия тогда в чём? Джуны должны получать 40к?)) Ну давай так, что ты увидел только узенький глазок, приоткрытый разрабом и определить компетенции ты можешь только после ревью. Ибо в текущих реалиях определить роль мидла, то только так, насколько исполнитель может самостоятельно поддерживать, а уже сеньор - расширять. И понять это на уровне пары системок или опенсурс мода 5 летней давности - комично. И кой смысл этого?

Посмотри мой гит github.com/enotit )) у меня ставка больше 160к, там наверно столько токсинов будет) В остальном, любви и развития, с наступающим.
 
Реакции: JJIGolem

youngBeaver

Покинул форум.
BackEnd developer
24 Янв 2023
1,244
482
191
Ремарка. Я понимаю что система была написана 4 года назад, но автор 10 месяцев назад её актуализировал, по этому будем считать её свежей, даже если автор так не считает.
Так же далее будем смотреть динамику на более актуальных репах.
В чем логика? Он добавил 2 функции и 2 обработчика год назад, что не обязывает его рефакторить весь код репозитория. Никто не предъявляет Торвальдсу, что в коммите на прошлой недели он не рефакторил код добавленный в 2015 году коммитом (Возьми любой репозиторий и выйдет тоже самое).
прикольно конечно докопаться до опенсурс кода
А в чем смысл тогда вкладывать свои исходники, если не показывать свои навыки и не давать пищу для мозга другим? Как можно оценить градацию навыков специалиста по его исходному коду, когда всё это оправдывает "Ну это же опенсурс". Как будто тогда лучше вообще ничего не публиковать чем оправдывать "низкое качество" (p.s. Вообще не смотрел код ни одной системы Голема на гитхабе, сужу лишь по оценки MoonFusion и косвенного подтверждения его слов от enotit) на уровне "Скажите спасибо, что вообще выложил". И я не говорю о том, что код на гитхабе должен быть стерильно чистым, но хоть какие-то старания должны быть. Если твоих стараний не хватило по мнению кого-го ты либо соглашаешься с критикой, либо контр-аргументируешь условными цитатами из плюс минус известной литературы или блогов.

А так вообще Голем достаточно крутой разработчик поскольку у меня было с ним взаимодействие в рабочем процессе один раз минимум. Очевидно, что код пятилетний давности будет технически более сырым чем код разработчика на текущий момент.
 

sonnyk

Участник портала
26 Ноя 2022
100
15
73
Ощущение, что ты кодишь максимально стерильно
Это тут причём :ROFLMAO::ROFLMAO::ROFLMAO:
У чела коммит 5 месяцев назад, создал код, который несёт потенциальную опасность серверу. Включение такой системы, даже на сервере с 50 игроками уже будет пиздец и не надо ля-ля, что это код для ознакомления, на этот ознакомительный код и смотрят те, кто будет тебе платить бабки. Глупо говорить, вот это опенсурный код, а где-то там на проектах присутствует твоя готовая версия. Если показывать портфолио, то уже нормальный вариант, в портфолио тебя никто не гонит за сроками, если ты к своему портфолио относишься, как к говну... это печально
 
Последнее редактирование:

enotit

Высший разум
High developer
BackEnd developer
13 Ноя 2020
1,820
611
187
22
А в чем смысл тогда вкладывать свои исходники, если не показывать свои навыки и не давать пищу для мозга другим? Как можно оценить градацию навыков специалиста по его исходному коду, когда всё это оправдывает "Ну это же опенсурс". Как будто тогда лучше вообще ничего не публиковать чем оправдывать "низкое качество" (p.s. Вообще не смотрел код ни одной системы Голема на гитхабе, сужу лишь по оценки MoonFusion и косвенного подтверждения его слов от enotit) на уровне "Скажите спасибо, что вообще выложил". И я не говорю о том, что код на гитхабе должен быть стерильно чистым, но хоть какие-то старания должны быть. Если твоих стараний не хватило по мнению кого-го ты либо соглашаешься с критикой, либо контр-аргументируешь условными цитатами из плюс минус известной литературы или блогов.
Мне не нравится политика, что "либо отполируй, либо ничего", ибо именно в этот момент будет меньше примеров то как что с чем взаимодействует.
Сколько по собесам хожу / провожу, ну будто бы подзабили на это, мне кажется, крайний раз у меня лет 5 назад смотрели. Я также не смотрю, а кой смысл? Можно купить, можно с гпт нагенерить стерильной хероты. Предварительно спрашиваю какие-нибудь наработки, если человек может показать хоть что-то, то есть предмет общения.

Так то, я щас в магазин шёл и в голове мысль мелькнула, @MoonFusion красавчик, нормальный ревью, с нормальными претензиями, но критика в область навыков и материальной мотивации - груба и неуместна.


Это тут причём :ROFLMAO::ROFLMAO::ROFLMAO:
У чела коммит 5 месяцев назад, создал код, который несёт потенциальную опасность серверу. Включение такой системы, даже на сервере с 50 игроками уже будет пиздец и не надо ля-ля, что это код для ознакомления, на этот ознакомительный код и смотрят те, кто будет тебе платить бабки. Глупо говорить, вот это опенсурный код, а где-то там на проектах присутствует твоя готовая версия. Если показывать портфолио, то уже отполированный вариант, в портфолио тебя никто не гонит за сроками, если ты к своему портфолио относишься, как к говну... это печально
Дак ты слепо не включай то что в интернете лежит, если ты программист, то почитай. Ответственность Голема то при чём?
У меня пустое портфолио везде, во всех сферах, но заказы то есть, а времени полировать нет, увы, корреляция ясна?
 
Реакции: JJIGolem

Vermilion

Искусственный Интеллект
High developer
BackEnd developer
FrontEnd developer
29 Сен 2021
1,758
1,102
181
35
Я смотрю на свой код годовой давности и немного охуеваю, как такое вообще можно было писать :jer:
 
  • RoflanEbalo
Реакции: Inoi

sonnyk

Участник портала
26 Ноя 2022
100
15
73
Ответственность Голема то при чём?
По сути не в чём, ответственность будет, когда он похожую систему сделает для какого нибудь проекта, а потом на старте этого проекта, проект будет ложиться кирпичом
 

Similar threads