Repository navigation
RU UO Topic files json data
Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
Главная · C# · IDE · UO API · A–Z · Примеры · Языки
Файлы, JSON, массивы и коллекции C#, а также совместимые помощники UO. Встроенные функции C# записываются без UO.
| Тема | Команды и пояснения |
|---|---|
| File | C# и стандартная библиотека |
| JSON Parse | C# и стандартная библиотека |
| JSON Load | C# и стандартная библиотека)) |
| JSON Save | C# и стандартная библиотека |
| JSON Stringify | C# и стандартная библиотека |
| List | C# и стандартная библиотека |
| Dictionary | C# и стандартная библиотека |
| Arrays | C# и стандартная библиотека · C# и стандартная библиотека |
| MemoryStream | C# и стандартная библиотека |
UO.GetArrayLength · UO.GetWord · UO.GetWordCount
C# и стандартная библиотека · C# и стандартная библиотека · C# и стандартная библиотека
В каждой карточке команды есть несколько самостоятельных сценариев: прямой код, функции и классы. Ниже приведены отдельные короткие сценарии; ограничения и полный разбор находятся в карточках.
Параметры, результат и все сценарии
dynamic[] amounts = new dynamic[checked((int)(2) + 1)];
amounts[0] = 50;
amounts[1] = 75;
amounts[2] = 25;
var total = 0;
for (int index = (int)(0); index <= UO.GetArrayLength(amounts) - 1; index += (int)(1))
{
total += amounts[index];
}
return total;Параметры, результат и все сценарии
return ReadX("move 1445 1690");
dynamic ReadX(dynamic text)
{
if (Truth(UO.GetWordCount(text) != 3))
{
return -1;
}
if (Truth(UO.GetWord(text, 0) != "move"))
{
return -1;
}
var xText = UO.GetWord(text, 1);
if (!(Truth(IsNumeric(xText))))
{
return -1;
}
var x = Convert.ToDouble(xText);
if (Truth(Convert.ToString(x) == "NaN") || Truth(x < 0) || Truth(x > 65535))
{
return -1;
}
if (Truth(x != Math.Truncate(x)))
{
return -1;
}
return Convert.ToInt32(x);
}
bool IsNumeric(object? value) => double.TryParse(Convert.ToString(value), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _);
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
dynamic UO.GetArrayLength(object? arg);Считает непосредственные ячейки массива для ограниченного перебора и безопасного чтения индекса.
int >= 0. Пустой Array и значение другого вида дают 0: только по результату нельзя проверить тип. Это количество, а не bool и не последний индекс.
- Локальная проверка: не отправляет запрос серверу, не перемещает предметы и не изменяет массив. В примерах заданы учебные данные, а не живой инвентарь.
- Проверяет вид значения и читает Array.Length без обхода и суммирования. объявление переменной values(2) создаёт три ячейки, индексы 0..2, включая незаполненные.
- Вложенные элементы рекурсивно не считаются. Для строки есть Len, для List/Dictionary — их Count. UO.GetArrayLength — совместимое имя той же локальной проверки.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
object? result = UO.GetArrayLength(new[] { 10, 20, 30 });
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));Параметры и ход выполнения:
- объявление переменной amounts(2) создаёт три записи. Цикл обходит индексы 0..2 и возвращает 150. Количества складывает цикл, а не ArrayLength.
- Локальная проверка: не отправляет запрос серверу, не перемещает предметы и не изменяет массив. В примерах заданы учебные данные, а не живой инвентарь.
dynamic[] amounts = new dynamic[checked((int)(2) + 1)];
amounts[0] = 50;
amounts[1] = 75;
amounts[2] = 25;
var total = 0;
for (int index = (int)(0); index <= UO.GetArrayLength(amounts) - 1; index += (int)(1))
{
total += amounts[index];
}
return total;Параметры и ход выполнения:
- В route две точки Array, в каждой по три ячейки координат. Результат 2|3, а не шесть. Персонаж не движется.
- Локальная проверка: не отправляет запрос серверу, не перемещает предметы и не изменяет массив. В примерах заданы учебные данные, а не живой инвентарь.
return RunScenario();
object? RunScenario()
{
dynamic[] first = new dynamic[checked((int)(2) + 1)];
first[0] = 100;
first[1] = 200;
first[2] = 0;
dynamic[] second = new dynamic[checked((int)(2) + 1)];
second[0] = 101;
second[1] = 200;
second[2] = 0;
dynamic[] route = new dynamic[checked((int)(1) + 1)];
route[0] = first;
route[1] = second;
return Convert.ToString(UO.GetArrayLength(route)) + "|" + Convert.ToString(UO.GetArrayLength(route[0]));
return null;
}Параметры и ход выполнения:
- Строка даёт 0; Main возвращает no route до обращения к индексу. Проверка подходит и для пустого Array, но не различает эти случаи.
- Локальная проверка: не отправляет запрос серверу, не перемещает предметы и не изменяет массив. В примерах заданы учебные данные, а не живой инвентарь.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var route = "not an array";
if (Truth(UO.GetArrayLength(route) == 0))
{
return "no route";
}
return route[0];
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: arg (Any)
Результат: dynamic / Any.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public static InjectionValue GetArrayLength(InjectionValue arg) => arg.Kind==InjectionValueKind.Array?new InjectionValue(arg.Array.Length):InjectionValue.Zero;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
string UO.GetWord(object? value, object? wordIndex);
string UO.GetWord(object? value, object? wordIndex, object? delimiter);Получает отдельное слово или поле из текста. Пригодится для разбора координат, списка приоритетов или сохранённой настройки скрипта.
-
value— Исходная строка. Функция разбирает именно переданный текст: не читает журнал, файл, экипировку или мир самостоятельно. -
wordIndex— Целый индекс слова от 0: 0 — первое, 1 — второе. Отрицательный индекс и индекс не меньше количества слов возвращают пустую строку. -
delimiter— Необязательный разделитель. Без него, с "" или с одним пробелом " " текст делится по любым пробельным символам Unicode, включая табуляцию и перевод строки. Иной разделитель — точная последовательность целиком: "::" означает два двоеточия подряд, а не каждое двоеточие. Пустые части отбрасываются; непустые части не обрезаются.
string — выбранная непустая часть, либо "", если индекс отсутствует. Это текст, а не ID, type или число: для числа отдельно проверьте IsNumeric и преобразуйте значение.
- Работает локально, без пакетов и игровых действий. GetWord и UO.GetWord вызывают один обработчик; GetWordCount и UO.GetWordCount также совпадают. Каждый вызов заново разделяет весь текст. В цикле сохраните количество заранее; для большого многократного разбора лучше хранить уже разобранные поля в массиве. Это не CSV-парсер: кавычки не защищают разделители, пустые столбцы теряются.
- GetWord · GetWordCount · IsNumeric
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetWord("red green blue", 1);
UO.Print("GetWord: " + Convert.ToString(result));Параметры и ход выполнения:
- ReadX получает строку "move 1445 1690". Проверяет три слова и имя move; индекс 1 выбирает X. IsNumeric проверяет текст, Convert.ToInt32 возвращает 1445. Это только разбор настройки; персонаж не двигается. При неверной форме возвращается -1.
- ReadX также требует целый X в диапазоне 0..65535 перед Convert.ToInt32; NaN, бесконечность и дробное X отклоняются. Y здесь не проверяется.
return ReadX("move 1445 1690");
dynamic ReadX(dynamic text)
{
if (Truth(UO.GetWordCount(text) != 3))
{
return -1;
}
if (Truth(UO.GetWord(text, 0) != "move"))
{
return -1;
}
var xText = UO.GetWord(text, 1);
if (!(Truth(IsNumeric(xText))))
{
return -1;
}
var x = Convert.ToDouble(xText);
if (Truth(Convert.ToString(x) == "NaN") || Truth(x < 0) || Truth(x > 65535))
{
return -1;
}
if (Truth(x != Math.Truncate(x)))
{
return -1;
}
return Convert.ToInt32(x);
}
bool IsNumeric(object? value) => double.TryParse(Convert.ToString(value), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _);
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- PriorityAt получает список "mage||tank|archer|" и index=1. Разделитель | отбрасывает пустые элементы, поэтому результат tank. Имена произвольные; здесь они не регистрируют ClassMask и не проверяют одежду. Используйте те же правила разделения при подсчёте и выборе.
return RunScenario();
object? RunScenario()
{
return PriorityAt("mage||tank|archer|", 1);
return null;
}
dynamic PriorityAt(dynamic names, dynamic index)
{
return UO.GetWord(names, index, "|");
}Параметры и ход выполнения:
- ReadPlace делит "Britain::Bank:west" точным разделителем ::. Индекс 1 возвращает Bank:west, внутреннее одиночное двоеточие остаётся. Если нет ровно двух непустых частей, помощник возвращает "". Пробелы вокруг частей сохраняются.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
return ReadPlace("Britain::Bank:west");
return null;
}
dynamic ReadPlace(dynamic text)
{
if (Truth(UO.GetWordCount(text, "::") != 2))
{
return "";
}
return UO.GetWord(text, 1, "::");
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: value (String), wordIndex (Integer)
Результат: string / String.
При вызове:
-
InjectionScript.Runtime.InjectionApi.GetWord. -
InjectionScript.Runtime.InjectionApi.GetWord:GetWord(value,wordIndex," ").
Внутренний код реализации, не самостоятельный скрипт.
private static string GetWord(string value,int wordIndex) => GetWord(value,wordIndex," ");Параметры: value (String), wordIndex (Integer), delimiter (String)
Результат: string / String.
При вызове:
-
InjectionScript.Runtime.InjectionApi.GetWord. -
InjectionScript.Runtime.InjectionApi.SplitWords:SplitWords(value,delimiter).
Внутренний код реализации, не самостоятельный скрипт.
private static string GetWord(string value,int wordIndex,string delimiter)
{
var words=SplitWords(value,delimiter);return wordIndex>=0&&wordIndex<words.Length?words[wordIndex]:string.Empty;
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.GetWordCount(object? value);
int UO.GetWordCount(object? value, object? delimiter);Считает непустые поля текста. Позволяет проверить число координат перед разбором и определить границы перебора списка.
-
value— Исходная строка. Функция разбирает именно переданный текст: не читает журнал, файл, экипировку или мир самостоятельно. -
delimiter— Необязательный разделитель. Без него, с "" или с одним пробелом " " текст делится по любым пробельным символам Unicode, включая табуляцию и перевод строки. Иной разделитель — точная последовательность целиком: "::" означает два двоеточия подряд, а не каждое двоеточие. Пустые части отбрасываются; непустые части не обрезаются.
int — количество непустых частей. Пустая строка и строка только из разделителей дают 0. Это счётчик, а не bool: 2 тоже допустимый результат; проверяйте count > 0 или нужное точное количество.
- Работает локально, без пакетов и игровых действий. GetWord и UO.GetWord вызывают один обработчик; GetWordCount и UO.GetWordCount также совпадают. Каждый вызов заново разделяет весь текст. В цикле сохраните количество заранее; для большого многократного разбора лучше хранить уже разобранные поля в массиве. Это не CSV-парсер: кавычки не защищают разделители, пустые столбцы теряются.
- GetWord · GetWordCount · IsNumeric
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetWordCount("red green blue");
UO.Print("GetWordCount: " + Convert.ToString(result));Параметры и ход выполнения:
- HasPoint принимает "1445 1690 0". Требует ровно три слова и числовой текст в каждом, затем возвращает 1; иначе 0. Это только проверка формы, а не допустимости карты, границ координат или проходимости. GetWordCount здесь возвращает 3, а bool возвращает наш помощник.
- HasPoint дополнительно отклоняет NaN и бесконечности, которые сам IsNumeric может принять. Дробные конечные числа допускаются; перед движением нужна отдельная проверка целых игровых координат.
return HasPoint("1445 1690 0");
dynamic HasPoint(dynamic text)
{
if (Truth(UO.GetWordCount(text) != 3))
{
return 0;
}
var i = 0;
while (Truth(i < 3))
{
if (!(Truth(IsNumeric(UO.GetWord(text, i)))))
{
return 0;
}
var value = Convert.ToString(Convert.ToDouble(UO.GetWord(text, i)));
if (Truth(value == "NaN") || Truth(value == "Infinity") || Truth(value == "-Infinity"))
{
return 0;
}
i = i + 1;
}
return 1;
}
bool IsNumeric(object? value) => double.TryParse(Convert.ToString(value), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _);
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- JoinPriorities получает "mage||tank|archer|". Один раз считает три непустых элемента, перебирает индексы 0..2 и возвращает "mage > tank > archer". Начальные, конечные и повторные | не создают отдельный приоритет.
return RunScenario();
object? RunScenario()
{
return JoinPriorities("mage||tank|archer|");
return null;
}
dynamic JoinPriorities(dynamic names)
{
var count = UO.GetWordCount(names, "|");
var i = 0;
var result = "";
while (Truth(i < count))
{
if (Truth(i > 0))
{
result = result + " > ";
}
result = result + UO.GetWord(names, i, "|");
i = i + 1;
}
return result;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- CountPlaces получает "Britain::Bank:west::". Разделитель :: даёт два поля, конечное пустое поле удаляется: результат 2. Одиночное : внутри Bank:west не разделяет текст. Это не перечень городов из клиента, а пример вашего формата настройки.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
return CountPlaces("Britain::Bank:west::");
return null;
}
dynamic CountPlaces(dynamic text)
{
return UO.GetWordCount(text, "::");
}
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: value (String)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApi.GetWordCount. -
InjectionScript.Runtime.InjectionApi.GetWordCount:GetWordCount(value," ").
Внутренний код реализации, не самостоятельный скрипт.
private static int GetWordCount(string value) => GetWordCount(value," ");Параметры: value (String), delimiter (String)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApi.GetWordCount. -
InjectionScript.Runtime.InjectionApi.SplitWords:SplitWords(value,delimiter).
Внутренний код реализации, не самостоятельный скрипт.
private static int GetWordCount(string value,string delimiter) => SplitWords(value,delimiter).Length;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Random(object? max);
int UO.Random(object? min, object? max);Возвращает случайное целое число. Новая форма UO.Random(min, max) выбирает число ОТ min ДО max включительно. Прежняя форма UO.Random(max) сохранена: она выбирает от 0 до max−1. Результат можно сохранить в переменную и использовать как задержку, координату, индекс или условие.
-
min— Первый аргумент ТОЛЬКО двухаргументной формы — включённая нижняя граница, целое от −2147483648 до 2147483647. Может быть отрицательной, нулём или положительной. Должна быть не больше max. В одноаргументной форме min отсутствует, а переданное число означает max. -
max— В двухаргументной форме — второй аргумент, включённая верхняя граница int от −2147483648 до 2147483647. В прежней одноаргументной форме — единственный аргумент, ИСКЛЮЧЁННАЯ верхняя граница, целое от 0 до 2147483647; Random(0) возвращает 0. Отрицательное max в одноаргументной форме недопустимо.
int — одно псевдослучайное целое число. При двух аргументах min ≤ результат ≤ max; обе границы могут выпасть. При одном положительном аргументе 0 ≤ результат < max. Повторение ранее выпавшего числа допустимо: команда не выбирает числа без повторений.
- Поддерживаются ровно две формы: UO.Random(max) и UO.Random(min, max). Вызов без аргументов не зарегистрирован. Для диапазона «от и до» используйте два аргумента.
- Random(5, 5) всегда возвращает 5. Random(10, 1) сообщает ошибку диапазона: границы не переставляются молча. Random(-10, -1) корректен, потому что −10 меньше −1.
- Обе границы — целые int; для десятичных долей можно выбрать целые единицы нужного масштаба и затем разделить. Например, Random(0, 100) / 100.0 даёт дискретные значения от 0 до 1 с шагом 0,01.
- Полный диапазон Random(-2147483648, 2147483647) допустим. Реализация не прибавляет 1 к max в int и поэтому не переполняется на верхней границе. Для широких диапазонов используется отбрасывание лишних значений, чтобы остаток от деления не смещал выбор.
- Вызов вычисляет число локально, не отправляет пакеты и сам по себе не делает паузу. Для случайной паузы передайте результат в UO.Wait. Минимальную необходимую серверу задержку должен сохранять ваш скрипт.
- Сохраните результат в var, если одно и то же число нужно несколько раз. Два отдельных вызова Random могут вернуть разные значения. Команда не проверяет, допустима ли выбранная клетка для движения или переноса: это проверяет соответствующая игровая команда.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Random(10);
UO.Print("Random: " + Convert.ToString(result));Параметры и ход выполнения:
- min получает lower=1, max получает upper=6. Возможны ровно шесть значений: 1, 2, 3, 4, 5 и 6.
- roll хранит одно полученное число. Print выводит именно его; Convert.ToString преобразует int в строку. Повторный запуск может дать то же число.
var lower = 1;
var upper = 6;
var roll = UO.Random(lower, upper);
UO.Print("Roll: " + Convert.ToString(roll));Параметры и ход выполнения:
- min=350 и max=700 задают включённые границы задержки. Результат, например 350, 512 или 700, записывается в delay.
- UO.Wait получает один аргумент delay в миллисекундах. Пауза происходит в UO.Wait; Random только вычисляет число.
- Подберите нижнюю границу под действия и требования вашего сервера. Случайная задержка не заменяет ожидание ответа сервера, если следующему действию нужен этот ответ.
return RunScenario();
object? RunScenario()
{
var delay = UO.Random(350, 700);
UO.Print("Waiting " + Convert.ToString(delay) + " ms");
UO.Wait(delay);
UO.Print("Wait finished");
return null;
}Параметры и ход выполнения:
- min=1, max=3: choice равен 1, 2 или 3. Каждой ветке соответствует одно из допустимых чисел.
- Вызов Random выполняется один раз до if. Если вызывать его заново в каждом условии, это будут разные выборы.
- Замените Print нужными действиями вашего скрипта, сохранив проверки условий, дальности и ответа сервера для этих действий.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var choice = UO.Random(1, 3);
if (Truth(choice == 1))
{
UO.Print("First action");
}
else
{
if (Truth(choice == 2))
{
UO.Print("Second action");
}
else
{
UO.Print("Third action");
}
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}Параметры и ход выполнения:
- Первый Random: min=50, max=90, результат x. Второй: min=60, max=100, результат y. Это две независимые координаты внутри контейнера, не экранные координаты и не координаты карты.
- В MassMove delay=350 мс, quantity=10 целых items, type=0 определяется первым ручным переносом, destination=backpack, x/y берутся из переменных, z=0.
- После команды перетащите образец мышью из исходного контейнера. Всё это включение MassMove использует одну выбранную позицию. Для случайной позиции каждого отдельного предмета нужен цикл с отдельными MoveItem, а не один вызов MassMove.
- Выберите диапазон X/Y внутри доступной области вашего рюкзака. Сервер может изменить размещение предметов.
var x = UO.Random(50, 90);
var y = UO.Random(60, 100);
UO.MassMove(350, 10, 0, "backpack", x, y, 0);
UO.Print("Drag a source item; position: " + Convert.ToString(x) + ", " + Convert.ToString(y));Параметры и ход выполнения:
- В обоих вызовах min=−2 и max=2: возможны −2, −1, 0, 1, 2. GetX/GetY без аргументов читают координаты персонажа.
- x/y — лишь рассчитанная клетка в квадрате вокруг персонажа. Этот пример не начинает движение и не бросает предметы.
- Случайная клетка может оказаться непроходимой или за границей карты. Перед игровым действием используйте подходящие проверки координат и маршрута.
return RunScenario();
object? RunScenario()
{
var offsetX = UO.Random(-2, 2);
var offsetY = UO.Random(-2, 2);
var x = UO.GetX() + offsetX;
var y = UO.GetY() + offsetY;
UO.Print("Candidate tile: " + Convert.ToString(x) + ", " + Convert.ToString(y));
return null;
}Параметры и ход выполнения:
- В Random(count) есть только max=10: верхняя граница исключена, возможны 0..9. Число 10 не выпадает.
- В Random(0, count−1) min=0 и max=9 включительно: допустимый диапазон тот же, но вызов делает новый независимый выбор.
- count должен быть положительным для выбора индекса. Особый совместимый случай Random(0)=0 не означает, что у пустой коллекции существует элемент с индексом 0.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var count = 10;
var index = UO.Random(count);
var equivalent = UO.Random(0, count - 1);
UO.Print("Index 0..9: " + Convert.ToString(index));
UO.Print("Another independent index: " + Convert.ToString(equivalent));
return null;
}
}Параметры и ход выполнения:
- min=7 и max=7 дают единственный результат 7.
- min=−100 и max=−50 дают только отрицательные числа, включая обе границы.
- Последний вызов охватывает весь знаковый 32-битный int. Его результат может быть положительным, отрицательным или нулём.
- Границы передаются от меньшей к большей. Ошибочный вызов Random(10, 1) останавливается с сообщением min must not exceed max; его не нужно использовать для перевёрнутого диапазона.
var fixedValue = UO.Random(7, 7);
var negative = UO.Random(-100, -50);
var signedValue = UO.Random(-2147483648, 2147483647);
UO.Print("Fixed: " + Convert.ToString(fixedValue));
UO.Print("Negative: " + Convert.ToString(negative));
UO.Print("Signed Integer: " + Convert.ToString(signedValue));C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: max (Integer)
Результат: int / Integer.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public int Random(int max)
{
lock (randomSync) return random.Next(max);
}Параметры: min (Integer), max (Integer)
Результат: int / Integer.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public int Random(int min, int max)
{
if (min > max)
throw new NativeSubrutineException("UO.Random(min, max): min must not exceed max.");
if (min == max) return min;
long count = (long)max - min + 1;
lock (randomSync)
{
if (count <= int.MaxValue)
return (int)(min + (long)random.Next((int)count));
// Inclusive Int32.MaxValue and the full signed range must not
// overflow. Rejection avoids modulo bias; reuse the four bytes.
const ulong domain = 1UL << 32;
ulong limit = domain - domain % (ulong)count;
uint sample;
do
{
random.NextBytes(randomRangeBytes);
sample = BitConverter.ToUInt32(randomRangeBytes, 0);
} while (sample >= limit);
return (int)(min + (long)(sample % (ulong)count));
}
}ClassicUO — Bad Newbie & C# Scripts IDE