• Из-за обновления GTA 5 (был добавлен новый патч) может временно не работать вход в 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/ru/newswire/
    Статус всех служб для Rockstar Games Launcher и поддерживаемых игр: https://support.rockstargames.com/ru/servicestatus


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

Мануал Простая система эффектов C# Back-End

DaVilka

Гуру
Автор темы
16 Сен 2020
601
228
108
Эта система нужна для того что бы легко создавать и использовать у себя в сборке различные эффекты(бафы/дебафы/различные пассивные эффекты).
В мода гта как и в других играх часто используются различные эффекты, но реализовываются они обычно
непосредственно в самих функциях(там где это видел я), на пример когда вы ложитесь в лечебную койку или жрете бургер
вам постепенно восстанавливается здоровье, не смотря на то что это один и тот же эффект реализуются они в разных местах дублируя друг друга.

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

int Duration - Время действия эффекта
uint UpdateRate - Частота обновления
bool IsDublicable - Можно ли наложить несколько копий эффекта(не работает вместе с IsUpdatable)
bool IsUpdatable - Можно ли обновить эффект при повторном использовании(не работает вместе с IsDublicable )
bool IsCancelable - Может ли игрок отменить его

Сам класс эффекта должен реализовать три абстрактные функции
public abstract bool Set(Player player); - Вызывается при наложении эффекта
public abstract bool Update(Player player); - Вызывается при работе эффекта
public abstract void End(Player player); - Вызывается при завершении работы эффекта

Дополнительно, если Duration равен нулю, то эффект работает бесконечно, пока не отменят из вне, а если -1 то эффект накладывается но не обновляется
так можно реализовывать эффекты которые выполнять определенное действие единожды, и отменятся из вне при определенных условия, на пример
у вас есть зеленая зона, при входе в ЗЗ вы просто накладываете неуязвимость, а при выходе отменяете его.

Пример реализации эффекта восстановления хп

C#:
namespace HardLife.Core.Effects
{
    //Duration 10000 означает что эффект будет длится 10 секунд
    //IsDublicable false значит что его нельзя наложить несколько раз
    //UpdateRate 1000 значит что функция Update будет вызыватся каждую секунду на протяжении Duration(10 сек)
    [Effect(Id = 0, Name = "Heal", Duration = 10000, UpdateRate = 1000, IsDublicable = false)]
    public class FoodHealEffect : Effect
    {
        //Вызывается при наложении эффекта
        //возвращает bool, наложение эффекта можно отменить вернув false
        //так как на пример нету смысла накладывать эффект восстановления хп
        //если хп полное
        public override bool Set(Player player)
        {
            Console.WriteLine($"Sets effect: {Name}");
            if(player.Health >= 100) return false;
            return true;
        }
        //Вызывается при завершении работы эффекта
        public override void End(Player player)
        {
            Console.WriteLine($"End effect: {Name}");
        }
        //Если вернуть false, то еффект прекратит действовать
        //в данной функции false возвращается когда hp игрока полное
        public override bool Update(Player player)
        {
            bool status = true;
            if (player.Health + 3 > 100) { player.Health = 100; status = false; }
            else player.Health += 3;
            Console.WriteLine($"Name {player.Name}, Heal: {player.Health}");
            return status;
        }
    }
}

Исходный код: EffectManager

P.S. Система не тестировалась, так что могут быть проблемы, если кто что то заменить - пишите в теме(если она кому-то вообще будет нужна)
 

JJIGolem

Гуру
high coder
19 Окт 2020
215
274
142
IsUpdatable, IsCancelable и прочее можно было бы перевести либо в интерфейсы, либо в enum с [Flags].Сложно будет в будущем, если появятся новые флаги, каждый раз в конструктор, в аттрибут, в интерфейс запихивать новые параметры. То есть, чтобы добавить новый параметр, нам необходимо в трех местах сделать правки.. А вдруг я забуду в конструкторе это сделать? Или разрешать конфликтные ситуации между флагами для всех эффектов.

Скорее всего, я бы лучше избавился от аттрибута эффекта и от абстрактного класса. Оставил бы начальный IEffect
C#:
interface IEffect
{
    public int Id { get; set; }
    public string Name { get; }

    bool Set(Player player);
    bool Update(Player player);
    void End(Player player);
}

Идея с Id эффекта для каждого класса сомнительна, так как придете вы через месяц создать новый эффект и ищи теперь какой ID не занят.

Плюс без всяких каких-либо на это ограничений мы можем вызвать Set напрямую у эффекта, минируя ValidateSet (это как я понял что-то типа TrySet)
Также зачем нам ValidateSet делать async Task, если мы его нигде не используем для этого? В самом ValidateSet авейтим создаваемый таск, но зачем?

Используйте обычный Task.Run вместо Task.Factory.StartNew, это хоть и сахар, но зачем нам фабрика, если её не настраиваем?

Не городите else там, где его можно избежать.
C#:
if (effectData != null && !IsDublicable)
{
    if (IsUpdatable)
        effectData.CancelToken.CancelAfter(TimeSpan.FromMilliseconds(Duration));
}
//эффекта нет или он может дублироваться, накладываем новый
else
{
    //...
    
    
// Можно же использовать return
if (effectData != null && !IsDublicable)
{
    if (IsUpdatable)
        effectData.CancelToken.CancelAfter(TimeSpan.FromMilliseconds(Duration));
    return;
}
//эффекта нет или он может дублироваться, накладываем новый
// ...

То, что говорил в самом начале, мы пришли к тому, что нам необходимо для IsUpdatable необходимо проверить, что ещё и IsDublicable стоит на false. Если IsUpdatable имеет приоритет над IsDublicable, то проверка на IsDublicable вовсе и не нужна, не так ли?

Может, я где-то и не прав, или вы посчитаете, что указал на несущественные вещи. Логика всего детища сложна как и для чтения, так и для расширения.
Заметьте, я ни слова не сказал про автора и про его личность. Поэтому нравоучений не надо )
Я полагаю, автор адекватно относится к критике.
 
  • Wow
Реакции: Inoi

DaVilka

Гуру
Автор темы
16 Сен 2020
601
228
108
Сложно будет в будущем, если появятся новые флаги, каждый раз в конструктор, в аттрибут, в интерфейс запихивать новые параметры. То есть, чтобы добавить новый параметр, нам необходимо в трех местах сделать правки.. А вдруг я забуду в конструкторе это сделать? Или разрешать конфликтные ситуации между флагами для всех эффектов.
Расчет был на то что тут не нужно будет добавлять новые параметры. А какие еще можно добавить?
Плюс без всяких каких-либо на это ограничений мы можем вызвать Set напрямую у эффекта, минируя ValidateSet (это как я понял что-то типа TrySet)
Тут согласен, но это решается просто сменой модификатора доступа
Также зачем нам ValidateSet делать async Task, если мы его нигде не используем для этого? В самом ValidateSet авейтим создаваемый таск, но зачем?
Работает же, остальное исправимо.
Используйте обычный Task.Run вместо Task.Factory.StartNew, это хоть и сахар, но зачем нам фабрика, если её не настраиваем?
Я не виноват, виноват ctrl+c/ctrl+v
То, что говорил в самом начале, мы пришли к тому, что нам необходимо для IsUpdatable необходимо проверить, что ещё и IsDublicable стоит на false. Если IsUpdatable имеет приоритет над IsDublicable, то проверка на IsDublicable вовсе и не нужна, не так ли?
Смысл был. Просто он не до конца реализован. тут будут серьезные правки.

Идея с Id эффекта для каждого класса сомнительна, так как придете вы через месяц создать новый эффект и ищи теперь какой ID не занят.
Id какраз таки можно перевести в enum, смысла использования айди в каждом классе заключается в том что удаление класса эффекта на лайве выльется еще в больший геморой

Скорее всего, я бы лучше избавился от аттрибута эффекта и от абстрактного класса. Оставил бы начальный IEffect
Аттрибут тут для красоты, мне показалось прикольней и понятней реализовать нужные параметры через аттрибут
и избавляться от него как и от абстрактного класса я точно не буду так как это в корне меняет подход к реализации,
а избавлюсь я какраз таки от интерфейса и запилю все через атрибут что бы параметры менялись только в 1 месте
п.с. Скорее всего, ты бы нагородил кучу статических методов и бесполезных списков, я че не видел твою сборку?:roflanebalo: (шутка)
 
Последнее редактирование:
  • RoflanEbalo
Реакции: Inoi

Inoi

/dev/null
VIP
15 Окт 2020
2,320
1,382
208
34
  • Like
Реакции: DaVilka

DaVilka

Гуру
Автор темы
16 Сен 2020
601
228
108
И так, первый же человек который удосужился хоть взглянуть на исходник обнаружил несколько недочетов,
по этому я внес некоторые изменения в скрипт.

1. Функции Set/Update/End получили модификатор доступа protected, что не позволит к ним обращаться из вне.
2. Был удален интерфейс IEffect, что исключило необходимость несколько раз дублировать одни и те же переменные /почему я до этого раньше не додумался:unsure:/(не обязательное исключение - вывел для удобства несколько геттеров из класса Effect)
3. Добавлено две приватные функции CreateEffect и CreateUpdateTask тем самым разгрузив функцию ValidateSet, что сделало код гораздо проще для понимания и редактирования
4. Заменил Task.Factory.StartNew на Task.Run, я так понял таски это что то сакральное на этом форуме
5. IsDublicable и IsUpdatable проверяются на истину в конструкторе, если оба true то эффект не создается и выдает ошибку, не в угоду приоритету. Смысл - показать что эффект не будет работать как задумано и его нужно править