-
Notifications
You must be signed in to change notification settings - Fork 2
Общие принципы написания скриптов для программы RutonyChat
В программе есть несколько мест где поддерживаются скрипты. В каждом из мест используются разные аргументы. Но общий принцип почти везде одиннаковый:
- Бот
- Удаленное управление
- Кастомные метки
- Автономные скрипты
Для скриптов используется кодировка 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);