• Из-за обновления 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) последний раз были обновлены:

Урок Управление сервером с помощью ботов / сайта

Cold

Участник портала
9 Окт 2022
46
22
46
И так господа, появилась потребность управлять сервером удалено, и я остановился на телеграмме, вообще суть этого метода не принципиальна откуда управлять, можно и с сайта и телеграмма и как угодно.

Результат чтобы не тратить ваше время зря:


Давайте начнем, создаем бота для телеграмма, бот у меня написан на Java, подключил я еще JDBC чтоб обращаться к базе данных игроков и так же обновлять им информацию, если с банами вопросов нет, все элементарно, человек написал /ban email days , мы распарсили и внесли изменения в БД в таблице users, то что делать если мы хотим что то более интересное, вызывать например создание машины, спавн конкретной вещи или еще какие то действия прям на сервере?
Код не лучший но думаю для гайда пойдет, главное смысл донести)

Тут нам на помощь приходит вторая таблица, создаем значит таблицу
Код:
create table public.commands_queue
(
    id           serial
        primary key,
    name_command varchar(255),
    arg1         varchar(255),
    arg2         varchar(255),
    arg3         integer,
    arg4         integer,
    finish       boolean default false,
    sender       varchar(255),
    time         varchar
);
Создаем сущность на серверсайде


Код:
public class commandsQueue
{
[Column("id")]
public int Id { get; set; }
[Column("name_command")]
public string NameCommand { get; set; }
[Column("arg1")]
public string Arg1 { get; set; }
[Column("arg2")]
public string Arg2 { get; set; }
[Column("arg3")]
public int Arg3 { get; set; }
[Column("arg4")]
public int Arg4 { get; set; }
[Column("finish")]
public bool Finish { get; set; }
[Column("sender")]
public string Sender { get; set; }
[Column("time")]
public string time { get; set; }
public commandsQueue()
    {
      
    }
}

Дальше нам понадобятся 2 класса для коннекта к БД) можете посмотреть гайды от Mip&Pesok, тот же код, от них брал

C#:
  public class CommandsConfiguration : IEntityTypeConfiguration <commandsQueue> 
    {
        public void Configure(EntityTypeBuilder<commandsQueue> builder)
        {
            try {
                builder.HasKey(x => x.Id);
            } catch (Exception e) {
                NAPI.Util.ConsoleOutput(DateTime.Now + $" Ошибка{e.Message} \n" +
                                        $" Сборка {e.Source} Stack: \n" + e.StackTrace);
            }
        }
    }


C#:
 public class DatabaseConCommands : DbContext
    {
        public DbSet<commandsQueue> commands_queue { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder OptionsBuilder)
        {
            try {
                var connString = new NpgsqlConnectionStringBuilder()
                {
                    Host = "localhost",
                    Port = 5432,
                    Database = "darkstar",
                    Username = "postgres",
                    Password = "postgres",
                    ConvertInfinityDateTime = true,
                    IncludeErrorDetails = true
                };

                OptionsBuilder.UseNpgsql(connString.ConnectionString)
                    .LogTo(str => Debug.WriteLine(str), new[] {RelationalEventId.CommandExecuted})
                    .EnableSensitiveDataLogging();
            } catch (Exception e) {
                NAPI.Util.ConsoleOutput(DateTime.Now + $" Ошибка{e.Message} \n" +
                                        $" Сборка {e.Source} Stack: \n" + e.StackTrace);
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            try {
                modelBuilder.ApplyConfiguration(new CommandsConfiguration());
            }
            catch (Exception e) {
                NAPI.Util.ConsoleOutput(DateTime.Now + $" Ошибка{e.Message} \n" +
                                        $" Сборка {e.Source} Stack: \n" + e.StackTrace);
            }
        }
    }
В нашем боте мы значит отправляем команду например /vehicle socialId hashName , он добавляет эту строку в БД, в игре сейчас мы будем считывать каждые например 5 секунд команду у которой finished = false, после проводим манипуляции че там надо, создать машину или телепортировать и затем finished = true, дабы второй раз не выполнилась данная команда и записываем изменения)



Код:
        [ServerEvent(Event.ResourceStart)]
        public async void OnResourceStart()
        {
            while (true)
            {
                await Task.Delay(5000);
                newCommand();
            }
        }


Код:
  public bool newCommand()
        {
            using (var db = new DatabaseConCommands())
            {
                commandsQueue? cmd = (commandsQueue) db.commands_queue.FirstOrDefault(x => x.Finish == false);
                if (cmd == null)
                {
                    return false;
                }
                switch (cmd.NameCommand)
                {
                    case "ban":
                        Console.WriteLine($"Player get ban social {cmd.Arg1} on day {cmd.Arg3} time send: {cmd.time} sender: {cmd.Sender}");
                        break;
                    case "kick":
                        Console.WriteLine($"Player was kicked");
                        break;
                    case "mute":
                        Console.WriteLine($"Player get mute social");
                        break;
                    case "vehicle":
                        var vPlayer = NAPI.Pools.GetAllPlayers()
                            .FirstOrDefault(x => x.SocialClubId == Decimal.Parse(cmd.Arg1));
                        if (vPlayer != null)
                        {
                           NAPI.Task.Run(() =>
                           {
                            var veh =NAPI.Vehicle.CreateVehicle(NAPI.Util.GetHashKey(cmd.Arg2), vPlayer.Position, 0, 255, 255,
                                "COLD");
                             vPlayer.SetIntoVehicle(veh.Handle, 0);
                             });
                        }
                        break;
                    case "give":
                        Console.WriteLine($"Player get item");
                        break;
                    case "teleport":
                        Console.WriteLine($"Player was teleported");
                        break;
                    default:
                        break;
                }
                cmd.Finish = true;
                db.SaveChanges();
                return true;
            }
        }
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
Код бы конечно подправить малёха, ну и ещё либо я не понял, либо так и есть, что в этом коде существует только логика усадки персонажа в созданную машину, а весь остальной функционал типа "напишите сами".
В любом случае информация кому-то может показаться полезной и помочь.
 
  • Haha
Реакции: MoonFusion

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Уровень мануала для этого форума в самый раз. Добавить скрипт в редагу и можно прям сидя на уроках баны раздавать.
 
  • RoflanEbalo
Реакции: m0v1l3, FireFeed и Cold

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
Уровень мануала для этого форума в самый раз. Добавить скрипт в редагу и можно прям сидя на уроках баны раздавать.
Лучше, чем то, что ты выложил за последние 3 года (то есть ровно 0 ресурсов).
Заебал токсичить, реально. Сходи проветрись что ли.
Продолжишь в таком темпе - будешь молча читать форум, ну либо вообще решишь сюда больше не заходить, что будет ещё лучше, ведь пользы от тебя здесь ровно 0.
Ведёшь себя как обиженная девочка, которой отказали все мальчики на районе. Тьфу, ей-Богу.
 

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Лучше, чем то, что ты выложил за последние 3 года (то есть ровно 0 ресурсов).
Не в обиду, но если ты продолжишь токсичить - сходишь посидеть в общем муте (намёк понят, я надеюсь).
Заебал токсичить, реально. Сходи проветрись что ли.
Продолжишь в таком темпе - будешь молча читать форум.
Где тут токсичность? К автору нет вопросов. Он красавчик. Или я в чем-то не прав?

А продолжишь общаться с людьми в таком тоне, будешь получать чапалахи (намек понят, я надеюсь).
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
Где тут токсичность? К автору нет вопросов. Он красавчик. Или я в чем-то не прав?

А продолжишь общаться с людьми в таком тоне, будешь получать чапалахи (намек понят, я надеюсь).
Угрозы IRL мы любим, ну так приезжай, заебёшь выебываться на форуме. Хоть бы 5% пользы для него сделал, чтобы так разговаривать, но форумным бойцам не до этого.
Если ты сам свою токсичность не понимаешь - я не стану тебе её разжёвывать, это должны были сделать твои родители: научить тебя манерам и каким-то обычным правилам нахождения в обществе, каком бы то ни было. Повторять не буду: увижу твоё подобное поведение в дальнейшем - попрощаемся, надоело читать подобную чепуху.
 

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Угрозы IRL мы любим, ну так приезжай, заебёшь выебываться на форуме. Хоть бы 5% пользы для него сделал, чтобы так разговаривать, но форумным бойцам не до этого.
Если ты сам свою токсичность не понимаешь - я не стану тебе её разжёвывать, это должны были сделать твои родители: научить тебя манерам и каким-то обычным правилам нахождения в обществе, каком бы то ни было. Повторять не буду: увижу твоё подобное поведение в дальнейшем - попрощаемся, надоело читать подобную чепуху.
Да какие угрозы, кому ты нужен) Я тебе в принципе говорю, что если ты так общаешься по жизни, то будь готов, что у оппонента с четкостью все в порядке.
А проблема с токсичностью не решится, пока ты не снимешь сам себе high developer (ведь ты не он). Новый акк 2 секунды регать)
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
Да какие угрозы, кому ты нужен) Я тебе в принципе говорю, что если ты так общаешься по жизни, то будь готов, что у оппонента с четкостью все в порядке.
А проблема с токсичностью не решится, пока ты не снимешь сам себе high developer (ведь ты не он). Новый акк 2 секунды регать)
Дак сиди регай новые акки, если тебе делать нечего по жизни и это всё, чем ты занимаешься, кто ж против. Пока люди работают и зарабатывают деньги на свою жизнь - ты будешь форуму реги набивать, ну не прекрасно ли.
Главное, чтоб за твои негативные действия следовало наказание, а не безнаказанность, которой ты пользуешься последние несколько лет.
Моё дело предупредить. Хорошего вечера!
 

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Дак сиди регай новые акки, если тебе делать нечего по жизни и это всё, чем ты занимаешься, кто ж против. Пока люди работают и зарабатывают деньги на свою жизнь - ты будешь форуму реги набивать, ну не прекрасно ли.
Главное, чтоб за твои негативные действия следовало наказание, а не безнаказанность, которой ты пользуешься последние несколько лет.
Моё дело предупредить. Хорошего вечера!
А чем отличается твоё набивание постов от моих? Контекстом? Че не работаешь, не зарабатываешь деньги, а тупо форуму посты набиваешь?
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
А чем отличается твоё набивание постов от моих? Контекстом? Че не работаешь, не зарабатываешь деньги, а тупо форуму посты набиваешь?
Это опять превращается во флуд в теме, которая к этому не относится, но раз ты всегда хочешь быть в бочке затычкой - пожалуйста, на следующее твоё сообщение ответа от меня не последует.

Отличаемся мы как минимум тем, что 95% твоих сообщений имеют негативный (токсичный) подтекст к абсолютно любому событию, происходящему на форуме.
У тебя либо действительно какое-то когнитивное искажение восприятия реальности, либо почему ты не можешь увидеть очевидного - я не понимаю.
Да и не сильно хочу понимать, честно говоря, я не твой родитель, не твой близкий друг - мне всё равно почему ты так всё воспринимаешь, у себя дома хоть под себя ходи, если тебе так удобно, но вот когда ты приходишь в место, где помимо тебя есть ещё другие люди - учитывай то, что тебе нужно считаться и с другими, есть просто правила нахождения в обществе, которые, опять же, тебе должны были привить твои прекрасные родители (и я без сарказма, за родителей никогда плохого не скажу). Если не привили или ты их почему-то не хочешь воспринимать, то это не значит, что все вокруг должны страдать из-за этого и выслушивать то, как ты привык действовать где-то там. Как говорится "в чужой монастырь со своим уставом не ходят". Я всё сказал. Повторно и уже в последний раз желаю тебе прекрасного вечера.
 
Реакции: ivancrossme

MaltrzD

Участник портала
30 Сен 2024
6
6
18
Мужики, я тут новенький пока, но зачем бд и тд?

Можно одним методом заменить бд:
C#:
    private static async Task GetUpdatesAsync()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetStringAsync("https://api.telegram.org/botTOKEN/" + "getUpdates");


        }
    }
Можно все перекешировать 100 раз, и так же вызывать проверку обновлений каждые 5 секунд.
 
Реакции: Cold и UchihaMadara

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Мужики, я тут новенький пока, но зачем бд и тд?

Можно одним методом заменить бд:
C#:
    private static async Task GetUpdatesAsync()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetStringAsync("https://api.telegram.org/botTOKEN/" + "getUpdates");


        }
    }
Можно все перекешировать 100 раз, и так же вызывать проверку обновлений каждые 5 секунд.
В целом лучшее решения для простых оповещений. Но если система сложная, то такое не подойдет. Не подойдет даже вариант автора.
 
Реакции: Cold

MaltrzD

Участник портала
30 Сен 2024
6
6
18
В целом лучшее решения для простых оповещений. Но если система сложная, то такое не подойдет. Не подойдет даже вариант автора.
Как не подойдет то, можно подключить .net telegram (название не помню), или реализовать под свои нужды работу с телеграм апи.
Из этого можно сделать абсолютно что угодно
 
Реакции: Cold

Cold

Участник портала
9 Окт 2022
46
22
46
Код бы конечно подправить малёха, ну и ещё либо я не понял, либо так и есть, что в этом коде существует только логика усадки персонажа в созданную машину, а весь остальной функционал типа "напишите сами".
В любом случае информация кому-то может показаться полезной и помочь.
А смысл мне было писать бы систему мута, бана, выдачу вещей? У меня своя сборка и людям бы это не подошло, а на примере машины можно сделать и тот же кик игрока с помощью NAPI.Pools получил игрока, если не null то кикнул, тоже самое с телепортом.

В этом гайде самое важное это я показал каким образом можно отправлять команды, или есть проблема написать ТГ бота? Сейчас каждый школьник на петухоне его сделает за 2 минуты, поэтому не стал растягивать статью
Поэтому странная претензия
 

Cold

Участник портала
9 Окт 2022
46
22
46
Мужики, я тут новенький пока, но зачем бд и тд?

Можно одним методом заменить бд:
C#:
    private static async Task GetUpdatesAsync()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetStringAsync("https://api.telegram.org/botTOKEN/" + "getUpdates");


        }
    }
Можно все перекешировать 100 раз, и так же вызывать проверку обновлений каждые 5 секунд.
Не знаю за этот метод но попробую) спасибо
 

UchihaMadara

Старожил
FrontEnd developer
27 Окт 2020
568
211
121
Как не подойдет то, можно подключить .net telegram (название не помню), или реализовать под свои нужды работу с телеграм апи.
Из этого можно сделать абсолютно что угодно
Так если рассматривать, сервер пингует бота на наличие обновлений. То есть здесь и долгий отклик, и пинг впустую. Ещё и команды как-то конфирмить нужно. В варианте автора - их можно конфирмить через БД.

Я бы предпочел вариант, когда именно бот обращается к серверу, а не наоборот. Так намного проще скейлить систему. Можно использовать тот же gRPC.
 
Реакции: JJIGolem и Vermilion

Vermilion

Высший разум
High developer
BackEnd developer
FrontEnd developer
29 Сен 2021
1,285
756
181
34
Отвыкайте от этих таймеров и интервалов. Что за дурная привычка.
 

MaltrzD

Участник портала
30 Сен 2024
6
6
18
А про реализацию саму, можем добавить немножечко рефлексии, и сделать все удобно.
Делал когда то такое для себя, показал в консольном приложении:

C#:
public static class Program
{
    private static CommandExecutor executor = new CommandExecutor();
    public static async Task Main()
    {
        // что то типа команд с тг
        executor.ExecuteCommand("vehicle 1 aboba");
        executor.ExecuteCommand("respawn_cars");
    }

    [CommandHandler("vehicle")]
    private static void SpawnVehicle(int socialId, string hash)
    {
        Console.WriteLine($"{socialId} | {hash}");
    }

    [CommandHandler("respawn_cars")]
    private static void RespawnCars()
    {
        Console.WriteLine("Машины успешно зареспавнены!");
    }
}

C#:
    public class CommandExecutor
    {
        public string ExecuteCommand(string command)
        {
            var parts = command.Split(' ');
            var cmd = parts[0];

            foreach (var method in GetMethodsWithCommandAttribute())
            {
                var attribute = method.GetCustomAttribute<CommandHandlerAttribute>();
                if (attribute != null && attribute.Command == cmd)
                {
                    method.Invoke(null, ConvertParameters(method, parts.Skip(1).ToArray()));
                    return "успэх";
                }
            }

            return $"Команды с именем: {cmd} не найдена!";
        }
        private object[] ConvertParameters(MethodInfo method, string[] parameters)
        {
            var methodParameters = method.GetParameters();
            var result = new object[methodParameters.Length];

            for (int i = 0; i < methodParameters.Length; i++)
            {
                var paramType = methodParameters[i].ParameterType;

                if (paramType == typeof(int))
                {
                    result[i] = int.Parse(parameters[i]);
                }
                else if(paramType == typeof(string))
                {
                    result[i] = parameters[i];
                }
            }

            return result;
        }
        private IEnumerable<MethodInfo> GetMethodsWithCommandAttribute()
        {
            foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
            {
                foreach (var method in
                    type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
                {
                    if (method.GetCustomAttribute<CommandHandlerAttribute>() != null)
                    {
                        yield return method;
                    }
                }
            }
        }
    }

C#:
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class CommandHandlerAttribute : Attribute
{
    public string Command { get; }

    public CommandHandlerAttribute(string command)
    {
        Command = command;
    }
}

Атрибут можно повесить на любой метод, будет работать во всей сборке

И получаем это:
1738188956514.png
 
Последнее редактирование:
Реакции: Cold и XDeveluxe

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,771
1,577
211
28
А про реализацию самому, можем добавить немножечко рефлексии, и сделать все удобно.
Делал когда то такое для себя, показал в консольном приложении:

C#:
public static class Program
{
    private static CommandExecutor executor = new CommandExecutor();
    public static async Task Main()
    {
        // что то типа команд с тг
        executor.ExecuteCommand("vehicle 1 aboba");
        executor.ExecuteCommand("respawn_cars");
    }

    [CommandHandler("vehicle")]
    private static void SpawnVehicle(int socialId, string hash)
    {
        Console.WriteLine($"{socialId} | {hash}");
    }

    [CommandHandler("respawn_cars")]
    private static void RespawnCars()
    {
        Console.WriteLine("Машины успешно зареспавнены!");
    }
}

C#:
    public class CommandExecutor
    {
        public string ExecuteCommand(string command)
        {
            var parts = command.Split(' ');
            var cmd = parts[0];

            foreach (var method in GetMethodsWithCommandAttribute())
            {
                var attribute = method.GetCustomAttribute<CommandHandlerAttribute>();
                if (attribute != null && attribute.Command == cmd)
                {
                    method.Invoke(null, ConvertParameters(method, parts.Skip(1).ToArray()));
                    return "успэх";
                }
            }

            return $"Команды с именем: {cmd} не найдена!";
        }
        private object[] ConvertParameters(MethodInfo method, string[] parameters)
        {
            var methodParameters = method.GetParameters();
            var result = new object[methodParameters.Length];

            for (int i = 0; i < methodParameters.Length; i++)
            {
                var paramType = methodParameters[i].ParameterType;

                if (paramType == typeof(int))
                {
                    result[i] = int.Parse(parameters[i]);
                }
                else if(paramType == typeof(string))
                {
                    result[i] = parameters[i];
                }
            }

            return result;
        }
        private IEnumerable<MethodInfo> GetMethodsWithCommandAttribute()
        {
            foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
            {
                foreach (var method in
                    type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
                {
                    if (method.GetCustomAttribute<CommandHandlerAttribute>() != null)
                    {
                        yield return method;
                    }
                }
            }
        }
    }

C#:
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class CommandHandlerAttribute : Attribute
{
    public string Command { get; }

    public CommandHandlerAttribute(string command)
    {
        Command = command;
    }
}


И получаем это:
Посмотреть вложение 18282
Хороший вариант, но стоит учесть ещё GreedyArg для команд с типом данных string, где потенциально пробел может быть как часть текста сообщения.