Skip to content

Общие принципы написания скриптов для программы RutonyChat

rutony edited this page Mar 29, 2024 · 9 revisions

Общая информация

В программе есть несколько мест где поддерживаются скрипты. В каждом из мест используются разные аргументы. Но общий принцип почти везде одиннаковый:

  • Бот
  • Удаленное управление
  • Кастомные метки
  • Автономные скрипты

Для скриптов используется кодировка UTF-8 без BOM

Шаблон для скриптов

Шаблон для отладки скриптов. Подойдет Visual Studio Community, Visual Studio Code, Xamarin Studio или другая среда разработки. Так же учитывайте, что в программе доступны некоторые компоненты по умолчанию, например, Newtonsoft json, поэтому он может быть добавлен в скрипте, и будет доступен при вызове скрипта. Но для тестов, его следует добавить в проект.

Список пакетов и библиотек доступных в программе:

  • CSScriptLibrary
  • Discord
  • HtmlAgilityPack
  • iTunesLib
  • KopiLua
  • NAudio
  • Newtonsoft.Json
  • NLua
  • OpenPop
  • SocketIoClientDotNet
  • SQLite-net
  • SuperSocket
  • TweetSharp
  • websocket-sharp
  • WebSocket4Net

Дополнительные методы

Все данные методы сделаны, что бы упростить однотипные действия в скриптах:

Все методы доступны в модуле RutonyBotFunctions

public static string GetScriptDirectory(string scriptname)

Получение каталога в котором размещен скрипт из Мастерской. Может быть полезен, если в скрипте используется какая то база, которая идет в комплекте, что бы получить относительный путь к ней из каталога Workshop.

public static bool FileHasString(string filename, string text)

Проверка наличия строки в текстовом файле.

public static void FileAddString(string filename, string text)

Добавить строку в текстовый файл.

public static void FileClear(string filename)

Очистить текстовый файл.

public static int FileLength(string filename)

Количество строк в текстовом файле.

public static string FileStringAt(string filename, int ind)

Строка из текстовая файла под номер ind.

Скрипты для бота

Для скриптов используется пространство имен - RutonyChat. Вызываемая функция имеет имя RunScript и заключена в класс Script. Аргументы:

  • site - имя сайта с которого был осуществлён вызов
  • username - имя вызвавшего пользователя
  • param - дополнительная информация для точной настройки скрипта пользователем

Важно. Запускаемый скрипт ничего не возвращает. Все вызовы по отсылке сообщений осуществляется методами:

RutonyBot.TwitchBot.Say(<string>); // чат твитча
RutonyBot.TwitchBot.SendCommand(<string>); // отправить команду в чат твитча
RutonyBot.GoodgameBot.Say(<string>); // чат гудгейма
RutonyBot.GoodgameBot.SendCommand(<string>); // отправить команду в чат гудгейма
RutonyBot.GoodgameBot.GetUserId(string username); // получить ID по нику
RutonyBot.GoodgameBot.SendBan(string username, string(int) seconds); // бан на гг
RutonyBot.YoutubeBot.Say(<string>); // чат ютуба
RutonyBot.SayToWindow(string _textParam); // сообщение в окно программы
RutonyBot.SayToWindow(string _textParam, Color color);
RutonyBot.SayToWindow(string _user, string _textParam);
RutonyBot.SayToWindow(string _user, string _textParam, Color color);
RutonyBot.BotSay(string text, List<ProgramProps.SiteEnum> targets); // отправка сообщения на список сайтов
RutonyBot.BotSay(string text, List<string> targets); // аналогично выше команде
RutonyBot.BotSay(string target, string text); // отправить сообщение на сайт target (универсальный метод, под любой сайт, пример, RutonyBot.BotSay("youtube", "123"); )

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

using System;
using System.Windows.Forms;      
namespace RutonyChat {
    public class Script {
        public void RunScript(string site, string username, string text, string param) {
            RutonyBot.TwitchBot.Say(string.Format("Param: {0}", param));
            /* Пример получения ранга пользователя и вывод его статистики
            RankControl.ChatterRank cr = RankControl.ListChatters.Find(r => r.Nickname == username);
            if (cr != null) {                    
                RutonyBot.TwitchBot.Say(
                    string.Format("{0} написал {1} сообщения(й)", username, cr.MessageQty)
                );
            }
            */
            // Вывод сообщения
            //MessageBox.Show("Это сообщение открыто из чата :D");
        }
    }
}

Скрипты для Удаленного управления

Для скриптов используется пространство имен - RutonyChat. Вызываемая функция имеет имя RunScript и заключена в класс Script. Аргументы:

  • username - имя вызвавшего пользователя, в случае триггеров по событию
  • param - дополнительная информация для точной настройки скрипта пользователем, в случае с донатом, там будет сумма

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

using System;
using System.Windows.Forms; 
     
namespace RutonyChat {
    public class Script {
        public void RunScript(string username, string param) {

             MessageBox.Show("Это сообщение открыто из чата :D");

        }
    }
}

Скрипты для кастомных меток

Для скриптов используется пространство имен - RutonyChat. Вызываемая функция имеет имя RunScript и заключена в класс Script. Аргументы:

  • param - дополнительная информация для точной настройки скрипта пользователем

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

using System;
using System.Windows.Forms; 
     
namespace RutonyChat {
    public class Script {
        public string RunScript(string param) {

        }
    }
}

Автономные скрипты

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

Примеры использования: Антикапс для чата (скрипт запоминает кто уже капсил и в следующий раз уже выдает бан вместо предупреждения), игра Травия (чаттеры отгадывают слова, если отгадали получают очки/баллы, можно посмотреть весь рейтинг, кто больше всего наотгадывал, база баллов сохраняется/загружается один раз), ну и другие примеры, их очень много.

using System;
using System.Threading;
     
namespace RutonyChat {
    public class Script {

        public void InitParams(string param) {
            RutonyBot.SayToWindow("Test script connected");
        }

        public void Closing() {
            RutonyBot.SayToWindow("Test script disconnected");
        }

        public void NewMessage(string site, string name, string text, bool system) {
            RutonyBot.SayToWindow(string.Format("site={0}, name={1}, text={2}", site, name, text));
        }
        public void NewMessageEx(string site, string name, string text, bool system, Dictionary<string, string> Params) {
        }

        public void NewAlert(string site, string typeEvent, string subplan, string name, string text, float donate, string currency, int qty) {
            RutonyBot.SayToWindow(string.Format("site={0} typeEvent={1}/{2}, name={3}, text={4}, donate={5}/{6}, qty={7}", 
                                                site, typeEvent, subplan, name, text, donate, currency, qty ));
        }
    }
}

Важно. Естественно такие скрипты так же поддерживают сложные параметры, поэтому у метода InitParams может быть перегрузка InitParams(Dictionary<string, string param).

NewMessageEx в Params, находятся дополнительные данные, например, id пользователя, является ли пользователь модератором и прочее.

Параметры для скриптов

Программа поддерживает 2 вида параметров: строкой и файлом описания параметров. В зависимости от параметров в скрипт при вызове передается либо строка, либо коллекция значений. Значения заполняются из пресета бота, либо кастомной метки. В зависимости от поддержки параметров скрипта, рядом с полем выбора скрипта будет либо текстовое поле, либо кнопка с вызовом окошка, где можно задать все параметры.

Параметры строкой

Не требуется дополнительно никаких настроек. В скрипт передается строковый параметр - param который содержит значение заполненное пользователем в программе. Далее уже скрипт сам волен делать и обрабатывать параметр как ему нужно.

Пример:

public void RunScript(string site, string username, string text, string param)

Файл описания параметров

Если в каталоге со скриптом лежит json файл с тем же именем, что и скрипт. То программа автоматически понимает что у скрипта есть описание параметров. Значение параметров, которые указал пользователь будет отдано в те же самые функции, с той лишь разницей что будет передан в скрипт не строковый параметр, а коллекция Dictionary<string, string>.

Пример: Есть скрипт testscript.cs и файл testscript.json. То будет использоваться перегрузка метода в

public void RunScript(string site, string username, string text, Dictionary<string, string> param)

Где ключи соответственно параметры, значения - значения.

Описание формата файла параметров

Формат аналогичен параметрам для тем оформлений. Пример использования - тема оформления - default-customs, файл params.json

// Структура файла параметров. Где массив параметры содержит описание параметров
{
  "params": [ ]    
}

// Цвет
    {
      "name": "NicknameColor",
      "desc": {
        "russian": "Цвет ника",
        "english": "Nickname color",
        "tchinese": "Nickname color"
      },
      "type": "color",
      "default": "#00A4F2"
    }

// Шрифт
{
      "name": "FontNickname",
      "desc": {
        "russian": "Шрифт никнейма",
        "english": "Font Nickname",
        "tchinese": "Font Nickname"
      },
      "type": "font",
      "default": {
		"name" : "Roboto",
		"size" : 16
	  }
    }

// Список
    {
      "name": "ShowEffect",
      "desc": {
        "russian": "Эффект появления сообщений",
        "english": "Show messages effect",
        "tchinese": "Show messages effect"
      },
      "type": "list",
      "default": "none",
      "enumerate": [
        {
          "value": "none"
        },	  
        {
          "value": "fadeIn"
        },
        {
          "value": "zoomIn"
        },
        {
          "value": "bounce"
        },
        {
          "value": "bounceInRight"
        },
        {
          "value": "bounceInLeft"
        },		
        {
          "value": "bounceIn"
        },
        {
          "value": "flipInX"
        },
        {
          "value": "flipInY"
        },
        {
          "value": "lightSpeedIn"
        },		
        {
          "value": "slideInRight"
        },	
        {
          "value": "slideInLeft"
        },			
      ]
    }

// Булево
    {
      "name": "HideMessages",
      "desc": {
        "russian": "Скрывать сообщения",
        "english": "Hide messages",
        "tchinese": "Hide messages"
      },
      "type": "bool",
      "default": false
    }

// Целое число со знаком
    {
      "name": "TimeNewMessages",
      "desc": {
        "russian": "Время показа сообщений",
        "english": "Time showing messages",
        "tchinese": "Time showing messages"
      },
      "type": "integer",
      "default": 10,
      "min":2,
      "max": 60
    }

// Вещественное число со знаком
{
      "name": "ShadowSize",
      "desc": {
        "russian": "Размер тени",
        "english": "Shadow size",
        "tchinese": "Shadow size"
      },
      "type": "float",
      "default": 1,
      "min": 1,
      "max": 100
    }

// Строка
    {
      "name": "StringExample",
      "desc": {
        "russian": "Пример строки (не используется)",
        "english": "String example (unabled)",
        "tchinese": "String example (unabled)"
      },
      "type": "string",
      "default": "Simple string text"
    }

Модуль Данные оповещений

Доступ к нему осуществаляется через ChatDB.ChatData и обращение к методам через ChatDB

Доступные коллекции

        public class FollowerClass {
            public int Index;
            public DateTime DT;
            public ProgramProps.SiteEnum Site;
            public string Name;
            public bool isTest = false;
        }
        public class SubscriberClass {
            public int Index;
            public DateTime DT;
            public ProgramProps.SiteEnum Site;
            public string Name;
            public string Text = "";
            public bool isTest = false;
        }
        public class DonateClass {
            public int Index;
            public DateTime DT;
            public ProgramProps.SiteEnum Site;
            public string Name;
            public float Sum;
            public string Currency;
            public string Text;
            public bool isTest = false;
        }
        public class DonateSumClass {
            public int Index;
            public ProgramProps.SiteEnum Site;
            public string Name;
            public float Sum;
            public string Currency;
            public bool isTest = false;
        }

        public class ChatDataClass {

            public List<FollowerClass> ListFollowers = new List<FollowerClass>();
            public List<SubscriberClass> ListSubscribers = new List<SubscriberClass>();
            public List<DonateClass> ListDonates = new List<DonateClass>();

            public List<DonateSumClass> ListDonateSum = new List<DonateSumClass>();

            public Dictionary<LabelBase.LabelType, int> ListCounters = new Dictionary<LabelBase.LabelType,int>();
        }

        public static ChatDataClass ChatData = new ChatDataClass();

Пример работы с меткой

Console.WriteLine(LabelBase.DictLabels[LabelBase.LabelType.Viewers_Youtube]);

LabelBase.DictLabels[LabelBase.LabelType.Viewers_Youtube].Params["QTY"] = qtyYT.ToString();
LabelBase.DictLabels[LabelBase.LabelType.Viewers_Youtube].Params["Like"] = intLike.ToString();
LabelBase.DictLabels[LabelBase.LabelType.Viewers_Youtube].Params["Dislike"] = intDislike.ToString();
LabelBase.DictLabels[LabelBase.LabelType.Viewers_Youtube].Save();

Работа с Рангами

Общий принцип

В программе есть база данных с рангами. Она храниться в файле /dataX/ranks.db в формате SQLite3 (программа для работы с базой DB Browser for SQLite). Программа использует файл базы SQLite3 только для первичной загрузки и сохранения данных в оперативную базу. Для оперативной же работы используется база RankControl.ListChatters. Итого есть 2 базы:

  • База SQLite3 (используюмая для хранения)
  • База RankControl.ListChatters(используюмая для оперативной работы, добавления, чтения, изменения)

Получается что работа вся происходит с RankControl.ListChatters, но для того что бы зафиксировать изменения нужно так же сделать изменения и в SQLite3 базе.

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

// База чаттеров, оперативная база, отсюда читаем ранги, вносим изменения, используется в первую очередь именно для чтения
RankControl.ListChatters<ChatterRank>

// Метод для обновления данных по чаттеру, по сути это список обьектов ChatterRank, которые в пакетном режиме вносятся в базу SQLite3, как есть возможность провести операцию
RankControl.ListUpdateSQL.Add(ChatterRank crItem);