Этот урок посвящён переменным и событиям.
переменные
integer
float
vector
rotation
key
string
List
Состояния
События
1 state_entry
2 state_exit
3 Touch_start
llDetectedKey
llDetectedGrab
llDetectedTouchUV
4 touch
5 Touch_end
6 collision_start
llCollisionSound
llCollisionFilter
7 collision
8 collision_end
9 land_collision_start
10 land_collision
11 land_collision_end
12 Changed
13 on_rez
llRezObject
llGetStartParam
14 object_rez
15 link_message
llMessageLinked
16 Listen
llListen
llListenControl
llListenRemove
17 timer
llSetTimerEvent
18 Sensor
19 no_sensor
llSensor
llSensorRepeat
llSensorRemove
20 run_time_permissions
llRequestPermissions
llSetPayPrice
llGiveMoney
llStartAnimation
llAttachToAvatar
llDetachFromAvatar
llGetAttached
llCreateLink
llBreakLink
llBreakAllLinks
llGetCameraPos
llGetCameraRot
llSetCameraAtOffset
llSetCameraEyeOffset
llReleaseCamera
llSetCameraParams
llClearCameraParams
llTakeControls
llReleaseControls
21 сontrol
22 money
23 attach
24 moving_start
25 moving_end
26 at_target
llTarget
llTargetRemove
llSetBuoyancy
27 not_at_target
28 at_rot_target
29 not_at_rot_target
llRotTarget
llRotTargetRemove
llEuler2Rot
llRot2Euler
кватернионы
30 dataserver
llGetNotecardLine
llGetNumberOfNotecardLines
llRequestAgentData
llKey2Name
llRequestInventoryData
llRequestSimulatorData
31 email
llGetNextEmail
llEmail
32 http_response
llHTTPRequest
33 remote_data
Для начала, неплохо было бы иметь представление о базовых единицах, которые служат местом хранения данных в скрипте, тоесть типах переменных (variable):
integer – дословно переводитсця с инглиша как ”целое” в них можно хранить НЕ ДРОБНЫЕ ЧИСЛА в диапазоне от -2147483648, до 2147483648.
Почему именно ”от сих и до сих”? О.о
Потому, что, если перевести это число в двоичную систему счисления, то получитсця число
10000000.00000000.00000000.00000000
Это число состоит из 32 знаков, а поскольку цифр в двоичной системе тока две, то их можно записать на любой физический носитель как
последовательность бит, в результате всё число можно упихать всего в 4 байта (как мы помним из школьного курса информатики в одном байте у нас восемь бит).
Э… а каким боком это к скриптам-то относится?
Таким, что клиент SL передаёт\принимает ВСЮ информацию в виде специального кода, который потом дешифровывается и превращается в то, что мы видим на экране, а для того чтобы игра шла с нормальной скоростью, компьютеру необходимо обрабатывать КУЧИ переменных ежесекундно с обоих направлений (то есть кодировать-отправлять и принимать-декодировать), успевать следить за вашими действиями (прыжки, ходьба, полёт и т.п.), корректно обрабатывать все ваши действия, плюс поступившие данные, такие, как передвижения других аватаров, ну или скажем примов, то есть можете представить какую ”кашу” приходится пережёвывать вашему компу со скоростью 25-50 раз в секунду и если бы все числа, которые хранятся в памяти находились бы там в том виде, в котором вы их видите на экране(то есть на каждую цифру десятичного числа приходился бы один байт), то для того, чтобы посидеть в Second Life с нормальным FPS (Frames Per Second – кол-во кадров в секунду) вам бы потребовался 20 процессорный кластер с 50 Гб оперативки на борту и Интернет-кабель шириной с магистральный газопровод…
То есть числовые пределы обусловлены обычной экономией трафика (тока вот не надо делать такие лица – помимо вашего скрипта сервер,
который отвечает за работу того или иного сима должен успеть обработать ещё и чужие), атседова первое правило скриптера:
Скрипт при всей своей функциональности, должен быть написан настолько просто и КОМПАКТНО, насколько это вообще возможно… но не проще!
Те, кто делают скрипты в стиле ”и так сойдёт” зовуться быдлокодерами, для того, чтобы был понятен смысл названия, приведу простейший пример –
представьте, что некий товаришч решив особо не заморачиваться запихнул в каждый прим некоей вещи, состоящей из 256 примов (это максимальное количество примов в одном объекте) по 10 скриптов выполняющих ОГРОМЕНЫЫЙ блок кода каждый, все скрипты на симе обрабатываются сервером этого Сима (сервер – это очень мощный комп, который находится в Linden Lab и обрабатывает поступающие данные, хоть сервак и мощная штука, но и его ресурсы не резиновые), а теперь почешите тыкву и скажите, раз в какой промежуток времени сервер будит успевать посылать вам (и остальным находящимся на симе) данные если на Симе окажется 10-15 таких вещичек?Если число в переменной типа integer превышает предел, то эта переменная автоматически становится равна -1.
Как правильно записывать данный тип переменной: integer varname=777;
Для тех, кто со скриптингом вообще не знаком поясню смысел сией конструкции.
Integer - в начале сообщает компилятору шо за тип данных тута лежит, тобиш целое это число или дробное,
или там не числа вообще, а буквы.
Varname - это имя нашей переменной, имя пишется ТОЛЬКО ЛАТИНСКИМИ БУКВАМИ и не должно начанаться с цифры (но может ей заканчиваться).
Длинна имени не должна превышать 255 символов.
777 - это то, чему наша переменная в данном случае равна.; - точка с запятой. Если забыть поставить её в конце переменной, то скрипт выдаст Syntax error
98% всех синтакс съеррориваний у новичков случаютсця из за забытых ”;”(точка с запятой), ”,”(запятая), ”{}”(фигурные скобки), ”[]”(квадратные скобки), ””(кавычки).
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
float – сдесць можно хранить десятичные дроби.
Предельным значением для переменной float будит число, которое, если убрать запятую (на каком бы десятке она ни была) не превышает по длинне 7 знаков как в положительную, так и в отрицательную сторону.
Как правильно записывать данный тип переменной: float varname=0.5;
Можно правда записать и вот так вот: float varname=.5; то есть, ноль стоящий в начале можно опускать.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
vector – нужен, для хранения данных, которые выражаютсця тремя значениями, например для хранения координат положения
и поворота в пространстве (позиции XYZ), цветов (RGB – красный, зелёный, синий), по факту является тремя float-ами слепленными вместе.
Вектора можно использовать и для хранения не связанных между собой чисел, то есть вместо трёх разных переменных упихать все значения в одну, это, шо называется для тех, кому лень писать ”многабукав”, главное патом не забыть куда и шо складировали…
На всякий поджаренный: если у вас есть переменная vector znacheniye=<2.5,1.8,0,3> и вам нужно вставить куда-нибудь,
ну например только первое значение, то сделать это можно вот так вот – znacheniye.x, соответственно для вставки второго или третьего значений
нужно приписать к имени переменной .y или .z и эту часть вектора можно будит вставить как дробь (float).
Как правильно записывать данный тип переменной: vector varname=<0.5,2.75,5.78>; убедительная прозьба не забывать ставить запятые между числами и ”галки” в начале и в конце значения, это тоже одна из распространённых ошибок.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
rotation – то же, что и предыдущее, только тут не три, а четыре переменных, используетсця в основном для хранения так называемых ”нормированных кватернионов” поворота. О том, шо это такое и с чем это едят, поговорим позже.
Если вам вдруг надо вставить куда-нибудь четвёртое значение как десятичную дробь, то после названия переменной поставьте .s
Как правильно записывать данный тип переменной: rotation varname=<1.45,0.5,2.75,5.78>;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
key (ключ) – сия штуковина нужна для хранения так называемого ”UUID объекта”.
UUID – это уникальный, универсальный идентификационный номер, который есть у КАЖДОГО объекта или аватара.
Э… и зачем он нужен? =О.о=
Данные каждого объекта, текстуры, аватара, находятся на серверах Linden Lab и имеют свой персональный адрес, чтобы их можно было найти и оперативно сгрузить вам на комп.
Ключ представляет из себя последовательность из 32 шестнадцатиричных цифр и выглядит примерно вот так вота: f73e94ac-1bfd-43e2-ff0a-efc7fee1029e
Как правильно записывать данный тип переменной: key
varname=”f73e94ac-1bfd-43e2-ff0a-efc7fee1029e”; сам ключ всегда пишется в кавычках!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
string – (строка) Ну, а тут можно хранить любой тип данных, но в основном тут хранят текст.
Как правильно записывать данный тип переменной: string varname=”Шо хотим, то тута и пишем”;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List (список) – этот тип, как явствует из его имени, служит для хранения данных любого типа.
Всё содержимое листа, должно быть заключено в квадратные скобки - [] переменные типов string и key всегда пишутся в кавычках.
Как правильно записывать данный тип переменной:
list varlist=[”многабукав”,”f73e94ac-1bfd-43e2-ff0a-efc7fee1029e”,<1,2,3>,<1,2,3,4>,1, 0.523];
Как мы можем заметить, здесь в одном листе присутствуют все типы переменных (по порядку – string, key, vector, rotation, integer, float), кроме самого листа, поскольку лист в LSL не может содержать в себе другой лист.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Так, мы рассмотрели все типы переменных, теперь неплохо было бы разглядеть, какие ещё конструкции будут встречаться нам в дальнейшем.
Стейты (state, они же ”состояния”) – это блоки в которых выполняется весь основной код скрипта, огораживаются эти блоки фигурными скобками - {}.
Стейты могут наличествовать в скрипте в нескольких экземплярах, по умолчанию в скрипте должен быть как минимум один стэйт, он там кстати всегда и присутствует – это default который.
Пример обычного стейта:
{
State_entry()
{
llOwnerSay(”Халоу”);
}
}
Пример двух стейтов в одном скрипте:
{
State_entry()
{
llOwnerSay(”Стейт 1”);
state two; //А вот так осуществляется перепрыгивание с одного стейта на другой (точку с запятой в конце не забываем ставить).
}
}
State two //Второй стейт
{
State_entry()
{
llOwnerSay(”Стейт 2”);
}
}
Все стейты, акромя дефолтного должны иметь приставку state перед именем. Имя стейта записывается ЛАТИНСКИМИ БУКВАМИ!
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Эвенты(events) – они же события, запускают определённый код если произошло определённое событие.
Э… а шо из себя эти ”события” представляют-то и когда они происходят? О.о
События представляют из себя… э… ну события они из себя и представляют, типа противотанковой мины – пока на неё не наступил она не работает, а если наступил, то салат мясной ”ошибка сапёра”.
Эвент включает в себя блок кода (код, который находится внутри эвента заключён в фигурные скобки), который срабатывает по данному событию, код должен всегда находиться внутри эвента, если попытаетесць вписать его между эвентами, то получите Syntax error при компиляции.
Убедительная просьба, не путать стейт с эвентом – стейт, это блок, В КОТОРОМ хранятся эвенты, эвент вне стейта существовать НЕ МОЖЕТ!
А ”детонируют” эвенты по следующим причинам:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
state_entry() сей эвент запускается первым ВСЕГДА, сразу после начала работы скрипта, даже если стейт_энтри находится где-нибудь в середине между другими эвентами или вообще в конце, компилятор его все равно запустит первым.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
state_exit() а это антипод стейт_интри,- он запускаетсця тогда, когда завершается выполнение одного стейта и начанается другой (прыжок со стейта на стейт описанный выше помним? Ну вот тама он и срабатывает)стейт_эксит НЕ СРАБАТЫВАЕТ при переходе между событиями внутри самого стейта!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Touch_start(integer total_number) а вот это первый для нас эвент, который перед срабатыванием возвращает атрибут, это который total_number в скобках, сие имя может быть заменено на любое другое написанное латинскими буквами и без пробелов, главное, чтобы он не совпадал названием с любой другой переменной имеющейся в скрипте, поскольку этот атрибут может быть вызван нами из кода этого события, и если имена совпадают, то скрипт при компиляции выдаст ошибку (небось видели такое, когда кричат чьё-то имя и откликаются человек десять, вот тут при совпадении имён навроде того будит).
А возвращает сей атрибут, как явствует из названия общее число всех, кто щёлкал по содержащему скрипт объекту, То есть,- если я клацну на объект, то он вернёт 1, если я опять клацну на него, то как было 1 так и останется, а вот если клацнет ещё кто-то, вот тогда будет уже 2 и т.д.
Зачем нам нужен этот номер?
Затем, что по нему можно узнать не только то, сколько человек щёлкнули по объекту, но и кто именно щёлкнул, для того чтобы это сделать, надо пихнуть номер атрибута в функцию key llDetectedKey, которая, как явствует из названия фиксирует ключ лапнувшего этот объект по номеру указанному в атрибуте.
Должно получитьсця что-то вроде этого: llDetectedKey(total_number);
Более того, есть ещё и функция, которая возвращает вектор направления движения курсора того, кто этот объект ухватил и пытаетсця передвинуть (причём без разницы физический это объект или нет). Зачем оно нужно? Ну, хотя бы для того, чтобы например, использовать объект, как рычаг для задания определённого параметра, способ, конечно не из простых, но эффектности ради чего тока ни сделаешь. Подобный способ,
кстати, использовал тот же товаришч Uchi в HUD-е для своих бесплатных фуриков.
А называетсця данная функция llDetectedGrab – принцип использования тот же, что и в предыдущем случае, только,
возвращает она не ключ, а вектор и работает только в событиях touch, touch_start и touch_end.
В этих же событиях работает и функция llDetectedTouchUV(integer index) ента функция возвращает координаты места, на которое вы щёлкнули по номеру указанному в параметре(а тама, как правило надо писать нуль).
Срабатывает это событие всякий раз, когда кто-то щёлкает на объекте и в отличии от следующего эвента срабатывает оно при каждом щелчке только ОДИН РАЗ!
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
touch(integer total_number) событие работает до тех пор пока вы удерживаете зажатой левую кнопку мыши на приме, в котором этот скрипт лежит (то есть по русски говоря, между нажатием и отпусканием кнопки мыши данный стейт срабатывает, выполняет код внутри себя и закрывается постоянно с небольшим интервалом).
Атрибут возвращает то же, что и предыдущий и следуюций эвенты.
Функции llDetectedKey и llDetectedGrab в комплекте поставки.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Touch_end(integer total_number) Это событие срабатывает, когда вы отпускаете кнопку мыши.
Функции llDetectedKey и llDetectedGrab в комплекте поставки.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
collision_start(integer total_number) это событие срабатывает тогда, когда какой-либо аватар или объект только начанает сталкиваться с примом, в котором этот скрипт находитсця.
Атрибут в скобках возвращает общее кол-во объектов, которые сталкивались с нашим примом.
Так же, как и событие touch, столкновение имеет ещё два события – collision(integer total_number) – работает, пока объект соприкасается с другим объектом, и событие collision_end(integer total_number), которое срабатывает при завершении столкновения.
Примечание: события collision не работают во время столкновения с землёй!!! Для этого (зачем-то) есть три других события.
Где это событие может использоваться: данные события полезны, например, если надо узнать, хто был у вас дома, пока вы отсутствовали, сие событие так же используетсця во всякого рода ракетах и снарядах, которые при столкновении по идее должны взрыватьсця, так же это событие можно использовать для создания ”нано-стен”, это такие экхм… ”двери”, которые пропускают вас и ваших знакомых, а так же обладают функцией посылки по указанному адресу всех остальных (фильм Doom смотрели наверное, вот типа таких штук).
Помимо Функции llDetectedKey в комплекте поставки у этого события есть ещё пара интересных штуковин:
llCollisionSound(string name, float volume) эта функция позволяет менять
звук проигрывающийсця во время столкновения объекта с кем-либо, или кого-либо с объектом.
string name – тута должно быть имя звука, находящегося в инвентаре прима.
float volume – это громкость. Приминает значения от 0.0 до 1.0
llCollisionFilter(string name, key id, integer accept) эта функция позволяет отфильтровать срабатывание событий типа collision по двум атрибутам:
string name – здесць можно указать имя прима или аватара, после столкновения с которым сработает событие.
Если имя столкнувшегося не соответствует написанному тута, то событие колизион не сработает.
key id – енто то же, что и предыдушчее, тока вместо имени сюда пихается ключ.
integer accept – а тута устанавливаетсця значение, включающее или выключающее фильтрацию столкновений. Если стоит TRUE,
то фильтрация производится, а если FALSE, то событие collision срабатывает при контакте с любым подвернувшимся объектом или аватаром.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
land_collision_start(vector position) данное событие являет из себя почти то же самое, что и события типа touch,
а отличается оно всего двумя вещами.
1.- срабатывает оно только, когда объект сталкивается с землёй.
2.- возвращает при столкновении не количество столкнувшихся объектов (поскольку земля на симе всего одна), а координаты места, в котором произошло столкновение.
Как и обычное столкновение, имеет ещё два события, это - land_collision(vector position) и land_collision_end(vector position)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changed(integer change)
Сие событие срабатывает при изменении какого-либо параметра прима, группы примов или аватара (в случае, если прим одет на нём.)
Атрибут change возвращает целое число, которое обозначает, шо именно изменилосць(сей атрибут тока констатирует что изменилось, но не показывает какое значение на какое поменялось).
Сопсна, перечень самих значений:
1 он же CHANGED_INVENTORY – Это значение возвращается, если в инвентарях этой группы объектов произошли какие-либо изменения (повторюсць В ИНВЕНТАРЯХ ГРУППЫ ОБЪЕКТОВ, а не только в том приме, где лежит этот скрипт).
Э… а… какие именно?
Ну примерно следующие: добавление, удаление, переименование объекта (или поля description) внутри инвентаря, изменение содержимого Note card,
перекомпиляция (НЕ СБРОС, А ИМЕННО ПЕРЕКОМПИЛЯЦИЯ) скрипта, изменение ”Asset Permissions” (активных прав) у объектов инвентаря (то есть, прав на копирование, модификацию, передачу объекта кому-то ещё, возможность изменять объект всем членам одной и той же группы,
возможность ”возить” чужим физическим объектом по земле и т.д.).
8 он же CHANGED_SCALE – это значение возвращается при изменении размера любого объекта этой группы.
32 он же CHANGED_LINK – это значение возвращается при: линковке\разлинковке примов, при ”заходе аватара на посадку”
(то есть, когда кто-то садится на этот объект), при вставании с прима, при изменении формы любого объекта группы (то есть был куб, стал шарик).
128 он же CHANGED_OWNER – срабатывает, когда у объекта меняетсця владелец (полезная штука, с её помощью можно сделать скрипт, который, допустим, говорит инструкцию по использованию объекта только один раз – при его покупке/получении,
а не зафлуживает чат мусором каждый раз, как его из инвентаря выложишь).
256 он же CHANGED_REGION – возвращается, когда объект или аватар переходят на другой сим.
Правда срабатывает только, если скрипт находитсця в главном приме группы.
512 он же CHANGED_TELEPORT – этот параметр возвращается, (только, если объект со скриптом надет на аватар) когда вы телепортируетесь на другой сим или когда садитесь на какой-то объект и он переносит вас в другое место,
на этом же Симе.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
on_rez(integer start_param) а это ещё один новый тип события, в отличии от предыдущих некоторые параметры этого события можно задать ещё до того, как оно произошло.
Срабатывает оно каждый раз, как только объект создаётся или выкладывается из инвентаря на землю.
А задать заранее тут можно атрибут start_param. Этот атрибут является целым числом в диапазоне от -2147483648, до 2147483648
Смысел этого атрибута по началу кажется не понятным. Нужен он для передачи данных в только что созданный объект из скрипта, который его создал (это в случае, если скрипт создаёт объект), ну например, сколько времени должна после старта лететь ракета, прежде, чем она взорвётся.
А предадаёт этот параметр функция llRezObject(string inventory, vector pos, vector vel,rotation rot, integer param);
Ну, вот мы и доползли до рассмотрения принципов работы функций. Как мы видим, после названия функции в скобках идут её атрибуты, я тут написал их в виде переменных, но вообще параметры функции заполняются конкретными значениями, то есть выглядеть это должно примерно вот так вота:
llRezObject(”Object”,<128,128,20>,<0,0,20>,<0.000000,0.000000,0.000000,1.000000>,7);
Если выразить то, что тут написано в так называемом ”псевдокоде”, то означать сие будит примерно следующее:
ллСоздатьОбъект(взять из инвентаря этого прима объект с именем ”Object” (сесна, шобы было, что брать, вам сперва енто в инвентарь объекта самому запихнуть надо, и желательно поставить тому, что в инвент положили права Copy, иначе скрипт не сможет выложить объект),| поставить объект в позицию <128,128,20>,| пнуть объект в направлении (а заодно и со скоростью) <0,0, 20> (то есть, если создаваемый объект является физическим, то он подскочет на 20 метров в верх, не физические объекты этот параметр просто проигнорируют), | перед тем, как пнуть объект, повернуть его на кватернионный угол <0.000000,0.000000,0.000000,1.000000>(что в данном случае означает не поворачивать объект ни на градус, поскольку этот угол является нулевым, вместо этого здоровенного кватерниона, можно вписать в этот параметр ZERO_ROTATION, после всех вышепроделанных глумлений сообщить объекту, тот самый start_param, который в данном случае равен 7);
Если скрипт по какой-либо причине пропустил данные из события on_rez, то стартовый параметр всегда можно взять из integer llGetStartParam();
Давайте-ка для кучи рассмотрим и его заодно:
Как мы можем заметить перед непосредственно самой функцией я написал integer – шо бы это могло значить? =О.о=
Означает это, что данная функция нужна для так называемого ”вызова” данных. То есть вместо функции тут выдаётся цифра,
которая сообщаетсця при создании этого объекта и её можно вызвать из любого другого события (например из state_entry).
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
object_rez(key id) - это событие срабатывает, после того, как функция llRezObject создала какой-либо объект.
Атрибут key id возвращает ключ созданного объекта (для тех, кто не понял, в каком именно объекте срабатывает это событие поясняю – в том КОТОРЫЙ создал объект, то есть в родительском).
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
link_message(integer sender_num, integer num, string msg, key id) – это событие срабатывает при получении объектом сообщения особого типа, эти сообщения могут передаватьсця только внутри группы примов, или внутри одного прима. Нужны они, для обмена данными между несколькими скриптами.
Как мы можем заметить у этого события не один, а несколько атрибутов.
Integer sender_num – возвращает номер прима пославшего сообщение.
Шо за номер такой спрашиваете? Э… щас объясню – когда вы выделили несколько примов и нажали Ctrl+L, перед линковкой каждому приму движком SL присваивается определённый номер. Первым в цепочке всегда стоит прим, который был выделен последним, он имеет порядковый номер 1 (если прим не слинкован с какими-либо другими, то его номер по умолчанию равен 0).
Прим выделенный предпоследним имеет порядковый номер 2 и т.д.
Вот этот-то номер нам в сендер_нум (ну или как вы этот параметр там назвали) и приплывает.Integer num, string msg и key id – это сопсна само сообщение.
Оно, как видим состоит из трёх частей. Num – это целое число, msg – может быть чем угодно, буквами, цифрами, тем и другим,
а через key id можно передать любой ключ.
Тока… не рекомендую посылать в командах тексты размером с ”Войну и Мир” ждать их прихода от одного скрипта к другому вы мягко говоря опухнете, к тому же не факт, что команда вообще дойдёт (да, и такое, к сожалению бывает…).
Э… а… как эти сообщения сюда послать? =О.о=
Через функцию llMessageLinked(integer linknum, integer num, string msg, key id);
Она, как видите имеет те же самые атрибуты, что и принимающее событие, разница только в том, что параметр integer linknum должен содержать ”адрес” получателя, то есть номер прима, к которому должно прийти сообщение.
Правда, не всегда нужно посылать сообщение какому-то конкретному объекту, а зачастую очень даже не нужно.
Для таких случаев существуют специальные константы:
1 она же LINK_ROOT - посылает сообщение только в главный прим (даже, если оно послано скриптом который в этом же главном приме и лежит).
-1 она же LINK_SET - посылает сообщение всем примам группы (и тому приму, в котором находится тоже).
-2 она же LINK_ALL_OTHERS – посылает сообщение всем примам, кроме того, в котором данный скрипт находитсця.
-3 она же LINK_ALL_CHILDREN - посылает сообщение всем примам, крме главного (если отправляющий скрипт находится не в главном приме, то сообщение так же прийдёт ко всем объектам, кроме родительского).
-4 она же LINK_THIS - посылает сообщение только в тот же прим из которого было отправлено.
То есть, выглядеть посылка сообщения будит следующим образом:
llMessageLinked(LINK_SET,0,”многабукав”,””);
В псевдокоде это будит звучать следующим образом:
ллСообщениеЛинку(ЕСЛИ_КОНКРЕТНЕЕ_ТО_ВСЕМ_ПРИМАМ,цифра 0, текст ”многабукав”,ключа нету);
Поясню некоторые особенности написания, если вам надо послать сообщение только через какой-то один параметр (например, как у меня -
посылаетсця только ”многабукав”), то в num напишите ноль, а для переменных типа string и key существует так называемый ”пустой бланк” – то есть пишутся просто две кавычки рядом, ну, мол нету тама ничего.
Или, если хотите, можете вместо пустышки в переменных типа key писать константу нулевого ключа – NULL_KEY (каторая, для справки, равна – ”00000000-0000-0000-0000-000000000000”).
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Listen(integer channel, string name, key id, string msg) – это событие активируетсця определённой функцией и позволяет слушать чат.
Атрибуты listen-а возвращают следующие параметры:
Integer chanel – возвращает номер канала, который скрипт в данный момент слушает.
В SL диапазон каналов такой же, как и диапазон чисел в переменной типа integer, то есть от (-2147483648) до 2147483647.
Писать сообщения на любой канал положительного диапазона, можно напечатав слэш (/ - не путать с обратным слэшэм,- это который \) и номер канала, тобиш вот так вота - /1024 какое-нить слово.
А вот на каналы отрицательного диапазона вам ничего сказать не получитсця.
Как вы наверняка уже знаете из лекций Зубы Зеновки, 0 – это публичный канал, а 2147483647 – это канал, на котором скрипты обычно матюкаются на криворуких скриптеров, иными словами – это канал отладки, где скрипты сообщают об ошибках.
string name – возвращает имя аватара (или прима), который сказал что-либо на прослушиваемом нами канале.
Key id – это почти то же самое, что и предыдущее, только возвращает он не имя, а ключ того, кто что-либо сказал.
Э… а зачем тут возвращаются и имя и ключ, по идее не всё ли равно? =О.о=
Нет, не всё равно,- иногда приходитсця делать скрипты, которые слушают либо только какой-то конкретный объект, либо какого-то конкретного аватара и если скрипт идентифицирует, ну допустим, аватара только по имени, то кто-нибудь может начать шуить и назвав обычный прим именем этого аватара отдавать команды ВАШЕМУ скрипту, но без вашего разрешения.
string msg – возвращает сказанное кем-то сообщение.
Так, атрибуты мы рассмотрели, теперь давайте рассмотрим функцию (или, вернее функции – их 3 шт.), которая срабатывание этого события и активирует:
llListen(integer channel, string name, key id, string msg);
В атрибуте integer channel надо указать, какой канал будит слушать скрипт.
В атрибуте string name можно указать имя, тогда событие будит срабатывать тока если имя сказавшего соответствует имени,
написанному в этом параметре (это может быть как имя аватара, так и имя объекта).
key id, то же, что и предыдущее, тока срабатывает, когда совпадают ключи, а не имена
(можно, кстати скомбинировать с предыдущим и следующим параметрами).
string msg, о! А этот параметр заставляет срабатывать событие, только, если текст сообщения полностью соответствует написанному тута.
Как правильно записывать эту функцию: llListen(0, ””,NULL_KEY, ””);
Как это звучит в псевдокоде: ллСлушать(слушать канал номер 0, имя не указано, ЛЮБОЙ_КЛЮЧ, фильтровки по конкретному сообщению нету);
Следующая функция позволяет включать и выключать срабатывание события listen:
llListenControl(integer num, integer active);
Эта функция чрезвычайно полезна в скриптах, которые по идее не всегда должны слушать чат.
Таковыми, например, являютсця скрипты некоторых видов оружия. Допустим у нас имеетсця пушка, в которой можно выставлять вручную скорость полёта пули, её тип, наносимый ею урон.
По идее, событие listen должно срабатывать тока когда владелец напечатает в чат параметры, в остальное время оно не используетсця.
То есть можно поставить включение события по нажатию кнопки, а как только параметры установлены, функция опять выключаетсця.
Ну дык вот в таких вота случаях её и используют.
В первом атрибуте должно быть число, которое генерируетсця функцией llListen. А генерируетсця оно не совсем обычным способом:
{
Integer a; //енто глобальная переменная, она так называетсяця потому, что она находится перед всем остальным кодом и может вызываться откуда угодно. Сдесь будит храниться сгенерированный ллЛистеном номер.
State_entry()
{
//integer a; //а вот если бы она стояла тута, то называласць бы она уже не глобальной, а локальной переменной и могла быть использована тока в этом событии и нигде больше. Я её тута закоментил, чтобы скрипт при компиляции не вылетел. Комментарии – это участки скрипта, которые игнорируютсця компилятором, это может быть код, текст или что-то ещё. Перед участком, который надо закоментить ставим тэг //. Поскольку закрывающего тега в ЛСЛ нету, комментарий заканчиваетсця там, где вы перейдёте на следующую строку нажав ENTER.
a=llListen(0,"","",""); //Присваиваем переменной значение сгенерированное ллЛистеном.
}
Listen(integer channel, string name, keyid,string msg)
{
llListenControl(a,FALSE);
}
}
Сопсна, шо делает то, шо тута начепятано? О.о
Э… ну код этого скрипта примитивен просто-таки до нельзя – он при включении активизирует событие listen, а заодно (вот это попрошу намотать на ус, ибо подобные логические кривляния встречаютсця довольно часто) присваивает переменной ”a” значение генерируемого числа (то есть функция одновременно выполняет активацию срабатывания события listen и возвращает некоторое значение), а после получения первого подвернувшегося сообщения из чата выключает срабатывание события listen.
Шо? =О.о= Как я узнал, шо событие выключаетсця? А, ну дык эт самое, у второго атрибута какое значение? FALSE, говорите?
Ну, вот поэтому и выключаетсця. А включить его можно поставив в листен контрол константу TRUE.
Для спраффки: FALSE=0, TRUE=1.
Ну и последняя листеновская функция это llListenRemove(integer number);
Она удаляет событие listen в отличии от листен контрола, который просто включает/выключает это событие, то есть – когда вы удалили событие listen с помощью llListenRemove, вы можете потом заново поставить его, но уже на другой канал, или с другими атрибутами вызвав llListen, например поменять канал, который слушает скрипт или изменить параметры фильтрации сообщений.
Для того, чтобы удалить событие и изменить параметры события, надо написать примерно следующее:
Default
{
State_entry()
{
a=llListen(0,””,””,””);
}
Listen(integer channel, string name, key id, string message)
{
llListenRemove(a);
llListen(1,””,””,”многабукав”);
}
}
Шо, сопсна сие значит – в state_entry мы устанавливаем событие на прослушивание нулевого канала.
При получении первого же попавшегося сообщения событие удаляется. На его место ставится листен, с прослушиванием не нулевого,
а уже первого канала и срабатыванием события только по слову ”многабукав”.
Некоторые могут спросить, а… почему в llListenRemove я всегда запихиваю переменную,
а не сопсна сам llListen со всеми его атрибутами?
По одной простой причине – чем больше раз вы вызываете какую-либо функцию, тем тормознее получаетсця скрипт.
Брехня, говорите? Ну смотрите сами – для того, чтобы пропустить/игнорировать какое-либо сообщение скрипт сперва его анализирует ПОБУКВЕННО (сам анализ происходит, напомню, на сервере Сима, который помимо вашего ещё и другие скрипты обработать должен и разослать всем пользователям данные успеть), а вот теперь представьте, что на одном симе встретелисць 8 человек, на которых надето по вещи, которая каждые 0.2 секунды говорит на определённом канале сообщение в чат, чтобы его услышали другие, а так же анализирует поступающие сообщения, чтобы выполнять какие-либо действия. Вот и почешите тыкву, с каким объёмом вычислений прийдётсця столкнутьсця серверу, если ему каждые 0.2 секунды прийдётся анализировать ВСЕ входящие сообщения по восемь раз.
Ну… падумаеш, скрипту и надо-то всего, тока пропустить ”правильные” мессаги, прописанные в листене, там прям вычислений мога как будто…
Э… для того, чтобы идентифицировать сообщение как ”своё” скрипту сперва надо понять, а своё оно, или всё-таки нет, а для этого ему сперва его и надо сопоставить с эталоном (ПОБУКВЕННО), более того, поскольку машина не видит разницы между ЛЮБЫМИ сообщениями,
то анализирует она заодно и сообщения посылаемые собственным же скриптом, а поскольку количество человек с подобными скриптами равно восьми, серверу приходитсця по ВОСЕМЬ РАЗ(!!!) каждые 0.2 секунды перебирать одни и те же сообщения.
Атседова второе правило ЛСЛ-скриптера: Десять раз подумайте, прежде, чем подумать сделать скрипт с использованием листена, поскольку при должным образом выкривленных руках даже один скрипт может наделать не мало тормозов на симе.
И из вышесказанного ещё одно правило: Не используйте более одного листена на одну вещь, поскольку при наличии моска в голове этого более, чем достаточно в 99.99999% случаев. Ну… а если репа вам нужна, тока для того, чтобы туда есть, то не рекомендую вообще браться за изучение ЛСЛ - вредно для "жылутка".
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
timer() Это событие срабатывает раз в определённый промежуток времени.
Промежуток этот указываетсця функцией llSetTimerEvent(float time); Время указывается в секундах.
Значение 0.0 прекращает работу события.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sensor(integer num_detected) Это событие представляет из себя шо-та навроде радара, оно может выдавать информацию о количестве определённых объектов или аватаров через атрибут integer num_detected (за раз, данное событие находит тока 16 целей, порядковые номера целей соответствуют их удалённости от сканирующего объекта).
Включаетсця это событие функцией llSensor(string name,key id,integer type,float range,float arc);
Смотрим, шо означают параметры сенсора:
string name и key id – это полные аналоги таких же атрибутов в llListen, являютсця своеобразными фильтрами имён, то есть – если имя или ключ зафиксированного объекта не равны эталону, то этот объект игнорируется.
integer type – этот параметр сообщает сенсору, объекты какого типа, сопсна искать-то нужна.
А типы ”жертв” следующие:
AGENT – искать тока аватарин.
ACTIVE – искать тока двигающиеся физические объекты, или объекты с активными(то есть работающими в данный момент) скриптами.
PASSIVE – искать либо физические примы, которые не шаволюцо, либо не физические.
SCRIPTED – искать примы, которые содержат работающие в данный момент скрипты.
float range – дальность сканирования. По умолчанию не может быть больше 96 метров… э… вернее, большее число-то поставить можна, тока дальность сканирования от этого не увеличитсця.
float arc – этот параметр указывает угол мёртвой зоны сканирования.
Э… и в каких еденицах этот ”arc” тута указываетцо? =О.о=
Для того, чтобы ввести нужное вам значение, можно использовать следующую формулу – (45*DEG_TO_RAD)*PI.
Где 45 – нужный вам угол, который автоматически переводится в радианы и умножаетсця на ”пи”.
Вот так вота это примерно выглядит, если представить графически:
Прошу обратить внимание на то, что угол 45 градусов при работе сенсора отмеряется в две стороны (то есть по факту тама будит угол в 90 градусов)
и на то, что внутри этого угла сканирования НЕ ПРОИЗВОДИТСЦЯ!
Самый простейший и наглядный пример принципа работы сенсора, это вот этот вота скрипт:
{
state_entry()
{
llSensor("",llGetOwner(),AGENT,30, (45*DEG_TO_RAD)*PI);
}
sensor(integer total_number)
{
llSetColor(<0,1,0>,ALL_SIDES);
}
no_sensor()
{
llSetColor(<1,0,0>,ALL_SIDES);
}
}
Как это, выглядит в псевдокоде:
Дефолтное состояние
{
Входное_событие()
{
ллСенсор(любое имя объекта, а вот ключ ллВзятьХозяйский(), тип объекта ТОКА_АВАТАРЫ, радиус 30 м, угол мёртвой зоны – 45 градусов ПЕРЕВЕДЁННЫХ_В_РАДИАНЫ и умноженных на ”пи”);
}
событие_сенсор(целое число скока_всего_нашол)
{
ллПоставитьЦветОбъекта(<зелёный>,НА_ВЕСЬ_ОБЪЕКТ);
}
событие_шота_никаво_не_видать()
{
ллПоставитьЦветОбъекта(<красный>,НА_ВЕСЬ_ОБЪЕКТ);
}
}
Как мы можем заметить из превдокода, при наличии хозяина скрипта в зоне сканирования объект содержащий данный скрипт зеленеет,
а при отсутствии – краснеет.
Событие no_sensor() активизируется и выполняет определённый код, когда сенсор не находит никого на заданном расстоянии.
Но! llSensor срабатывает только один раз, после чего для дальнейшего сканирования её надо будит вызывать повторно.
А вот если требуется проводить сканирование постоянно с определёнными интервалами, то на этот случай предусмотрена
функция llSensorRepeat(string name, key id, integer type, float range, float arc, float rate);
Это почти тот же ллСенсор, только с одним добавочным параметром (float rate в конце). Вот этот атрибут-то какраз и указывает раз в какой промежуток времени проводить сканирование (то есть, это что-то среднее, между листеном и таймером).
Дык вота… а теперь вспоминаем, как работает механизьм фильтрации функции llListen.
Сперва функция получает входные параметры, затем берёт букву первого параметра, сравнивает её с эталонной, если букова совпала,
то начанает анализировать следующую… и т.д. (для тех, до кого из предыдущего ликбеза о функции листен всё ещё недоехало –
если сообщения поступают с частотой раз в 0.2 сек, то сервер должен успеть выполнить ПОБУКВЕННОЕ СОПОСТОВЛЕНИЕ ВСЕХ ПАРАМЕТРОВ в промежутке между двумя сообщениями, а заодно и обработать другие скрипты и разослать данные пользователям)
Поскольку у примов параметров… э… ”чуток” побольше, чем у сообщений, то и нагрузка на сервер ”чуток” возрастёт.
Атседова правило:
НЕ ИСПОЛЬЗУЙТЕ БОЛЬШЕ ОДНОГО СЕНСОРА В ОДНОМ ОБЪЕКТЕ, И КАК ТОЛЬКО ДАЛЬНЕЙШАЯ НЕОБХОДИМОСТЬ В СКАНИРОВАНИИ ОТПАДАЕТ – СВОЕВРЕМЕННО ВЫКЛЮЧАЙТЕ ЭТО СОБЫТИЕ!!!
А выключается это событие функцией llSensorRemove(); Никаких параметров эта функция не имеет,
она просто убивает сенсор и нужна только для деактивации llSensorRepeat.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
run_time_permissions(integer permission) Это событие срабатывает каждый раз,
когда чей-нибудь скрыпть пытается запросить функции, не надлежащее применение которых чревато некислыми проблемами.
Атрибут integer permission – возвращает значение обозначающее, шо именно хочет от нас скрипт.
Для активации события используетсця функция llRequestPermissions(key avatar, integer permissions);
Вот, сопсна полный список значений атрибута integer permission:
0 он же ”от ворот поворот” – более компактный ЛСЛ-овский аналог Русского "трёхбайтного адреса" типа string, куда посылают тех, кому не следует лезть не в свои дела…
По русски говоря,- если скрипт получил подобный ответ, то это значит, что права на выполнение мониторинга ему не предоставлены.
1 он же ”хрен знает что” – упоминание об этом значении есть в ЛСЛ-педии, а вот, накой оно нужно не написано.
2 он же PERMISSION_DEBIT – Самый верный способ расстаться с вашими кровными L$,
дать эти прва скрипту (особенно если он самопальный и сильно глючащий), поскольку активация этого атрибута даёт скрипту возможность платить из вашего кармана, но без вашего участия.
Частенько используетсця в вендорах – если покупатель по недосмотру переплатил за товар, то скрипт возвращает лишнее обратно или,
когда необходимо разделить полученные от продажи товара деньги между несколькими людьми.
При запрашивании всегда выползает режущее глаза кислотно-оранжевое окошко с предупреждением.
Права может спрашивать только принадлежащий вам скрипт, чужие скрипты автоматически шлются по ”трёхбайтному адресу”.
Давайте подробней рассмотрим, как этот параметр вызываетсця:
llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
псевдокод:
ллЗапроситьПрава(запросить у ллВзятьХозяина(), какие именно ПРАВА_НА_ОСУЩЕСТВЛЕНИЕ_ПЛАТЕЖЕЙ);
Эти права нужны, в основном, для использования функций llSetPayPrice(integer price, list quick_pay_buttons) и llGiveMoney(key destination, integer amount).
llSetPayPrice(integer price, list quick_pay_buttons) – первый параметр(integer price) указывает цену продукта, а второй(list quick_pay_buttons) величину суммы,
на кнопках ”быстрого платежа” в специальном окне, которое выползает при покупке.
llGiveMoney(key destination, integer amount) – первый параметр(key destination), указывает ключ того,
кому надо заплатить, ну а второй(integer amount), соответственно, указывает, сколько надо заплатить.
***
4 он же – PERMISSION_TAKE_CONTROLS – этот параметр позволяет скрипту идентифицировать клавиши управления нажимаемые вами.
Используется в основном в транспорте и АО-шках. Может запрашиваться сторонними скриптами.
Давайте подробней рассмотрим, как этот параметр вызываетсця:
llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);
псевдокод:
ллЗапроситьПрава(запросить у ллВзятьХозяина(), какие именно ПРАВА_НА_ИДЕНТИФИКАЦИЮ_КЛАВИШ);
Если run_time_permissions вернул 4, значит разрешено срабатывание события control, которое мы рассмотрим сразу, после этого события.
***
8 он же – PERMISSION_REMAP_CONTROLS – на данный момент её работа не реализована, но константа, тем не менее есть.
***
16 он же – PERMISSION_TRIGGER_ANIMATION – запрашивает разрешение на проигрывание анимации.
Не ваши скрипты или не приаттаченные к аватару вещи выводят окошко с запросом, приаттаченные же могут его и не выводить, так шо прежде, чем взять от кого-то халявный АО рекомендую сперва посмотреть анимации, которые в нём лежат, просто есть такие штуки,
которые заворачивают ноги аватара за уши и оставляют его в таком положении (лечится это правда довольно просто, надо перезапустить клиент СЛ, но тем не менее всёравно не сильно-то приятно). Может запрашиваться сторонними скриптами.
Давайте подробней рассмотрим, как этот параметр вызываетсця:
llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
псевдокод:
ллЗапроситьПрава(запросить у ллВзятьХозяина(), какие именно ПРАВА_НА_ПРОИГРЫВАНИЕ_АНИМАЦИИ);
Эти права нужны, для того, чтобы работала функция llStartAnimation(string anim_name);
***
32 он же – PERMISSION_ATTACH – запрашивает разрешение на ”добровольно-принудительное” приаттачивание лежащего НЕ В ИНВЕНТАРЕ объекта к вашей тушке. В некоторых случаях может выдавать окошко с прозьбой, а в некоторых и не выдавать…
Может использоваться, только принадлежащими вам скриптами (правда, некоторые, особо подкованные, всё-таки как-то умутняются
прикреплять аттачменты к аватарам без их ведома…).
Давайте подробней рассмотрим, как этот параметр вызываетсця:
llRequestPermissions(llGetOwner(), PERMISSION_ATTACH);
псевдокод:
ллЗапроситьПрава(запросить у ллВзятьХозяина(), какие именно ПРАВА_НА_ПРИКРЕПЛЕНИЕ_ВЕЩИ_К_ТУШКЕ);
Эти права нужны, для того, чтобы работали функции llAttachToAvatar(integer attach);, llDetachFromAvatar();, integer llGetAttached();.
llAttachToAvatar(integer attach) - позволяет приаттачить какую-либо вещь к тушке. В параметр attach надо вписать константу нужной части тела
(все константы можно найти тута).
llDetachFromAvatar() - как явствует из названия, снимает содержащую вещь скрипт с аватара.
Некоторые используют эту функцию, как систему демонстрации каких-либо вещей, то есть дают бесплатно полнофункциональный, ну ствол допустим, а в него вшивают скрипт, который по прошествии определённого времени снимает эту вещь с аватара и не даёт надеть её в последствии, а при попытке выкинуть вещь из инвентаря для просмотра тут же уничтожает вещь. В результате, единственное место, где она может существовать, это у вас в инвентаре, как говорится – висит груша, нельзя скушать.
Код демо-скрипта (тока учтите, мало кому такие рекламные акции нравятся и много кто может накатать репорт на вас за подобное):
integer Demo_time=600; //Время в секундах, которое аватар должен носить вещь одетой.
integer time; //Сколько прошло времени с момента первого одевания.
integer restricter=0;
//Триггер-халявовырубальник.
default
{
state_entry()
{
llSetTimerEvent(1.0); //Включить таймер (интервал 1 секунда).
}
timer()
{
time++; //При каждом срабатывании таймера, увеличивать эту переменную на 1.
if(time>=Demo_time) //Если счётчик равен или превышает предельно допустимое время...
{
restricter=1; //...то поставить отрубильнику значение 1.
llDetachFromAvatar(); //Снять вещь с аватара.
}
}
attach(key attached) //Если вещь приаттачили к аватару.
{
if(restricter!=0) //Если отрубильник не равен 0...
{
llDetachFromAvatar();//...то снять вещь с аватара.
}
else{} //Если же отрубильник нулю не равен – ничего не делать.
}
on_rez(integer start_param) //Если вещь выложили
{
if(restricter!=0) //Если отрубильник не равен 0...
{
llDie(); //...то уничтожить вещь.
}
else{} //Если же отрубильник нулю не равен – ничего не делать.
}
}
llGetAttached() – возвращает константу, говорящую на какой части аватара закреплёна данная вещь
(полный список констант, можно посмотреть вот тута).
***
64 он же – PERMISSION_RELEASE_OWNERSHIP – сей параметр раньше позволял делать вещь доступной для редактирования всем желающим.
Нынче свобода всеобщего редактирования накрылась медным тазом, а вот константа, тем не менее, осталасць.
***
128 он же – PERMISSION_CHANGE_LINKS – запрашивает разрешение на линковку/разлинковку примов.
Давайте подробней рассмотрим, как этот параметр вызываетсця:
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
псевдокод:
ллЗапроситьПрава(запросить у ллВзятьХозяина(), какие именно ПРАВА_НА_ЛИНКОВКУ/РАЗЛИНКОВКУ_ПРИМОВ);
Эти права нужны, для того, чтобы работали функции llCreateLink(key target, integer parent), llBreakLink(integer linknum), llBreakAllLinks().
Давайте подробнее рассмотрим, как эти функции используются:
llCreateLink(key target, integer parent) – первый параметр(key target), это ключ прима КОТОРЫЙ должен быть прилинкован к нашему.
Второй параметр(integer parent), это номер родительского прима (если кто забыл, номер родительского прима в группе и прима вне группы не есть одно и то же).
После линковки, скрипт в течении одной секунды не сможет выполнять какие-либо операции (это называется задержка, прошу обращать внимание имеет ли нужная вам функция задержку или нет и какую именно).
llBreakLink(integer linknum) – эта функция вытаскивает прим, указанный в integer linknum из группы и смещает номера примов, которые стояли после извлечённого на 1 (то есть – вытянули мы, допустим 5-й по счёту прим из группы, значит 6-й станет 5-ым, 7-й 6-ым, и т.д.)
Ну, а llBreakAllLinks(), как явствует из названия разбивает вообще всю группу на отдельные примы.
***
256 он же – PERMISSION_CHANGE_JOINTS - запрашивает разрешение на смену ”места дислокации” аттачмента.
То есть – если топор был воткнут в репу, то теперь он красуется в том месте, откуда у некоторых растёт хвост…
Принцип использования аналогичен использованию функций PERMISSION_ATTACH.
***
512 он же – PERMISSION_CHANGE_PERMISSIONS – запрашивает разрешение на смену… э… разрешения…
По Русски говоря, если скрипт перехватывал, допустим, клавиши ввода и ему вдруг потребовалось проиграть анимацию, а прав на её проигрывание у скрипта нету, то с помощью этой константы их можно переназначить.
Может использоваться, только принадлежащими вам скриптами.
***
1024 он же - PERMISSION_TRACK_CAMERA – запрашивает разрешение на отслеживание положения и угла поворота камеры.
Эти права нужны, для того, чтобы работали функции vector llGetCameraPos() и llGetCameraRot().
***
2048 он же - PERMISSION_CONTROL_CAMERA – а этот параметр запрашивает разрешение на принудительную установку камеры в определённое положение (в машинах катались? Вот там иногда камеру приходится устанавливать).
Рассмотримка фунции, для которых нужны эти права:
llSetCameraAtOffset(vector offset) – эта функция устанавливает точку, указывающуюся в координатах региона, на которую смотрит камера, когда аватар садитсця на содержащий этот скрипт объект.
llSetCameraEyeOffset(vector offset) – эта функция делает то же, что и
предыдущая, с той лишь разницей, что работает она, только,
когда аватар не сидит ни на чём. Константа ZERO_VECTOR (<0,0,0>)
отменяет действие этого параметра. Координаты этой и предыдущей функции совпадать НЕ ДОЛЖНЫ.
llReleaseCamera(key agent) – эта функция ”отпускает” камеру аватара, чей ключ прописан в параметре key agent.
llSetCameraParams(list rulllz) – О! А вот эта функция задаёт сразу несколько параметров в виде листа.
Поскольку эта функция не единственная, использующая подобную систему, думаю будит чрезвычайно полезно понять, как и какие параметры можно тута задать.
После каждого параметра необходимо ввести через запятую определённое значение.
Сопсна, вота и сами параметры:
0 он же CAMERA_PITCH – Э… судя по описанию добавляет к чему-то, какой-то угол.
Судя по экспериментам - не совсем понятно, зачем этот угол нужен… Диапазон от -45 до 80 градусов.
1 он же CAMERA_FOCUS_OFFSET – Смещает вектор поворота камеры на указанное количество метров относительно точки фокусировки.
Может принимать значения от <-10,-10,-10> до<10,10,10>.
5 он же CAMERA_POSITION_LAG – Заставляет переходить камеру с одной позиции на другую в течении указанного количества секунд.
Может принимать значения от 0 до 3
6 он же CAMERA_FOCUS_LAG – На сколько должна запаздывать фокусировка камеры.
Похожий приём применяется в некоторых фильмах, видели наверное сцены, когда герою говорят что пугающее, он делает морду лица, а ля ”ой-боюсь-боюсь”, а фоновые декорации в Это время как будто приближаются к герою (на самом деле, просто меняется угол фокуса камеры). Вот это и называется запаздывающая фокусировка. Может принимать значения от 0 до 3 секунд.
7 он же CAMERA_DISTANCE – Устанавливает как далеко должна быть камера от своей ”цели”.
Может принимать значения от 0.5 до 10 метров. Если больше 0.5, то блокирует параметр CAMERA_POSITION.
8 он же CAMERA_BEHINDNESS_ANGLE – Устанавливает, на какой угол может поворачиватьсця камера за спиной аватара.
Может принимать значения от 0 до 180 градусов (поскольку угол больше 180, это, как вы сами понимаете уже не ”за спиной”).
9 он же CAMERA_BEHINDNESS_LAG – Устанавливает, насколько сильно камера привязана к объекту.
В переводе на русский означает следуюшчее, если самолёт, в котором вы сидите вдруг резко повернулся на 45 градусов в лево и значение параметра
больше нуля, то камера перейдёт в новую позицию не сразу, а в течении указанного количества секунд. Приминает значения от 0 до 3.
10 он же CAMERA_POSITION_THRESHOLD – Указывает радиус (в метрах) от позиции камеры на расстоянии которого, повидимому не происходит фокусировка, если вдруг, позиция точки фокуса оказалась ближе (хотя помоему этот параметр, равно,
как и следующий врядли кому-то пригодятся, поскольку, для задания движения камеры через подобные параметры, надо быть либо Эйнштейном, либо Спилбергом Х______________х ). Предельные значения от 0 до 4.
11 он же CAMERA_FOCUS_THRESHOLD – Полный аналог предыдущего атрибута, с той лишь разницей, что радиусц устанавливаетсця не относительно координат камеры, а относительно координат точки фокусировки.
12 он же CAMERA_ACTIVE – после этого параметра через запятую пишется параметр, который включает/выключает скриптовое управление камерой. Может принимать значения TRUE и FALSE.
13 он же CAMERA_POSITION – По идее, должен ставить камеру в позицию указанную в координатах региона…
по факту изменять положение камеры можно, только, если параметр CAMERA_DISTANCE равен 0.5, правда, даже в этом случае,
дальше 10 метров от аватара, камера уезжать почему-то категорицски нихатит.
17 он же CAMERA_FOCUS – Устанавливает ”точку прицела” камеры в указанную в региональных координатах позицию.
21 он же CAMERA_POSITION_LOCKED – если значение этого параметра не равно ТРУЪ, то вместо пусть и довольно быстрого, но всё же плавного перехода, камера будит резко перепрыгивать между озициями.
Может принимать значения TRUE и FALSE.
22 он же CAMERA_FOCUS_LOCKED – То же, что и предыдущее, только применительно к целевой точке камеры. Значения те же
Порядок расположения параметров в подобных функциях абсолютно не важен, как и количество этих параметров. Если какой-то из перечисленных параметров не вписан, то ему будит присвоено дефолтное значение (как правило это 0).
llClearCameraParams() - ставит камере дефолтные атрибуты.
llTakeControls(integer controls, integer accept, integer pass_on) эта функция, при получении прав, перехватывает клавиши управления…
Верней, не перехватывает, а передаёт информацию, о том, какие клавиши нажал пользователь в событие Control.
Атрибуты у неё следующие:
integer controls – здесць указываетсця, о нажатии каких именно клавиш управления скрипт должен знать.
Нужные параметры вводятсця через вертикальную черту ( | ):
1 он же CONTROL_FWD – этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши вперёд.
2 он же CONTROL_BACK - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши назад.
4 он же CONTROL_LEFT - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши влево.
8 он же CONTROL_RIGHT - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши вправо.
16 он же CONTROL_UP - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши прыжок
(она же – лететь вверх).
32 он же CONTROL_DOWN - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши присесть
(она же лететь вниз).
256 он же CONTROL_ROT_LEFT - этот параметр сообщает скрипту, что должен перехватываться ПОВОРОТ влево.
512 он же CONTROL_ROT_RIGHT - этот параметр сообщает скрипту, что должен перехватываться ПОВОРОТ вправо.
268435456 он же CONTROL_LBUTTON - этот параметр сообщает скрипту, что должно перехватываться нажатие левой кнопки мыши.
1073741824 он же CONTROL_ML_LBUTTON - этот параметр сообщает скрипту, что должно перехватываться нажатие клавиши левая кнопка мыши,
правда, тока в том случае, когда аватар находитсця в виде от первого лица.
integer accept – не совсем понятный параметр. Принимает значеня TRUE и FALSE.
integer pass_on – не совсем понятно, зачем это нужно, но лучше всегда тут ставить значение TRUE.
Принимает значения TRUE и FALSE.
Для того, шобы убрать контроль кнопок, используетсця функция llReleaseControls(key avatar).
Параметр key avatar, как явствует из названия, должен содержать ключ того, кого скрипт, сопсна, контролил.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
сontrol(key name, integer levels, integer edges) это событие срабатывает, когда получено разрешение на фиксирование клавиш управления.
key name – выдаёт ключ того, чьи клавиши управления фиксируются.
integer levels – выдаёт цифру, соответствующую определённой константе (константы смотрим выше, это, которые CONTROL_FWD и т.п.)
integer edges – выдаёт цифру, соответствующую константе предыдущей нажатой клавиши управления.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
money(key giver, integer amount) – это событие срабатывает, когда вы заплатили приму, включающему в себя данный скрипт энную сумму L$.
key giver – выдаёт ключ того, кто эту сумму заплатил.
integer amount – ну, а этот атрибут выдаёт, скока именно заплатили.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
attach(key attached) – это событие срабатывает каждый раз, как только вы вешаете объект на себя.
key attached – выдаёт ключ того, на ком ”повесился” объект.
Используетсця в связке с приведёнными в PERMISSION_ATTACH Функциями.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
А вот эти вота события мы рассмотрим, шо называетсця, сразу всей кучей, потому, что применяютсця они как правило в связке.
moving_start() – это событие срабатывает, когда объект начинает двигатьсця (даже, если это аттачмент).
***
moving_end() – ну, а енто, соответсна, когда движение заканчиваетсця.
***
at_target(integer tnum, vector targetpos, vector ourpos) - это событие активируетсця, когда объект прибывает в указанную точку (цель).
integer tnum – этот атрибут возвращает порядковый номер цели. Она нужна, для того, чтобы скрипт знал номер данной цели
и используетсця, в основном, если целей несколько.
vector targetpos – это, сопсна, сама конечная позиция, которая указываетцо в llTarget.
vector ourpos – а тута возвращается сейчасошняя позиция прима.
А теперь хлянем, шо за функция вызывает это событие.
llTarget(vector pos, float range).
vector pos – тута указывается целевая точка по пришествии в которую срабатывает событие at_target.
float range – это радиус от целевой точки (в метрах), при попадании в который срабатывает событие at_target.
Так же для облегчения задачи доползания прима до цели, используют фунуцию llSetBuoyancy(float value), которая, если тама выставить значение 1.0 заставляет физический объект парить в воздухе (ента шо-та типа параметра гравитации, если он равен 0, то объект падает вниз, а если 2, то… угу правильно - вверх).
Для удаления цели (и как следствие – прекращения срабатывания событий at_target и not_at_target) используют функцию llTargetRemove().
***
not_at_target() – это событие срабатывает, всё время, пока прим не находитсця в целевой точке.
***
at_rot_target(integer number, rotation target_rotation, rotation our_rotation) – это событие срабатывает, когда прим поворачиваетсця до целевого угла.
integer number – как и в случае с llTarget этот атрибут показывает порядковый номер текущего целевого поворота.
rotation target_rotation – тута возвращаетсця конечный угол.
rotation our_rotation – ну, а тута текущий.
***
not_at_rot_target() – а это соответственно, когда целевой угол ещё не достигут.
А вота сопсна функция, которая вызывает срабатывание события at_rot_target и not_at_rot_target:
llRotTarget(rotation rot, float error).
rotation rot – указывает точный кватернионный угол, при повороте на который сработает событие at_rot_target.
float error – а тута устанавливаетсця угловой промежуток (в радианах) при попадании в который событие at_rot_target так же срабатывает (вспоминаем картинку от llSensor, вот красный конус, это и есть угловой промежуток).
А вот тута, шобы от вышеприведённого ”объяснения” у вас не случилсця вывих или перелом моска, пожалуй объясню шо из себя представляют кватернионы, а заодно и в чём разница, между глобальной системой координат и локальной:
Кватернион, в контексте SL,– это угол поворота по трём осям выраженный в четырёх координатах.
Э… а почему именно в четырёх? =О.о=
При повороте объекта на определённый угол по трём координатам, каждая из которых представляется в виде десятичной дроби, поворот не всегда получается точным, а после нескольких поворотов, как правило, всегда получается не точным ввиду того, что некоторые знаки десятичных дробей приходится округлять.
Э… пожалуй объясню принцип образования неточности более простым примером – все мы знаем, что в сутках не 24 часа, а 23 часа, 56 минут и 58 с копейками секунд.
Дык вота, из этих трёх с копейками минут каждые четыре года набегают ”лишние” сутки. Связано это отнюдь не с тем, что сутки такие неровные, а с тем, что создателя нашего сейчасошнего календаря, к большому сожалению, вовремя не сожгла на костре средневековая инквизиция.
Поэтому сутки округляют до целого числа, для удобства счёта. Однако… как бы хто не хотел, но с реальными сутками всё-таки считаться приходится, шобы по прошествии определённого времени январь, вдруг ”внезапно” не начался в июле… Поэтому и придумали високосный год, шобы каждые 4 года не происходило смещения дат на 1 сутки.
Вот на примерно таком же принципе и получается не точность в трёх координатной системе поворота.
Э… а шо тама может случиться-то? Там всего-то и надо, шо повернуть кубик на определённый угол…
Угу, тока это элементарный случай, а вот если надо заранее рассчитать маршрут, ну допустим прохождения ядерной ракеты к ”пятой точке” постоянно бегающего аватара, да так, чтобы ракета ещё и не впечаталась в первую стенку (и во все последующие по возможности тоже), то тута уже приходится оперировать переменными, которые могут быть как целым числом (шо бывает крайне редко), так и дробями. Тобиш – их надо делить, умножать, складывать, вычитать и т.п.
Внимание, вопрос – уместится ли в 7 знаков (то есть в переменную типа float) результат деления, ну например,
угла 139,9868 на угол 68,75541 ? =О.о=
Сесна, тута придётся округлять, причём округлять не кисло. А если подобные операции проводятся с частотой раз в каждые 0.1 секунды
и погрешность округления составляет 2%, то уже меньше, чем через пол минуты полёта, погрешность будит равна 100%.
Дык вота… для этого и придумали нормированный кватернион. Все углы в нём выражаются в диапазоне от 0.000000 до 1.000000 в тех же самых трёх координатах, с одной лишь разницей – кватернион имеет стабилизирующую все три угла четвёртую координату.
Вот вам примеры нескольких кватернионов для наглядности:
<1.000000,0.000000,0.000000,0.000000>
<0.000000,0.500000,0.000000,0.500000>
<0.500000,0.000000,0.000000,0.500000>
<0.000000,0.000000,0.000000,1.000000> он же ZERO_ROTATION.
То есть, как мы видим, при повороте по какой-то одной оси, угол поворота нормируется четвёртым параметром.
Правда при повороте сразу по нескольким осям число в нормирующей координате будит рассчитываться уже по определённым формулам.
Для того, чтобы перевести градусный вектор в кватернион, можно использовать следующую формулу:
rotation angle=llEuler2Rot(<65,23,58>*DEG_TO_RAD);
Поясню, как работает эта формула - функция llEuler2Rot, как явствует из её названия переводит угол в кватернион, НО!
Переводит она тока угол представленный в радианах, поэтому угол внутри скобок умножается на константу DEG_TO_RAD.
А для перевода кватерниона обратно в вектор, вот такую вота:
vector angle=(llRot2Euler(<0.000000,0.000000,0.000000,1.000000>))/DEG_TO_RAD;
Ну а тут, всё с точностью до наоборот. Кватернион переводится в радианный вектор, а потом делится на ГРАДУСЫ_В_РАДИАНЫ.
Теперь объясню, шо такое глобальная и локальная ось (это полезно знать тем, кому надо сделать вещь, в которой примы перемещаются или поворачиваются с помощью скриптов).
Глобальная ось координат – это ось координат сима, в этой координатной системе все оси фиксированы и задают местоположение объектов
внутри этой системы координат.
Локальная ось – это координатное пространство одного конкретного объекта (в группе объектов нулевая точка координат перемещения равна позиции главного прима, а локальный поворот дочерних примов,- это угол поворота дочернего объекта относительно главного).
Если повернуть или переместить этот объект по глобальной оси, то локальные координаты всех примов включённых в группу объекта останутся теми же самыми.
integer num – это порядковый номер цели.
Для того, чтобы выключить срабатывание событий at_rot_target и not_at_rot_target используется функция llRotTargetRemove(integer num).
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
dataserver(key id, string data) – это событие срабатывает при запросе информации о каком-либо объекте через определённые функции (ну и, выдаёт запрашиваемую инфу).
key id – этот атрибут возвращает ключ того, чью информацию запрашивали.
string data – этот атрибут возвращает саму информацию.
А вот и сами запрашивающие функции:
llGetNotecardLine(string name, integer line) – эта функция позволяет скрипту брать данные из ноут-карты лежащей там же,
где и сам скрипт.
string name – это имя ноут-карты.
integer line – это номер строки, которую надо взять.
llGetNumberOfNotecardLines(string name) – эта функция позволяет узнать, сколько всего строк в ноут-карте.
string name – это имя ноут-карты.
llRequestAgentData(key id, integer data) – эта функция запрашивает определённую информацию о конкретном аватаре.
key id – тут указываетсця ключ аватара, о котором надо взять информацию.
integer data – тута указывается тип запрашиваемой информации.
Сопсна, сами типы:
1 он же DATA_ONLINE – с помощью этой константы можно узнать в СЛ аватар в данный момент или нет.
В событие dataserver вернётся, либо 0 (означает аватар не в сети), либо 1 (значит в сети).
2 он же DATA_NAME – спомощью этого параметра, можно узнать полное имя аватара
(без учёта фсяких групп и пр.). Не совсем понятно, накой сей параметр кому-то сплюсцнулся, если есть функция llKey2Name(key UUID), которая, в отличии от датасервера возврашает полное имя чего угодно по указанному в key UUID ключу без задержек.
3 он же DATA_BORN – с помощью этого параметра можно узнать дату регистрации аккаунта.
Выведется она в формате год(4 знака)-месяц(2 знака)-число(2 знака).
4 он же DATA_RATING – раньше эта константа возвращала общий рейтинг ваших построек, вас,
и вашего аватара, после ликвидации системы рейтингов всегда возвращает шесть нулей.
8 он же DATA_PAYINFO – с помощью этого параметра, можно узнать о том,
заполнена ли у вас платёжная форма или нет и покупаете ли вы L$ (или же платный у вас аккаунт или нет).
0 – означает, что платёжная форма заполнена,
1 – значит, что L$ вы покупаете, или у вас платный аккаунт,
2 – это атавизм оставшийся со времён бета-теста – означает, что платёжная форма не заполнена, но аккаунт у вас тем не менее платный,
3 – означает, шо и платёжная форма заполнена и L$ вы покупаете (или у вас платный аккаунт).
llRequestInventoryData(string name) – эта функция запрашивает данные об объектах инвентаря.
Правда по факту данные можно получать только с лендмарок, функция возвращает в string name векторную координату места,
в которое должен телепортироваться аватар.
llRequestSimulatorData(string sim, integer data) – эта функция запрашивает данные о Симе.
string sim – ну, тута вроде из названия понятно, шо она делает – сюда вписывается имя Сима.
integer data – а сюда вписывается один из параметров, указывающих какой именно тип данных запрашивается:
5 он же DATA_SIM_POS – возвращает вектор абсолютной (не путать с глобальной) позиции сима.
6 он же DATA_SIM_STATUS – запрашивает статус сима.
Типы ответов на запрос статуса сима:
"up" – означает, что сим работает.
"down" - означает, что сим не работает.
"starting" - означает, что сим начанает работу.
"stoping" - означает, что сим останавливается.
"crashed" - означает, что сим "выпал в осадок".
"unknown" – означает ХЗ.
7 он же DATA_SIM_RATING – запрашивает рейтинг сима, каторый бывает "PG", "MATURE", "ADULT" и "UNKNOWN".
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
email(string time, string address, string subj, string message, integer num_left) – это событие срабатывает, когда получен ответ от функции llGetNextEmail.
Атрибуты события:
string time – тута возвращается, так называемый, временной штамп в виде интегера.
string address – тут возвращается адрес отправителя(не должно быть больше 78 знаков).
string subj – тут возвращаетсця тема письма (не должно быть больше 78 знаков).
string msg – тута возвращается само сообщение(не должно быть больше 1000 знаков).
integer num_left – тут возвращается количество оставшихся сообщений.
Рассмотрим функцию вызывающую это событие:
llGetNextEmail (string address, string subject) – эта функция нужна для просмотра поступившего из Ё-нэта в прим мыла, угу, и так тоже можна у каждого прима езь сопсный, условно говоря ”ящик” его адрес равен ключу прима + @lsl.secondlife.com, но… имейте в виду, шо больше 100 не просмотренных писем в приме утрамбоватсця не может (они просто не доползают до адресата).
string address – это мыло, отправителя.
string subject – ну, а тут надо вписать тему письма.
Для просмотра писем по порядку можно оставить параметры string address и string subject пустыми, они нужны если заранее знаешь, чьи письма надо просмотреть в первую очередь.
Кстати: письмо можна послать и из СЛ Каму-нить на мыло, Посылаетсця оно функцией llEmail(string addres, string tema, string text)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http_response(key request_id, integer status, list metadata, string body) – это событие срабатывает при получении ответа от функции llHTTPRequest.
key request_id – тут возвращается ключ функции вызвавшей данное событие.
integer status – тут возвращается http-статус (подробнее о том, что это такое на более-менее понятном языке можно почитать тута).
list metadata – возвращает данные в виде <константа, номер> - тип константы на данный момент всего один - HTTP_BODY_TRUNCATED - означает, что данные в следующем атрибуте обрезаны,
а число обозначает, сколько конкретно байт обрезано.
string body – ну, а тута возвращается текст самой страницы (не более 2048 символов).
Ну а теперь, давайте рассмотрим вызывающую данное событие функтцыю:
llHTTPRequest(string url, list params, string body)
string url – тут указывается адрес страницы, с которой надо взять текст.
list params – в этом листе задаются в виде листа параметры запроса:
0 он же HTTP_METHOD – после этой константы, через запятую пишется определённая команда, которая ”по идее” должна говорить скриптам сайта,
какие действия он должен выполнять.
”GET” – получить. Параметр string body в этом случае не должен быть длиннее 254 символов, поскольку он приписывается к адресной строке,
а в событие http_response приходит ответ... или не приходит, зависит от правилности написанного адреса, параметра, и желания сервера этот ответ дать.
”POST” – послать(добавить)
”PUT” – добавить(или если там уже что-то есть, то обновить)
”DELETE” – удалить
Поскольку ллХТТПРеквест только посылает и принимает запросы, но сам с ними ничего не делает, в параметр типа ”POST”, можно упихать всё необходимое для отправки (а с ”GET”, соответсна для получения информации), ПУТ и ДЕЛЕЙТЕ как правило не используются, просто из за того, что сами эти команды не более, чем обычные символы и стирать или обновлять они, если серверу (то есть принимающей информацию стороне) на их счёт не дано инструкций, сесна ничего не смогут.
1 он же HTTP_MIMETYPE – указывает на то, что в параметре string body лежит обычный текст.
2 он же HTTP_BODY_MAXLENGTH – пока не поддерживается, но по задумке должен добровольно-принудительно устанавливать размер ”тушки” приходящего в http_response ответа.
3 он же HTTP_VERIFY_CERT – ента штука нужна, только для параноиков при подключении использующем шиферование данных.
Для сайтов существует специальный сертификат соответствия, дык вота, если хотите его проверить, то здесь надо ставить 1,
если же не хотите ломать моск, то 0.
string body – ну а тут, в зависимости от параметров должен валяться либо отправляемый текст
(если предыдущий параметр у вас HTTP_MIMETYPE), либо параметр, который приписывается к адресной строке
(если стоит HTTP_METHOD, ”GET”).
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
remote_data(integer event_type, key channel, key message_id, string sender, integer idata, string sdata)
Данное событие вызывается так называемым XML-RPC запросом.
Шо это такое, спрашиваете? Э… это чрезвычайно плющно-глюкавый запрос, который генерируется спомощью специального кода лежащего на каком-либо сайте.
Значения параметров:
integer event_type – тут указывается тип поступивших данных.
1 он же REMOTE_DATA_CHANNEL – означает, что канал успешно создан. Никакой инфы, которая не относится к запросу при этом не приходит
(активируется функцией llOpenRemoteDataChannel(), или вернее функция посылает запрос наружу, а ”наружа” уже присылает сюда ответ).
2 он же REMOTE_DATA_REQUEST – означает, шо пришёл ответ в виде данных.
key channel – тута возвращаетсця ключ канала, который был открыт.
key message_id – ID сообщения. При event_type равном 1 или 2 – ключ равен NULL_KEY.
string sender – всегда равно ”” тобиш тама фсегда пусто.
integer idata – если в event_type стоит REMOTE_DATA_CHANNEL, то этот параметр равен нулю, в любом другом случае тута приходит определённая отправителем цифра.
string sdata – ну а тута приходят сами данные запроса, которые не должны превышать 256 символов.
Вот такие, вота блины.
Следующий урок










