пятница, февраля 29, 2008

Тестирование типа переменной instanceof. AS2

Лучший способ проверить тип переменной: instanceof.
Однако, необходимо учитывать, что результат тестирования наследника и родителя быдет один и тот же. Поэтому, если необходимо отличить наследника от родителя, нужно тестировать объект на предмет причастности к наследнику.

Например, нам нужно проверить, что переменная является не массивом, а объектом (Array является наследником Object):
Пишем:
var a={a:1,b:2,c:3};
trace(a instanceof Object);
// true.
Всё отлично.
var a=[1,2,3];
trace(a instanceof Object);
// true.
А это уже не приемлемо.

Пробуем проверить на непричастность к Array:
var a={a:1,b:2,c:3};
trace(!(a instanceof Array));
Всё отлично.
var a=[1,2,3];
trace(!(a instanceof Array));
// false.
Вот теперь всё верно.

четверг, февраля 28, 2008

Про EventDispatcher. AS2

Повторение - мать учения.

Как использовать EventDispatcher:

Класс объекта, посылающего события:
import mx.events.EventDispatcher;

/**
* Класс отправителя события
*/
class Sender {

/**
* Идентификатор события
*/
static public var EVENT_TYPE:String="event_type" ;

/**
* Добавить слушателя
*/
public var addEventListener:Function;

/**
* Удалить слушателя
*/
public var removeEventListener:Function;

/**
* Генерировать событие
*/
private var dispatchEvent:Function;

/**
* Конструктор
*/
function Sender() {
EventDispatcher.initialize(this);
}

/**
* Послать событие
*/
public function dispatch() {
this.dispatchEvent({type:EVENT_TYPE});
}
}


Класс объекта, принимающего события:
import mx.utils.Delegate;

/**
* Класс обработчика события
*/
class Receiver {

/**
* Отправитель события
*/
private var __sender:Sender;

/**
* Реестр событий
*/
private var __handlers:Array;

/**
* Конструктор
*/
function Receiver() {
this.__sender=new Sender();
this.__handlers=new Array();
this.addEventListener(Sender.EVENT_TYPE,this.__sender,this,this.onEventType1);
this.addEventListener(Sender.EVENT_TYPE,this.__sender,this,this.onEventType2);
}

/**
* Обработчик события
*/
private function onEventType1(event:Object):Void {
trace("onEventType handler1"+event.type);
}

/**
* Другой обработчик события
*/
private function onEventType2(event:Object):Void {
trace("onEventType handler2"+event.type);
}

/**
* Метод тестирования обработки событий
*/
public function testDispatch() {
trace("Testing ...");
this.__sender.dispatch();
this.removeEventListener(Sender.EVENT_TYPE,this.__sender,this,this.onEventType1);
trace("Handler 1 removed ...");
this.__sender.dispatch();
this.removeEventListener(Sender.EVENT_TYPE,this.__sender,this,this.onEventType2);
trace("Handler 2 removed ...");
this.__sender.dispatch();
trace("Finish ...");
}

/*
*
*
* Методы управления обработчиками событий.
* Это пример. Управление лучше поручить специальному классу
*
*
*/

/**
* Подписаться на прослушивание события
*
* @param event Событие
* @param sender Объект-отправитель
* @param receiver Объект-получатель
* @param handler Метод-обработчик
*/
public function addEventListener(event:String,sender:Object,receiver:Object,handler:Function) {
var delegated_handler:Function=Delegate.create(receiver,handler);
this.__handlers.push({event:event,sender:sender,receiver:receiver,handler:handler,delegated_handler:delegated_handler});
sender.addEventListener(event,delegated_handler);
}

/**
* Отписаться от прослушивания события
*
* @param event Событие
* @param sender Объект-отправитель
* @param receiver Объект-получатель
* @param handler Метод-обработчик
*/
public function removeEventListener(event:String,sender:Object,receiver:Object,handler:Function) {
var i:Number=0;
while (i<this.__handlers.length) {
if ((this.__handlers[i].event==event)&&
(this.__handlers[i].sender==sender)&&
(this.__handlers[i].receiver==receiver)&&
(this.__handlers[i].handler==handler)) {
sender.removeEventListener(event,this.__handlers[i].delegated_handler);
this.__handlers.splice(i,1);
} else
i++;
}
}

}


ВАЖНО: Если объект Sender является MovieClip-ом, то в приведенном выше коде событие не отрабатывается. Для того, чтобы событие сработало, необходимо подписываться на него(вызывать addEventListener) не из конструктора! а из обработчика onLoad().

* * *

ОБНОВЛЕНИЕ: Добавление обработчика с использованием Delegate усложняет его удаление всвязи с тем, что при делегировании возвращается новая функция обработчика (см. комментарии). Для отписывания можно просто запомнить новый обработчик в переменную и потом ее использовать для отписывания:
sender.addEventListener(EVENT_TYPE,this.__event_handler=Delegate.create(this,this.onEventType1));
sender.removeEventListener(EVENT_TYPE,this.__event_handler);

В коде приведен универсальный метод подписывания на прослушивание и отписывания от событий.

Да, чуть не забыл. Для тестирования в таймлайне нужно написать:
this.reciever=new Receiver();
this.reciever.testDispatch();

пятница, февраля 22, 2008

Внутренности Flex Framework. Flex SWF. Flex

Заканчиваем изучать первую часть "Внутренностей Flex Framework".
Всё в чём я сомневаюсь, буду помечать знаком (#?) где #- ID сомнения (для последующего комментирования).

SystemManager


  • Является корневым объектом (Root) SWF.
  • Является классом, инстанцируемым в первую очередь.
  • Контролирует и координирует инициализацию приложения
    - инстанцирует и отображает класс Preloader
    - инстанцирует класс Application
  • Управляет слоями порожденных объектов, отвечающих за всплывающие окна (popups), курсоры и контекстные подсказки (tooltips)
  • Способствует управлению классами в ApplicationDomain-ах

Инициализация Flex SWF

  • SWF Flex-приложения является клипом с двумя фреймами
  • Первый фрейм содержит:
    - SystemManager,
    - Preloader,
    - DownloadProgressBar
    - несколько вспомогательных классов.
  • Второй фрейм содержит:
    - остальные элементы фреймворка,
    - код приложения
    - ассеты (вспомогательные средства) - внедренный шрифт, графика и т.д.
    Кастомные (пользовательские) компоненты и все их ассеты располагаются во втором фрейме.

Инициализация Flex SWF. Frame 1

  • Загружается объем данных, достаточный для активизации первого фрейма
  • Flash Player выполняет полученные данные. При этом:
    - он инстанцирует SystemManager
    - SystemManager командует проигрывателю остановиться на конце фрейма (1?)
    - SystemManager создает Preloader
    - Preloader
    создает DownloadProgressBar
    - Preloader и DownloadProgressBar начинают осуществлять мониторинг загрузки оставшихся данных
    - SystemManager начинает прослушивать событие frameEnd
  • Flash Player останавливается на конце фрейма и продолжает загружать SWF-файл.

Инициализация Flex SWF. Frame 2

  • Как только все данные будут загружены, Flash Player генерирует событие frameEnd
    - SystemManager
    инстанцирует класс Application
    - устанавливает ссылку на себя в свойство Application.systemManager
    - SystemManager начинает прослушивать событие preloaderDone
    - Application
    создает все свои объекты (children)
  • Flash Player начинает посылать событие enterFrame и выполнять события Events
    - LayoutManager
    обрабатывает созданные объекты
  • В конечном счете, приложение (Application (2?)) генерирует событие о завершении своего создания creationComplete
    - Preloader
    начинает удаление DownloadProgressBar
    - Preloader генерирует событие preloaderDone
    - SystemManagers
    добавляет Application в дисплей-лист
    - SystemManagers командует Application генерировать событие applicationComplete

Информация, приведенная выше, ознакомила нас в общих чертах с процессом инициализации Flex-приложения. Если не обращать внимания на пару вопросов, всё предельно ясно.

В контексте темы загрузки и инициализации, хочется еще раз упомянуть создание прелоадера для Flex-приложения. Любопытно, что в описанном этой статьей методе, специально указывается мета-тег для генерации второго фрейма [Frame(factoryClass="MyFactoryClass")]. Если верить "Внутренностям Flex", то на самом деле, мета-тег не "вынуждает" создавать второй фрейм, а лишь объявляет factoryClass, а второй фрейм присутствует по-любому во всех Flex-приложениях.

Продолжение "внутренностей" - вторую часть этого увлекательнейшего документа - мы очень жаждем увидеть у Роста на горячо нами любимом Флэш Потрошителе.

четверг, февраля 21, 2008

Внутренности Flex Framework. Обработка клавиатуры/фокуса. Flex

Продолжаем знакомиться с "внутренностями" Flex.
Статья посвящается обработке клавиатуры и фокуса. Если с клавиатурой всё ясно, то про фокус можно сказать, что речь идет не о фокусах и трюках, а о понятии активности или готовности в данный момент времени какого-либо элемента интерфейса принимать события от клавиатуры.
Всё в чём я сомневаюсь, буду помечать знаком (#?) где #- ID сомнения (для последующего комментирования).

Обработка клавиатуры/фокуса


  • В Flash Player предусмотренны свойства, методы и события для обработки клавиатуры и фокуса. Однако он не имеет встроенных средств, реализующих:
    - составные интерактивные элементы
    - модальность
  • Flex берет на себя (или перекрывает) большую часть возможностей Flash Player по обработке клавиатуры/фокуса
  • Flex добавляет новые интерфейсы и свойства для обработки клавиатуры/фокуса
    - интерфейс IFocusManagerComponent
    - свойство focusEnabled
  • UIComponent обладает всеми свойствами IFocusManagerComponent но не реализует его. Это нужно для того, чтобы можно было разделить компоненты на интерактивные (например, TextInput, DataGrid) и не интерактивные (такие как Label, ProgressBar)

Обработка клавиатуры/фокуса. Основы

  • В обработке клавиатуры/фокуса нет ничего сложного:
    - “implements IFocusManagerComponent”
    - UIComponent.keyDownHandler

public class RandomWalk implements IFocusManagerComponent {
override protected function keyDownHandler(event:KeyboardEvent):void {
switch (event.keyCode) {
case Key.DOWN:
}

  • Если компонент не реализует интерфейс IFocusManagerComponent, то его свойства, относящиеся к обработке фокуса, не имеют никакого действия.
    - Компоненты-контейнеры должны контролировать свое свойство tabChildren (контейнер может не реализовывать интерфейс IFocusManagerComponent, но это свойство позволит обрабатывать изменение фокуса по клавише TAB у вложенных в него объектов)
  • Свойство focusEnabled компонента устанавливает, будет ли FocusManager обрабатывать другие свойства, связанные с фокусом для этого компонента.
    - Используется для выключения обработки фокуса вложенных компонентов, а также для обозначения составных компонентов
  • Свойство tabEnabled компонента устанавливает, будет ли FocusManager, при нажатии клавиши TAB, передавать фокус этому компоненту.
    - при этом необходимо, чтобы у всех компонентов-контейнеров, в которые данный компонент вложен), свойство tabChildren==true
  • Свойство mouseFocusEnabled компонента устанавливает, будет ли FocusManager передавать фокус этому компоненту при клике на него мышью.
    - Если false, то проверяется свойство mouseFocusEnabled компонентов-родителей.

Обработка клавиатуры/фокуса. Композиция

  • Большинство компонентов не являются составными (не используют композицию):
    - Button
    - CheckBox
    - ButtonBar! (3?)
  • У составных компонентов может быть несколько внутренних компонентов с реализацией IFocusManagerComponent.
    Кроме того, составные компоненты могут генерировать внутренние компоненты IFocusManagerComponent динамически.
    При нажатии клавиши TAB, осуществляется навигация между внутренними компонентами IFocusManagerComponent.
    - Например, составными компонентами являются редакторы элементов DataGrid/List/Tree
  • Некоторые компоненты, с точки зрения FocusManager, действительно являются контейнерами.
    - Slider является контейнером бегунков, способных обрабатывать фокус

Обработка клавиатуры/фокуса. Композиция. Slider

  • Не реализует IFocusManagerComponent
  • Устанавливает tabChildren = true
  • Вложенные компоненты - бегунки - реализуют IFocusManagerComponent
  • Предполагается, что легче все же реализовать IFocusManagerComponent чем использовать композицию, и, вероятно, в будущем будет что-то переработано и диалоги tabIndex во FlexBuilder не будут поддерживать такую конфигурацию.(4?)

public class Slider {
public function Slider() {
tabChildren = true;
}
}

public class SliderThumb implements
IFocusManagerComponent


Обработка клавиатуры/фокуса.Реализация композиции

  • Реализовать IFocusManagerComponent
  • В focusInHandler, подписаться на прослушивание события "keyFocusChange"
  • В keyFocusChangeHandler:
    - вызывать preventDefault(), чтобы focusManager не обрабатывал это событие
    - обработать нажатие клавиши TAB и установить фокус внутренним компонентам

public class DataGrid implements IFocusManagerComponent {

override protected function focusInHandler(event:FocusEvent):void {
addEventListener(“keyFocusChange”, keyFocusChangeHandler);
}

protected function keyFocusChangeHandler(event:FocusEvent):void {
event.preventDefault();
itemEditor.setFocus();
}

Обработка клавиатуры/фокуса. Подведение итогов

  • Почти все компоненты, с точки зрения FocusManager были реализованы без композиции.
  • Исключение составляют:
    - Slider
    - List/Tree
    - DataGrid
  • Вероятно, большинство ваших компонентов также не будет иметь дела с композицией.

В статье, у меня возникло одно непонимание - (4?) связанное с композицией Slider. Поэтому фразы "Easier to implement than composites" и "We will probably re-implement as composite in future..." я выразил своими словами. Возможно, я ошибаюсь.

среда, февраля 20, 2008

Внутренности Flex Framework. Жизненный цикл компонента. Flex

Статья Добрался до самого вкусного — внутренности Flex Framework навела на очень важный документ, расставляющий многие точки над i, которые до этого валялись где-то в области догадок. Итак, источник вот он. Всё в чём я сомневаюсь, буду помечать знаком (#?) где #- ID сомнения (для последующего комментирования).

Жизненный цикл компонента. Дисплей-лист.
  • Во Flex многие элементы размещаются (1?) в дисплей-листе (который мы используем для доступа к ним). Это:
    - внедряемые шрифты
    - стили
    - размер прогрывателя (2?)
    - верхушка (головной элемент) DOM (3?)
  • Доступ к этим элементам осуществляется через SystemManager.
  • При создании, компоненты не имеют доступа к дисплей-листу.
    - свойство компонента systemManager == null
  • Поэтому, конструктор вашего компонента не имеет доступа к этим элементам.

var randomWalk:UIComponent = new RandomWalk();
randomWalk.dataProvider = dataSet;
/* Random Walk cannot access the player’s size, or add capture phase event listeners until addChild is called because systemManager ==null */
addChild(randomWalk);
/* After addChild(), systemManager !=null */

Жизненный цикл компонента. Application.

  • Объект Application - особый случай.
  • Он также не видит (4?) дисплей-лист. Но...
  • ... systemManager != null, хотя
    - stage == null
    - root == null
  • Он не видит дисплей-лист до тех пор, пока не наступит событие creationComplete.
    - в следствии чего, и ваш компонент тоже не видит дисплей-лист.
  • Дисплей-лист становится доступным, когда генерируется событие applicationComplete.
  • Всё это делается в целях улучшения производительности.
  • Тут легко ошибиться.
  • Используйте systemManager.stage (то только не в конструкторе).

Жизненный цикл компонента. Создание экземпляра компонента.

var myComp:UIComponent = new RandomWalk();
myComp.dataProvider = dataSet;

addChild(myComp);

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

public function RandomWalk() {
…}
public function set dataProvider() {…}

  • Подготавливает начальную установку (или начальный набор ?) стилей (5?).
  • Добавляет в дисплей-лист.
  • Генерирует событие preInitialize.

protected function createChildren() {…}

  • Инициализирует accessibility-свойства объекта (6?), если таковые имеют место.
  • Генерирует событие initialize.

Жизненный цикл компонента. Несколько правил.

  • Не добавлять объекты в конструкторе.
    - это не вызовет ошибки, но делать так - не очень эффективно
    - лучше всего переопределить метод createChildren() и делать это в нём
  • Не вызывать метод getStyle() в конструкторе.
    - он вызовет ошибки, но может выдать некорректные данные
    - подождать до createChildren()
    - а еще лучше, переопределить метод commitProperties()
  • Не обращаться к systemManager, stage или root из конструктора.
    - они все равны null
    - лучше подождать до createChildren() или более поздних выводов
  • Не используйте прямой доступ к stage и root
    - используйте systemManager

Жизненный цикл компонента. Запуск. Инициализация.

  1. Создан экземпляр Application.
  2. Установлен Application.systemManager.
  3. Application.dispatchEvent(new Event(‘preinitialize’))
  4. Application.createChildren()
    1. Создан экземпляр randomWalk
    2. Вызван конструктор randomWalk()
    3. Установлены свойства этого компонента
    4. randomWalk.dispatchEvent(new Event(‘preInitialize’))
    5. randomWalk добавлен в приложение (но его всё еще нет в дисплей-листе)
    6. randomWalk .createChildren()
    7. randomWalk.dispatchEvent(new Event(‘initialize’))
  5. Application.dispatchEvent(new Event(‘initialize’))

Жизненный цикл компонента. Запуск. Валидация.

  • Фаза 1
    randomWalk.commitProperties()
    Application.commitProperties()
  • Фаза 2
    randomWalk.measure()
    Application.measure()
  • Фаза 3
    Application.updateDisplayList()
    randomWalk.updateDisplayList()
  • Фаза 4
    randomWalk.dispatchEvent(new Event(‘creationComplete’))
    Application. dispatchEvent(new Event(‘creationComplete’))

Жизненный цикл компонента. Запуск. Завершение.

  • Объект Application добавлен в дисплей-лист
  • Application.dispatchEvent(new Event(‘applicationComplete’))


понедельник, февраля 18, 2008

Синхронизация случайных чисел для клиент-серверных приложений.

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

Итак, есть задача случайным образом распределять какие-либо данные на клиентских приложениях. При этом должны генерироваться случайные, но одинаковые на всех клиентах числа. Для этого, при инициализации и синхронизации взаимодействия клиентов и сервера, сервер генерирует гамму случайных чисел и шлет ее всем клиентам. Клиенты сохраняют полученную гамму.
Клиенты имеют свои "прозрачные" методы random();, которые выдают случайное число. На самом деле, метод random(); при вызове попросту выбирает каждый последующий элемент из гаммы и возвращает полученное значение. После выборки последнего элемента, указатель перемещается на начало гаммы.

Для "подновления" генерируемых случайностей, можно (а во многих случаях нужно) подгружать новую гамму. При этом, процесс подновления можно легко встроить в протокол обмена данными. Периодически "пристраивая" свежую гамму в ответы сервера на запросы, требующие синхронизации клиентов, можно делать "свежие" вливания в вероятность случайных чисел.

Код класса псевдо-генератора прилагается.

Список с указателем. AS3

Понадобилось использовать простой список с указателем, на подобии XML, с навигацией по списку next/previous. Ручками это реализовать проблем нет - хочется готовое поюзать. Думал, уж наверняка есть какой-нть класс чтонть типа хзCollection в AS3. Ан нет. В Flash AS3 API не нашел :(. Может быть я плохо искал?

воскресенье, февраля 17, 2008

3-я встреча RAFPUG. Рабочие будни

Сегодня забежал на пару часиков на третью встречу Российских Пользователей Адоби-Флэш-платформы.

Задержаться до конца не позволили обстоятельства, ибо, потратить личное время в выходные - слишком большая жертва для семейного человека, работающего пять дней в неделю 8 часов вне дома, а то и дома по вечерам (Эх, в будни бы проводили с утреца и хоть до самого вечера).

На этот раз всё было скромно. На входе девушки не раздавали именных бэйджиков, не было громких слов и именитых гостей. Да и гостей вобщем-то было не так много. Мне показалось, даже меньше чем на первой встрече.

Начал встречу, как всегда, Артемий, и анонсировал проект Adobe и иже с ним - портал Flashawards - несколько кривовато работающий (позже понял почему такое ощущение - объект флэш криво вставлен в HTML и в IE появляется злочастная рамочка), но вполне симпатичный, посвященный Первому профессиональному flash-конкурсу в России. Для начала, нашему вниманию был представлен призванный вдохновить всех флэшеров, забавный видео-ролик с зомбирующим образом быстро сменяющимися кадрами под чудесную музыку Save the Robots (Members Of Mayday), представляющий работы победителей предыдущего конкурса. Затем были вручены подарочки (обещаные на второй встрече) и Артемий обмолвился о скором выходе 3го FlexBuilder!

Цель моего сегодняшнего визита - послушать доклад Александра Козловского "Простой путь создания трёхмерного AIR приложения". Анонс был настолько завлекателен, что, казалось, только ради одного этого доклада стоило сорваться - анонсировалось и Papervision3D и создание AIR-приложения.

Я не буду обсуждать сам доклад - не имею такого права, т.к. сам не набрался сил и смелости что-либо вообще подготовить и докладывать.
В ходе доклада довольно подробно было продемонстрировано создание AIR-приложения и несколько поверхностно - использование Papervision3D.

Основные (лично для меня) моменты по созданию AIR приложения:
  1. Конфигурирование AIR-приложения. Все настройки хранятся в файле PROJECTNAME-app.xml. Важные для нас теги:
    filename - имя генерируемого файла.
    name - имя приложения (ВНИМАНИЕ - оно где-то в конце файла дублируется, что может вызвать недопонимание в процессе отладки).
    visible - будет ли видимым главное окно после старта.
    И другие - аналогично - пояснения есть для каждого в комментариях.
  2. Если нам нужно приложение в виде окна с тулбаром и тому подобными примочками, мы наследуем главный класс нашего приложения от mx.WindowedApplication. Если же нам всё это не нужно и мы хотим отсутствия всякого фона между нашей графикой и десктопом - просто от mx.Application.
  3. Создание tray-иконок для Windows и Apple платформ отличается. Если в Windows это место называется tray, то в Apple - это Dock. Соответственно, Александр предлагает нам проверять такие параметры как NativeApplication.supportsDockIcon и NativeApplication.supportsSystemTrayIcon. Затем, используя класс NativeMenu и иже с ним, мы создаем меню. ВАЖНО: Иконку лучше убирать принудительно, т.к. операционная система не всегда это делает самостоятельно. Для этого достаточно сделать NativeApplication.icon.bitmaps=[];.
  4. Для доступа к главному окну, используем SystemManager.Stage.NativeWindow.
  5. Для отлова Drag'n'Drop нам понадобятся события для ViewPort3D:
    NATIVE_DRAG_ENTER - вход мыши с драг'н'дроп-содержимым.
    NATIVE_DRAG_DROP - отпускание мыши с драг'н'дроп-содержимым.
    Кроме того, пользуется событие ADDED_TO_STAGE для инициализации.
  6. Важное замечание по Drag'n'Drop: используя объект события NativeDragEvent.Clipboard.getData(); можно получить переданное драг'н'дроп-содержимое. Дело в том, что при Drag'n'Drop-перетаскивании, данные складируются в буфере Clipboard, хотя, при этом данные, запомненные, к примеру, по Contrl+C не теряют своей актуальности.
  7. Сохранение файла:
    Stream=new FileStream();
    f=new File(File.applicationDirectory.nativePath+'...'); Где File.applicationDirectory.nativePath - текущая директория исполняемого приложения.
    Stream.open(f, FileMode.WRITE);
    Stream.WriteMultiByte("...data...");
    Stream.close();

По Papervision3D следующие заметки:

  1. Основные компоненты, которые необходимо создать и инициализировать: BasicRendererEngine - движок.
    Viewport3D - наследник Sprite для рендера изображения.
    Другие объекты - Scene3D, Camera (Camera.target - устанавливает объект, за которым будет наблюдать камера)

Другие заметки:

  1. Для прелоадера/сплэш-скрина используем объект-потомок ProgressBar. По окончании загрузки, диспатчим событие COMPLETE, после чего приложение Application получит событие PRELOADER_DONE.
  2. Для обновления приложения используем класс Updater. Класс выполняет лишь следующую функцию - сообщает AIR, что необходимо после закрытия приложения обновить его. Александр предложил самостоятельно скачивать и обновлять приложения с использованием библиотек ZIP-архивации.

Конечно, хотелось бы увидеть более подробное изложение, и, я думаю, если бы у Александра всё получилось так, как он планировал, так бы оно и было, но - обстоятельства выше нас. Несмотря на все трудности, доклад получился очень ценным и интересным.

После доклада, Артемий предложил "ручками" потрогать флекс, под присмотром старших товарищей, всем, кто еще не лишился девственности. К сожалению, я должен был покинуть это заведение, конечно же не из страха дефлорации - ибо уже флекс посетил меня. Я был бы очень рад попрактиковаться в создании скинов для компонентов и осветить для себя несколько вопросов по байндингу. Но, видимо, придется это сделать самостоятельно.

В итоге, впечатление от встречи однозначно - Коллеги, хватит веселиться - настало время потрудиться. Наступили рабочие будни.

* * *

Исходники того, что демонстрировал Александр на RAFPUG-3 здесь. Про обновление AIR-приложения статья здесь (уже в "Чужой тетради").

четверг, февраля 14, 2008

Установка перменных объектов. Server Side API. SmartFoxServer

Основные объекты SmartFoxServer (room и user) могут сохранять и возвращать переменные. Как они возвращают переменные мы уже видели здесь и здесь.
Для того, чтобы установить переменные, необходимо вмешательство главного управляющего класса _server.

Следующие методы позволяют устанавливать/удалять переменные:

_server.setRoomVariables(room, who, varList, setOwnership, sendUpdate)
Устанавливает переменную(ые) комнаты.
room - объект Room комната, переменные которой устанавливаются.
who - объект User пользователя, который производит установку. null - установка от имени сервера.
varList - массив, состоящий из объектов, характеризующих переменную:
name - имя переменной
val - значение переменной. Если установить undefined (а можно null ?) переменная будет удалена.
priv - приватная или нет
persistent - постоянная или нет (если постоянная - не удалится, если пользователь перейдет в другую комнату. Но после его отключения - удалится)
setOwnership - если false - не позволит изменить хозяина переменной (того кто ее создал). true по умолчанию.
sendUpdate - если false, пользователи комнаты не будут извещаться о происшедшем изменении. true по умолчанию.

_server.setUserVariables(who, varList, sendUpdate)
Устанавливает переменную(ые) пользователя.
who - объект User пользователя, который производит установку. null - установка от имени сервера.
varList - объект (ассоциативный массив) содержащий переменные ([имя]=значение). Если значение установлено в undefined - переменная удаляется.
sendUpdate - если false, пользователи комнаты не будут извещаться о происшедшем изменении. true по умолчанию.

_server.setBuddyVariables(user, variables)
Установить переменные друга. Генерирует событие onBuddyListUpdate.
user - объект User пользователя-хозяина переменных.
variables - ассоциативный массив переменных.

* * *

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

вторник, февраля 12, 2008

Всплывающие окна внутри Flex-приложения. Flex

Для всплывающих окон Flex-приложения используется PopUpManager:

createPopUp(parent:DisplayObject, className:Class, modal:Boolean = false, childList:String = null):IFlexDisplayObject
Создает всплывающее окно поверх других.
parent:DisplayObject - определяет дисплей-объект, относительно которого SystemManager выравнивает всплывающее окно.
className:Class - класс объекта всплывающего окна.
modal:Boolean - если true, окно будет модальным (другие интерактивные элементы блокироются). По умолчанию false.
childList:String - список, в который добавляется окно.
Значения:
PopUpManagerChildList.APPLICATION
PopUpManagerChildList.POPUP
PopUpManagerChildList.PARENT (по умолчанию).

Пример использования:
var warning:WarningWindow = PopUpManager.createPopUp(this, WarningWindow, true) as WarningWindow

понедельник, февраля 11, 2008

Работа с интервалами. SmartFoxServer

Работать с интервалами полезно. Иначе можно совсем заработаться и свихнуться.
И в SmartFoxServer есть методы работы с интервалами:

setInterval(functionName, interval, params) - устанавливает новый интервал.
functionName - функция, которая будет вызвана после заданного интервала
interval - количество времени (в млсек.) между вызовами функции
params - объект (или ассоциативный массив), содержащий набор свойств
Возвращает ссылку на объект интервала.

clearInterval(intervalObj) - останавливает интервал и удаляет его.
intervalObj - объект ранее созданного интервала.

ВАЖНО: После своего создания, объект интервала осуществляет постоянный вызов заданной функции через заданное время. Необходимо обязательно явно, через clearInterval удалять объекты интервалов, если необходимость в них отпала. Иначе рано или поздно сервер просто загнется.

* * *

С отключением интервала реально жестко - если запущен какой-нибудь ошибочный интервал, который не умеет отключаться, убить его можно только перезагрузкой сервера. Ни перезагрузка комнаты или зоны, ни переключения активности комнаты/зоны не помогут. Наверное, есть смысл сделать свою заготовку интервала с зашитым в него отключением через какой-то срок. Однако, и это может не помочь, если, к примеру, запустить таймер с допущеной в синтаксисе обработчика ошибкой - интервал запустится, обработчик будет генерить ошибку и вылетать до следующего цикла.

Обновление при отладке серверных скриптов комнат. SmartFoxServer

При отладке серверных скриптов уровня комнат, необходимо каждый раз обновлять серверный скрипт для каждой комнаты.
Например, мы имеем три комнаты, для каждой из которых определен один и тот же серверный скрипт. Если мы внесли измененения в скрипт, необходимо провести процедуру обновления его (кнопочка RELOAD EXT.) для каждой комнаты. (Имеется в виду, что скрипт задан в конфигурации а не аттачится динамически).

if vs. switch. SmartFoxServer

Странное поведение серверного интерпретатора в обработчике handleInternalEvent(evt) .
Прямая проверка срабатывает:
if (evt.name=="spectatorSwitched") {}
Однако вариантная проверка работать отказывается!
switch (evt.name) {
case "spectatorSwitched":
break;
}


Далее эксперементы показали, что необходимо приведение к строковому типу:
switch (String(evt.name)) { }

Делаем вывод - в неоднозначных и странных ситуациях первым делом приводим типы.

Внутренние события SmartFoxServer

При определенных обстоятельствах SmartFoxServer генерирует внутренние события, которые можно обработать методом handleInternalEvent(event), где event.name - имя события, event.* - параметры события.

События:

fileUpload - клиент загрузил на сервер файл используя клиентское SFS API.
files - массив объектов со свойствами fileName(имя, под которым файл сохранился на сервере) и originalName (оргигнальное имя файла на клиенте)
user - объект User пользователя, пославшего файл.

loginRequest - генерируется в момент авторизации пользователя в зоне сервера. Только для скриптов уровня зоны. Только при включенной опции зоны customLogin.
nick - имя пользователя (java.lang.String)
pass - пароль пользователя (java.lang.String)
chan - объект сокет-канала соединения

logOut - генерируется, когда пользователь выходит из зоны.
roomIds - список всех комнат, в которых был пользователь (только для уровня зоны) (Java array)
playerIndexes - список всех номеров слотов, которые были у игрока до выхода (только для уровня зоны) (Java array)
uid - идентификатор вышедшего пользователя (java.lang.String)
chan - объект сокет-канала соединения
oldPlayerIndex - номер слота игрока для текущей комнаты (только для уровня комнаты)

newRoom - создана новая комната в зоне (только для уровня зоны).
room - объект новой комнаты

pubMsg - послано публичное сообщение.
room - объект комнаты
user - объект пользователя пославшего сообщение
msg - сообщение (java.lang.String)

privMsg - послано публичное сообщение.
room - объект комнаты
sender - объект пользователя пославшего сообщение
recipient - объект пользователя принимающего сообщение
msg - сообщение (java.lang.String)

roomLost - уничтожена комната в зоне (только для уровня зоны) .
roomId - идентификатор уничтоженной комнаты

spectatorSwitched - наблюдатель переключился в пользователя.
user - объект User пользователя, ставшего игроком
playerIndex - номер слота

userExit - пользователь покинул комнату зоны.
uid - идентификатор пользователя (java.lang.String)
oldPlayerIndex - номер слота игрока (java.lang.String)
room - объект комнаты, которую покинул пользователь

userJoin - пользователь вошел в комнату зоны.
user - объект User пользователя
room - объект Room комнаты

userLost- генерируется, когда пользователь непредсказуемо отключается от сервера.
roomIds - список всех комнат, в которых был пользователь (только для уровня зоны) (Java array)
playerIndexes - список всех номеров слотов, которые были у игрока до выхода (только для уровня зоны) (Java array)
uid - идентификатор вышедшего пользователя (java.lang.String)
oldPlayerIndex - номер слота игрока для текущей комнаты (только для уровня комнаты)
ЗАМЕЧЕНО: Если пользователь выходит непредсказуемо в момент события userLost, данные getAllUsers(), а так же getSpectatorCount() и getUserCount() еще старые и обновляются позже.

Класс User. Server Side API. SmartFoxServer

Класс представляет клиента, подключенного сервера и авторизованного в его зоне.

getIpAddress()
Возвращает IP-адрес клиента

getLastMessageTime()
Возвращает время (в млсек.) последнего сообщения клиента

getLoginTime()
Возвращает время авторизации пользователя (в млсек.)

getName()
Возвращает имя пользователя

getPlayerIndex()
Возвращает номер игрока (слот) пользователя

getPlayerIndex(roomObj)
Возвращает номер игрока (слот) пользователя для комнаты roomObj

getRoomsConnected()
Возвращает массив идентификаторов комнат, в которые вошел пользователь

getUserId()
Возвращает уникальный идентификатор пользователя

getVariable(name)
Возвращает переменную пользователя с именем name
Переменная возвращается как объект UserVariable.
Объект имеет лишь один метод - getValue() - вернуть значение переменной.

getVariables()
Возвращает список всех переменных пользователя в формате java.util.HashMap

isAdmin()
Возвращает true, если пользователь администратор

isModerator()
Возвращает true, если пользователь модератор

isSpectator()
Возвращает true, если пользователь наблюдатель

setAsModerator(flag)
Переключить статус модератора flag пользователю

updateMessageTime()
Обновляет счетчик последнего сообщения пользователя


Управление свойствами класса

Можно установить собственные свойства для объекта User, используя свойство properties - ассоциативный массив. Например:
user.properties.put("score", score)

Методы управления properties:

put(key, value)
Добавляет новое свойство/объект

get(key)
Возвращает свойство/объект, с именем key. Если объект отсутствует, возвращает null

remove(key)
Удаляет свойство с именем key

size()
Возвращает размер массива свойств

Класс Room. Server Side API. SmartFoxServer

Класс представляет комнату зоны.

Методы управления комнатой:

contains(userName)
Возвращает true, если пользователь userName вошел в комнату

getAllUsers()
Возращает массив объектов User всех пользователей.
ЗАМЕЧЕНО: Если пользователь выходит непредсказуемо в момент события userLost, данные getAllUsers(), а так же getSpectatorCount() и getUserCount() еще старые и обновляются позже.

getId()
Возвращает идентификатор комнаты

getMaxSpectator()
Возвращает максимально допустимое количество наблюдателей в комнате

getMaxUsers()
Возвращает максимально допустимое количество пользователей в комнате

getName()
Возвращает имя комнаты

getPassword()
Возвращает пароль доступа к комнате

getSpectatorCount()
Возвращает текущее количество наблюдателей в комнате

getUserCount()
Возвращает текущее количество пользователей в комнате.
ВАЖНО: Если комната игровая, также как и для класса Room SFS Flash API возвращается не общее количество пользователей, а только количество игроков. Наблюдатели в это число не входят. Поэтому для получения общего количества пользователей необходимо сложить getSpectatorCount() и getUserCount(), либо getAllUsers().length (если идет работа с массивом, для улучшеия производительности лучше сохранить его в пременную и оперировать с переменной, т.к. скорее всего getAllUsers является возвращателем динамически собранного массива).

getVariable(name)
Возвращает значение перемеменной с именем name.
Переменная возвращается как объект RoomVariable .
Объект управляется методами:
getValue() - вернуть значение переменной.
getOwner() - объект-владелец переменной (по всей видимости объект Room).
isPersistent() - true, если постоянная переменная
isPrivate() - true, если приватная переменная

getVariables()
Возвращает список переменных в формате java.util.HashMap

isGame()
Возвращает true, если комната игровая

isPrivate()
Возвращает true, если комната приватная

isTemp()
Возвращает true, если комната временная (создана динамически)


Управление свойствами класса

Можно установить собственные свойства для объекта Room, используя свойство properties - ассоциативный массив. Например:
room.properties.put("score", score)

Методы управления properties:

put(key, value)
Добавляет новое свойство/объект

get(key)
Возвращает свойство/объект, с именем key. Если объект отсутствует, возвращает null

remove(key)
Удаляет свойство с именем key

size()
Возвращает размер массива свойств

Старые грабли с зоной видимости переменных. AS2

В примере Добавляем ссылку в контекстное меню Flash. ContextMenu. AS2 есть один подводный камень. В методе onContextMenu, getURL вызывается от имени _root.
Если не указывать от чъего имени вызывать, либо вызывать от this, ничего не произойдет.
Метод onContextMenu работает, трейс из него проходит, но окно ссылки не открывается. Превое что приходит на ум - может быть покопаться в локальной политике безопасности? - Не поможет. Дело совсем в другом.

А дело в том, что метод onContextMenu присваивается объекту элемента контекстного меню ContextMenuItem, который не знает такого метода.

Для корректной работы, необходимо определять метод-обработчик с использованием Delegate. В этом примере я этого умышленно не сделал для того, чтобы лишний раз вспомнить эти грабли и больше на них не наступать. Это только типичный случай из множества других аналогичных ситуаций.

воскресенье, февраля 10, 2008

TextField+TextFormat.url работает только при включенном TextField.html. AS2

Потребовалось сделать текстовое поле ссылкой. Делать его с использованием HTML-разметки смысла небыло, поэтому просто снял с него getTextFormat, установил ему url="http://.../" и установил обратно setTextFormat. Однако ссылка не установилась. Поле по прежнему было неактивным. Чисто интуитивно, установил text_field.html=true и ссылка активировалась.

пятница, февраля 08, 2008

Заметки по программированию серверных скриптов. SmartFoxServer

Серверные скрипт поддерживают стандарт ActionScript 1.0. Отсюда вытекают следующие последствия:
  • Функция trace() еще не поддерживает множественные параметры. После AS3 так трудно это принять!
  • Не нужно в описании переменных указывать тип. Когда я написал строчку var zone:Zone; SmartFox меня просто не понял... и проигнорировал.

Класс Zone. Server Side API. SmartFoxServer

Класс Zone представляет методы управления и доступа к данным зоны сервера SmartFoxServer.

addBuddy(who, buddyName)
Добавляет друга (buddyName) в список друзей пользователя (who) .

checkBuddy(buddyName)
Проверяет, что друг (buddyName) авторизован в текущей зоне. возвращает boolean.

clearBuddyList(who)
Очищает список друзей пользователя с именем who.

getAutoJoinRoom()
Возвращает идентификатор комнаты для автоматического входа в текущей зоне.

getEmptyNames()
Возвращает true, если в текущей зоне включена опция "EmptyNames".

getCountUpdate()
Возвращает true, если в текущей зоне влючена опция "uCountUpdate".

getMaxRooms()
Возвращает максимальное число комнат, доступное в текущей зоне.

getMaxUsers()
Возвращает максимальное число пользователей, доступное в текущей зоне.

getName()
Возвращает имя текущей зоны.

getRoom(roomId)
Возвращает объект комнаты с идентификатором roomId.

getRoomByName(roomName)
Возвращает объект комнаты с именем roomName.

getRoomCount()
Возвращает текущее количество комнат в зоне.

getRooms()
Возвращает список объектов Room всех комнат зоны.

getStatus()
Возвращает true, если зона в состоянии активности.

getUserCount()
Возвращает текущее число пользователей зоны.

getUserList()
Возвращает список java.util.List, содержащий всех пользователей, авторизованных в зоне.
java.util.List - упорядоченная коллекция или секвенция. Для использования в SmartFoxServer нам очень полезен будет метод toArray(), позволяющий преобразовать список-коллекцию в обычный массив.

hasBuddyList()
Возвращает true, если для текущей зоны включена поддержка списков друзей buddyList.

removeBuddy(who, buddyName)
Удаляет друга (buddyName) из списка друзей пользователя (who).

setPubMsgInternalEvent(flag)
Если установить в true, каждый раз, при поступлении публичного сообщения на сервер, будет генерироваться внутреннее событие. Это полезно для ведения журнала сообщений. По умоляанию false.

Взаимодействие с клиентом. SmartFoxServer

Главным управляющим объектом серверного скрипта SmartFoxServer является _server.
Для общения с криентом, в основном используется метод sendResponse().

_server.sendResponse(response, fromRoom, sender, recipients, type)
response - объект, который содержит все свойства и объекты, которые необходимо передать клиенту. По соглашению, объект должен содержать свойство _cmd с именем команды.
fromRoom - здесь можно указать идентификатор комнаты, из которой сообщение поступает. Если это ненужно, указывается -1.
sender - объект User пользователя, которого мы хотим указать в качестве отправителя сообщения.
recipients - массив, содержащий один или более объектов User пользователей-получателей
type - формат передаваемых данных. По умолчанию "xml". Для передачи в виде строковой сериализации - "str".


Другой метод sendGenericMessage() может служить для реализации собственных или модифицированных версий стандартных сообщений сервера. Например, можно отключить некоторые сообщения сервера и создать свои собственные версии этих сообщений.

_server.sendGenericMessage(xmlMsg, sender, recipientList)
xmlMsg - XML-сообщение.
sender - объект User пользователя-отправителя.
recipientList - список объектов User пользователей-получателей.
Пример ниже показывает как отправить клиенту данные комнаты, где он в данный момент авторизован:

function sendSmallRoomList(r, who) {
var msg = "<msg t='sys'><body action='rmList' r='-1'>"
msg += "<rmList><rm id='" + r.getId()
msg += "' priv='" + (r.isPrivate() ? "1" : "0")]
msg += "' temp='" + (r.isTemp() ? "1" : "0")
msg += "' game='" + (r.isGame() ? "1" : "0")
msg += "' ucnt='" + (r.getUserCount())
msg += "' maxu='" + r.getMaxUsers()
msg += "' maxs='" + r.getMaxSpectator()
msg += "'><n><![CDATA[" + r.getName() + "]]></n></rm></rmList>"
msg += "</body></msg>"
_server.sendGenericMessage(msg, null, [who])
}


Другие команды для более узкого применения:
_server.dispatchPublicMessage(message, room, user) - послать публичное сообщение.
message - текст сообщения
room - объект Room комнаты, в которую посылается сообщение
user - объект User пользователя-отправителя

_server.dispatchPrivateMessage(message, room, sender, recipient) - послать приватное сообщение.
message - текст сообщения
room - объект Room комнаты, в которую посылается сообщение
sender - объект User пользователя-отправителя
recipient- объект User пользователя-получателя

_server.sendModeratorMessage(message, sender, type, id) - послать сообщение модератора.
message - текст сообщения.
sender - объект User пользователя-отправителя.
type - масштаб рассылки:
_server.MOD_MESSAGE_TO_ZONE - всем пользователям зоны.
_server.MOD_MESSAGE_TO_ROOM - всем пользователям комнаты.
_server.MOD_MESSAGE_TO_USER - конкретному пользователю.
id - к этому параметру нет объяснения.

_server.sendRoomList(who) - послать список комнат пользователю.
who - объект User пользователя-получателя.

Кроме явно отправляющих ответы методов, есть ряд других, опционально отправлящих сообщения, информирующие клиента о каких-либо действиях:
_server.createRoom(roomObj, user, sendUpdate, broadcastEvt, roomVars, varsOwner, setOwnership)
_server.joinRoom(user, currRoomId, leaveRoom, newRoom, pwd, isSpec, sendUpdate)
_server.leaveRoom(user, roomId, broadcastAll)
_server.setUserVariables(who, varList, sendUpdate)
_server.switchSpectator(user, roomId, broadcastAll)

Следующие функции пока оставим без внимания - назначение их специфично:
_server.requestAddBuddyPermission(sender, targetUserName, optionalMessage)
_server.sendBuddyListUpdate(user)
_server.sendMail(from, to, subject, message)
_server.setBuddyBlockStatus(user, buddyName, isBlocked)
_server.setBuddyVariables(user, variables)

четверг, февраля 07, 2008

Серверные скрипты (Extensions). SmartFoxServer

Серверные скрипты (я так обозвал термин Extensions, т.к. дословный перевод, типа расширение или серверное расширение, на мой взгляд, менее точны и понятны) - это Java или Actionscript 1.0 (Javascript/ECMA-262) код, для реализации серверной логики.

Применительно к ActionScript (другие варианты я рассматривать не буду), скрипты содержатся в файлах типа .as, размещенных в директории sfsExtensions (для Windows это "C:\Program Files\SmartFoxServerPRO_1.6.0\Server\sfsExtensions\").

Для того, чтобы сервер обрабатывал скрипт, необходимо зарегистрировать его в файле конфигурации config.xml. Выглядит это примерно так:

<Extensions>
<extension name="myExt" className="myExtension.as" type="script" />
</Extensions>

Здесь name - имя скрипта, к которому осуществляет обращение клиент, className - имя файла скрипта.

Кроме того, можно динамически закрепить скрипт за динамически создаваемой комнатой (см. SmartFoxClient.createRoom).

Теперь можно из клиента посылать запрос на выполнение скрипта (см. SmartFoxClient.sendXtMessage):

server.sendXtMessage("myExt", "helloWorld", obj);

Сообщения, получаемые клиентом от серверного скрипта обрабатываются примерно так:

smartfox.onExtensionResponse = function(resObj:Object, type:String) {
var cmd:String = resObj._cmd
if (cmd == "myCommand")
{ // Handle the response here
}
}


Роль серверных скриптов в архитектуре сервера хорошо видна на диаграмме:


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

Основные функции серверных скриптов:

init() - инициализация серверного скрипта. Вызывается автоматически, как только сервер загрузил скрипт.

destroy() - вызывается перед уничтожением серверного скрипта.

handleRequest(cmd, params, user, fromRoom)
cmd - имя запроса. При формировании запроса, для снижения трафика, рекомендуется делать имена короткими.
params - объект с данными, котторые передал клиент серверу.
user - объект пользователя.
fromRoom - идентификатор комнаты, из которой поступил запрос.

handleInternalEvent(eventObject) - реагирует на внутренние события сервера.
Список событий сервера:
userJoin - пользователь вошел в зону/комнату.
userExit - пользователь вышел из комнаты.
userLost - пользователь отключился
newRoom - создана новая комната
roomLost - в зоне была уничтожена комната
loginRequest - пользователь послал запрос на авторизацию
spectatorSwitched - в игровой комнате, наблюдатель переключился в игрока.

Проверим на практике.
Создаем свой серверный скрипт и попробуем посмотреть, как он будет реагировать на события.

Создаем скрипт test.as в вышеописанной директории:
function init() {
trace("Initialization")
}

function destroy() {
trace("Destruction")
}

function handleRequest(cmd, params, user, fromRoom) {
trace("cmd="+cmd+" params="+params+" user="+user+" fromRoom="+fromRoom);
}

function handleInternalEvent(evt) {
trace("eventName="+evt.name);
}


Поместим в Config.xml в нашу созданную ранее зону запись:
<Extensions>
<extension name="tst" className="test.as" type="script" />
</Extensions>

Теперь рестартуем сервер. Или нажимаем "Reload Zones" для перезагрузки зон (?).

Чтобы просмотреть результаты трейсов, можно использовать окно консоли или зайти в SFS Admin Tool в раздел Zone Browser -> Extensions View -> Trace Window.
В серверной консоли можно посмотреть результат трейсов из init и destroy. Просмотреть эти трейсы в реальных условиях в Admin Tool невозможно, так как скрипты, прописанные в конфигурации инициализируются сразу после старта сервера и удаляются непосредственно перед выключением. Однако рядом есть кнопочка "Reload Ext.", где скрипт убивается и опять инициализируется. Здесь то мы и видим наши трейсы.

Что ж, наш скрипт исправно работает, и трейсит все события. Он даже принимает наш запрос:
smartfox.sendXtMessage("tst", "testCommand", {value:1}, "xml");

Интересная особенность - сервер не обрабатывает запрос, если третий параметр (объект с данными запроса) установлен в null. Если некорректно задать другие параметры, это еще объяснимо, но если мне не нужно передавать никакие данные?

Теперь попробуем получить ответ от сервера. Добавим в серверный скрипт в метод handleRequest новый код:
function handleRequest(cmd, params, user, fromRoom) {
trace("cmd="+cmd+" params="+params+" user="+user+" fromRoom="+fromRoom);
var response = {}
response._cmd = "response"
_server.sendResponse(response, -1, null, [user])
}

И в свою очередь, добавим клиенту обработчик события onExtensionResponse:

. . .

this.__sfs.addEventListener(SFSEvent.onExtensionResponse, this.onExtensionResponse);

. . .

public function onExtensionResponse(evt:SFSEvent):void {
trace("Пришел ответ от серверного скрипта: "+evt.params.dataObj);
}

Теперь наш клиент получает на свой запрос ответ от серверного скрипта.

среда, февраля 06, 2008

Событие от компонентов itemRenderer. Flex

Есть компонент список List, элементы которого являются компонентами (MXML) и задаются через свойство itemRenderer.
В свойство dataProvider указан [Bindable] массив ArrayCollection.
Каждый из элементов этого массива - объект [Bindable] класса с набором свойств, который порождается от EventDispatcher. В компонентах элементов списка свойства этого объекта указаны как источники данных: text="{data.name}" и change="data.text=text_input.text;".

При работе со списком, происходят изменения свойств любого из объектов списка. Свойства объектов элементов массива обновляются, меняют свои значения. Все хорошо.

Теперь, требуется получать событие обновления какого-либо элемента.
Я пошел обычным путем - подписался на прослушивание события PropertyChangeEvent.PROPERTY_CHANGE для каждого экземпляра элемента массива при его создании. Приблизительный код:

. . .

[Bindable]
public var some_list:ArrayCollection;

. . .

var item:TSomeListItem=new TSomeListItem(some_source.name, some_source.status);
item.addEventListener PropertyChangeEvent.PROPERTY_CHANGE,this.onPropertyChange,false,0,true);
this.some_list.addItem(item);

. . .

private function onPropertyChange(event:PropertyChangeEvent):void {
trace("Изменилось свойство", event.source, ".", event.property,"Было:", event.oldValue,"Стало:",event.newValue, "Тип изменения:", event.kind);
}

. . .

<mx:HorizontalList . . . dataProvider="{some_list}" itemRenderer="SomeListItemRenderer" id="some_list_box"></mx:HorizontalList>

Таким образом, при каждом изменении какого-либо элемента списка отрабатывает событие, предоставляющее полную информацию об изменении.
Возможно существует другой способ получить это событие - я пока не нашел.

вторник, февраля 05, 2008

Параметры конструктора. MXML

Определяя класс для последующей его вставки в MXML, при объявлении конструктора, необходимо указать для всех его параметров значения по умолчанию. Иначе возникает ошибка "1136: Incorrect number of arguments. ".
Других способов избежать ошибки я не нашел.

понедельник, февраля 04, 2008

ViewStack и эффекты появления/исчезания. MXML

Компонент ViewStack удобен для строительства последовательностей диалогов. Чтобы диалоги появлялись/исчезали интереснее, можно использовать эффекты (способ применим к любым компонентам, это частный случай).
Определяем эффекты:
<mx:Move id="fadeIn" duration="500" xFrom="-1000"/>
<mx:Move id="fadeOut" duration="500" xTo="-1000"/>

Для каждого компонента указать эффекты появления/исчезания:
<mx:ViewStack . . . selectedIndex="0">
<mx:Canvas . . . hideEffect="{fadeOut}" showEffect="{fadeIn}">

пятница, февраля 01, 2008

Класс User. SmartFoxServer

Класс User- класс, осуществляющий доступ к информации пользователя SmartFoxServer.

Полное определение класса: it.gotoandplay.smartfoxserver.data.User

Методы:

getId () : int
Возвращает идентификатор пользователя.

getName () : String
Возвращает имя пользователя.

getVariable (varName:String) : *
Возвращает переменную пользователя.
Name - имя переменной.

getVariables () : Array
Возвращает ассоциативный массив переменных пользователя. Ключевые значения массива - имена переменных.

isSpectator () : Boolean
Пользователь является наблюдателем.

isModerator () : Boolean
Пользователь является модератором.

getPlayerId () : int
Идентификатор игрока пользователя. Отсчитывается от 1, для наблюдателей равен -1. Работает только для пользователей игровых комнат.

Класс Room. SmartFoxServer

Класс Room- класс, осуществляющий доступ к информации комнаты SmartFoxServer.

Полное определение класса: it.gotoandplay.smartfoxserver.data.Room

Методы:

getUserList (): Array
Возвращает ассоциативный массив объектов User пользователей комнаты. В качестве ключевых значений массива выступают идентификаторы пользователей.

getUser (userId:*) : User
Возвращает параметры пользователя, находящегося в комнате.
userId : идентификатор (int) или имя (String) пользователя.

getVariable (varName:String) : *
Возвращает переменную комнаты.
varName : имя запрашиваемой переменной.
ОЧЕНЬ ВАЖНО: Объект Room не будет получать переменные, если в конфигурации параметр roomListVars не установлен, или установлен в false. Методы getVariable() и getVariables() не будут возвращать никаких переменных.

getVariables () : Array
Возвращает ассоциативный список переменных, где в качестве ключей используются имена переменных.

getName () : String
Возвращает имя комнаты.

getId () : int
Возвращает идентификатор комнаты.

isTemp () : Boolean
Если true, комната является временной. Всегда true для комнат, созданных во время работы приложения на стороне клиента (?).

isGame () : Boolean
Комната является игровой.

isPrivate () : Boolean
Комната является приватной.

getUserCount () : int
Возвращает число пользователей в комнате.
ВАЖНО: В игровых комнатах важно различать количество пользователей и количество наблюдателей. Количество пользователей здесь - это не общее число пользователей, а только число игроков. Соответственно, общее число пользователей в игровой комнате равно getUserCount()+getSpectatorCount().

getSpectatorCount () : int
Возвращает число наблюдателей в комнате. (Только для игровых комнат).

getMaxUsers () : int
Возвращает максимальное число пользователей, которые могут войти в комнату.

getMaxSpectators () : int
Возвращает максимальное число наблюдателей, которые могут войти в комнату. (Только для игровых комнат).

getMyPlayerIndex () : int
Возвращает идентификатор игрока текущего пользователя в комнате. Отсчитывается от 1, для наблюдателей равен -1.

isLimbo () : Boolean
Комната работает в режиме "limbo" (рассчитана на очень большое количество пользователей).

Класс SFSEvent. SmartFoxServer

Класс SFSEvent - представляет все события, которые обрабатываются объектом SmartFoxClient.

Полное определение класса: it.gotoandplay.smartfoxserver.SFSEvent

Потомок Event.

Свойства:

params : Object - объект, содержащий параметры обрабатываемого события.

Методы:

clone () : Event
Возвращает копия объекта события.

toString () : String
Возвращает строку, содержащую все параметры объекта события.

События:

onAdminMessage : String
Получено сообщение от администратора. Это событие обязательно должно обрабатываться, иначе пользователи не смогут получать сообщения от администратора сервера.
Параметры, переданные через params:
message : String - текст сообщения.

onBuddyList : String
Получен список друзей для текущего пользователя. Генерируется также при добавлении/удалении друга из списка.
Параметры, переданные через params:
list : Array - список друзей.

onBuddyListError : String
Ошибка загрузки списка друзей.
Параметры, переданные через params:
error : String - сообщение об ошибке.

onBuddyListUpdate : String
Статус или переменные друга в списке друзей изменились.
Параметры, переданные через params:
buddy : Object - параметры друга.

onBuddyPermissionRequest : String
Текущий польователь получил запрос на добавление в список друзей.
Параметры, переданные через params:
sender : String - имя пользователя.
message : String - текст сообщения, сопровождающего запрос.

onBuddyRoom : String
Ответ на запрос SmartFoxClient.getBuddyRoom.
Параметры, переданные через params:
idList : Array - список идентификаторов комнат, в которых авторизован запрашиваемый друг.

onConfigLoadFailure : String
Ошибка загрузки файла внешней конфигурации.
Параметры, переданные через params:
message : String - текст ошибки.

onConfigLoadSuccess : String
Файл внешней конфигурации успешно загружен. Никакие параметры не передаются.

onConnection : String
Ответ на запрос SmartFoxClient.connect.
Параметры, переданные через params:
success : Boolean: результат соединения. True - успешно.
error : String - сообщение об ошибке.

onConnectionLost : String
Связь со SmartFoxServer прервалась (клиентом или сервером). Никакие параметры не передаются.

onCreateRoomError : String
Ошибка при создании комнаты.
Параметры, переданные через params:
error : String - сообщение об ошибке.

onDebugMessage : String
Получено отладочное сообщение trace() SmartFoxServer API.
Параметры, переданные через params:
message : String - текст ошибки.

onExtensionResponse : String
Получена команда/ответ от серверного скрипта.
Параметры, переданные через params:
dataObj : Object - объект, содержащий данные, посланные серверным скриптом. Желательно, чтобы среди параметров присутствовала строка _cmd которая отличала бы данное сообщение от других сообщений того же серверного скрипта.
type : String - тип протокола. См. SmartFoxClient.sendXtMessage;

onJoinRoom : String
Подключение к комнате прошло успешно.
Параметры, переданные через params:
room : Room - объект представляющий комнату, к которой подключился пользователь.

onJoinRoomError : String
Ошибка в процессе подсоединения к комнате.
Параметры, переданные через params:
error : String - сообщение об ошибке.

onLogin : String
Попытка авторизоваться в зоне SmartFoxServer.
Параметры, переданные через params:
success : Boolean - true - успешная авторизация.
name : String - действительное имя пользователя.
error : String - сообщение об ошибке в случае неудачи.

onLogout : String
Пользователь успешно покинул зону. Никакие параметры не передаются.

onModeratorMessage : String
Получено сообщение от модератора.
Параметры, переданные через params:
message : String - текст сообщения.
sender : User - объект пользователя модератора.

onObjectReceived : String
Получен объект ActionScript.
Параметры, переданные через params:
obj : Object - объект ActionScript.
sender : User - объект пользователя, пославшего объект ActionScript.

onPrivateMessage : String
Получено личное сообщение.
Параметры, переданные через params:
message : String - текст сообщения.
sender : User - объект пользователя, пославшего сообщение.
roomId : int - идентификатор комнаты пользователя, пославшего сообщение.
userId : int - идентификатор пользователя, пославшего сообщение. Полезно в случае, если объект пользователя недоступен.

onPublicMessage : String
Получено массовое (чат) сообщение.
Параметры, переданные через params:
message : String - текст сообщения.
sender : User - объект пользователя, пославшего сообщение.
roomId : int - идентификатор комнаты пользователя, пославшего сообщение.

onRandomKey : String
Ответ на запрос SmartFoxClient.getRandomKey.
Параметры, переданные через params:
key: String - уникальная случайная последовательность символов (ключ), сгенерированная сервером.

onRoomAdded : String
Создана новая комната в зоне, где пользователь в настоящий момент авторизован.
Параметры, переданные через params:
room : Room - объект представляющий вновь созданную комнату.

onRoomDeleted : String
Была удалена комната в зоне, где пользователь в настоящий момент авторизован. Параметры, переданные через params:
room : Room - объект представляющий удаленную комнату.

onRoomLeft : String
Ответ на запрос SmartFoxClient.leaveRoom. Генерируется в случае, когда пользователь подключен к нескольким комнатам.

onRoomListUpdate : String
Получен список комнат для текущей зоны.
Генерируется в следующих случаях:
- автоматически после успешной авторизации в зоне,
- в качестве ответа на запрос SmartFoxClient.getRoomList
Параметры, переданные через params:
roomList : Array - список объектов Room комнат в текущей зоне. Список ассоциативный. Попробовал получать его прямым перебором - неудобно. Лучше использовать for..in. Причем в качестве ключа устанавливаются целочисленные значения, генерируемые по усмотрению сервера - идентификаторы комнат.

onRoomVariablesUpdate : String
Обновились переменные комнаты.
Принимаются переменные только текущей комнаты (комнат).
Принимаются только переменные, которые изменились.
Параметры, переданные через params:
room : Room - объект представляющий комнату, где произошли изменения.
changedVars : Array - ассоциативный массив переменных.

onRoundTripResponse : String
Ответ на запрос SmartFoxClient.roundTripBench, измерение скорости соединения. Желательно провести серию измерений в течении 3-5 секунд и вычислить среднее значение скорости.
Параметры, переданные через params:
elapsed : int - измеренное время запроса/ответа сервера.

onSpectatorSwitched : String
Ответ на запрос SmartFoxClient.switchSpectator, смену наблюдателя на игрока.
Параметры, переданные через params:
success: Boolean - true - наблюдатель успешно сменился на игрока.
newId : int - идентификатор игрока (слот).
room : Room - объект, представляющий комнату, в которой произошла смена.

onUserCountChange : String
Изменилось количество пользователей в какой-либо из комнат текущей зоны.
Параметры, переданные через params:
room : Room - объект, представляющий комнату, в которой произошло изменение.
ВАЖНО: Событие не генерируется, если в натройках конфигурации зоны или текущей комнаты uCountUpdate не установлены или установлены в false. Отключение этого параметра позволяет сэкономить трафик. Однако, это в этом случае, учет миграции пользователей по комнатам перекладывается именно на клиентскую часть. Используя события onUserEnterRoom и onUserLeaveRoom можно отлавливать изменения только в комнатах, к которым подключен пользователь. Обычно в многопользовательских играх, обновление списка комнат осуществляется по запросу (кнопка "Обновить").
Кроме того, событие не генерируется, если текущий пользователь не вошел ни в одну из комнат.

onUserEnterRoom : String
Новый пользователь вошел в комнату.
Параметры, переданные через params:
roomId : int - идентификатор комнаты, к которой подключился пользователь.
user : User - объект, представляющий пользователя, подключившегося к комнате.

onUserLeaveRoom : String
Пользователь покинул комнату или отключился от сервера.
Параметры, переданные через params:
roomId : int - идентификатор комнаты, к которой подключился пользователь.
userId: int - идентификатор пользователя, покинувшего комнату.
userName: String - имя пользователя, покинувшего комнату.

onUserVariablesUpdate : String
Пользователь в текущей комнате изменил свои переменные.
Параметры, переданные через params:
user : User - объект, представляющий пользователя, изменившего свои переменные.
changedVars: Array - ассоциативный массив переменных. Передаются только измененные переменные.
Событие приходит только при изменении параметров других пользователей.

Класс SmartFoxClient. SmartFoxServer

Класс SmartFoxClient - главный класс SmartFoxServer API.

Полное определение класса: it.gotoandplay.smartfoxserver.SmartFoxClient
Потомок EventDispatcher

Конструктор:

SmartFoxClient (debug:Boolean = false)
debug - включить сообщения отладки.

Свойства:

ipAddress : String - IP-адрес SmartFoxServer.
port : int - порт для соединения со SmartFoxServer.
defaultZone : String - зона логина по умолчанию.
blueBoxIpAddress : String - IP адрес BlueBox (фича, позволяющая организовать соединение для клиентов, которые находятся за Proxy или Firewall. Прямое сокетное соединение для них не доступно, и связь осуществляется через HTTP-туннель).
blueBoxPort : Number - порт для соединения с BlueBox.
smartConnect : Boolean - позволяет включать BlueBox при отсутствии прямого сокетного соединения.
buddyList : Array - список друзей. Массив объектов, содержащих параметры каждого друга.
myBuddyVars : Array - ассоциативный массив, содержащий переменные друзей.
debug : Boolean - включает вывод отладочной информации на клиенте. Выводятся все принятые/отправленные сообщения.
myUserId : int - идентификатор текущего пользователя, который SmartFoxServer присваивает пользователю при его успешном подключении.
myUserName : String - имя текущего пользователя. Доступно только после успешной авторизации пользователя.
playerId : int - идентификатор текущего пользователя (или слот) в игровой комнате. Доступен только после подключения к игровой комнате. Отсчет начинается с 1.
amIModerator : Boolean - показывает, что сервер опознал пользователя как модератора.
activeRoomId : int - идентификатор комнаты, к которой последней раз подключался текущий пользователь. Если пользователь не вошел ни в одну в комнату, равен -1.
httpPort : int - TCP-порт, который прослушивает встроенный в SmartFoxServer веб-сервер. По умолчанию 8080.
rawProtocolSeparator : String - разделительный символ для протокола String (raw). Должен совпадать со значением <RawProtocolSeparator> в конфигурации сервера.
isConnected : Boolean - показывает, что текущий пользователь соединен с сервером.
httpPollSpeed : int - минимальный интервал в миллисекундах между двумя запросами к SmartFoxServer при использовании BlueBox. По умолчанию 750. Не рекомендуются значения меньше 50.

Методы:

loadConfig (configFile:String = "config.xml", autoConnect:Boolean = true) : void
Загружает файл внешней конфигурации клиента.
configFile - имя файла внешней конфигурации клиента. Не следует путать с файлом конфигурации сервера.
autoConnect - после успешной загрузки файла конфигурации, автоматически вызвать метод connect().
Пример файла конфигурации:


<SmartFoxClient>
<ip>127.0.0.1</ip>
<port>9339</port>
<zone>simpleChat</zone>
<debug>true</debug>
<blueBoxIpAddress>127.0.0.1</blueBoxIpAddress>
<blueBoxPort>9339</blueBoxPort>
<smartConnect>true</smartConnect>
<httpPort>8080</httpPort>
<httpPollSpeed>750</httpPollSpeed>
<rawProtocolSeparator>%</rawProtocolSeparator>
</SmartFoxClient>



getConnectionMode () : String
Возвращает текущий режим соединения:
CONNECTION_MODE_DISCONNECTED - нет соединения.
CONNECTION_MODE_SOCKET - сокетное соединение.
CONNECTION_MODE_HTTP - соединение по http-туннелю.

connect (ipAdr:String, port:int = 9339) : void
Устанавливает соединение с SmartFoxServer.
ipAdr - IP-адрес сервера
port - порт сервера

disconnect () : void
Закрывает соединение с SmartFoxServer.

addBuddy (buddyName:String) : void
Добавляет пользователя в список друзей.
buddyName - имя добавляемого пользователя.

autoJoin () : void
Автоматически присоединяет пользователя к комнате, заданной в текущей зоне как комната для соединения по умолчанию.

clearBuddyList () : void
Удаляет всех пользователей из списка друзей. (Устаревший)

createRoom (roomObj:Object, roomId:int = -1) : void
Динамически создает комнату в текущей зоне. Если комната игровая, то пользователь автоматически присоединяется к вновь созданной комнате.
name, maxUsers, maxSpectators, isGame, uCount, vars, extension - аналогичны параметрам конфигурации комнат.
password : Устанавливает пароль на комнату и делает ее приватной.
exitCurrentRoom: Если комната игровая - присоединяться к комнате сразу после ее создания.

getAllRooms () : Array
Возвращает список всех комнат в текущей зоне. Каждый из элементов - объект it.gotoandplay.smartfoxserver.data.Room. Возвращается список комнат, который хранится на клиенте. Запрос на сервер не отправляется.

getBuddyByName (buddyName:String) : Object
Получить объект с параметрами друга из списка друзей используя имя.
buddyName - имя друга.

getBuddyById (id:int) : Object
Получить объект с параметрами друга из списка друзей используя идентификатор.
id - идентификатор друга.

Возвращаемый объкт содержит свойства:
id : идентификатор друга.
name : имя друга.
isOnline : друг в режиме on=line.
isBlocked : друг заблокирован
variables : переменные друга.

getBuddyRoom (buddy:Object) : void
Послать запрос на получение идентификатора комнаты, в которой находится друг.
buddy - объект искомого друга из списка друзей.

getRoom (roomId:int) : Room
Получить объект комнаты из списка комнат, используя идентификатор.
ОЧЕНЬ ВАЖНО: Объект Room не будет получать переменные, если в конфигурации параметр roomListVars не установлен, или установлен в false. Методы getVariable() и getVariables() не будут возвращать никаких переменных.

getRoomByName (roomName:String) : Room
Получить объект комнаты из списка комнат, используя имя комнаты.

getRoomList () : void
На сервер отправляется запрос на получение списока всех комнат в текущей зоне. Затем, обработав событие onRoomListUpdate, можно получить свежий список комнат.

getActiveRoom () : Room
Возвращает объект текущей активной комнаты. Сервер позволяет присоединяться к нескольким комнатам одновременно.

getRandomKey () : void
Послать запрос серверу на получение строки с уникальной последовательностью случайных символов. Затем, обработав событие onRandomKey, можно получить строку с ключом.

getUploadPath () : String
Получить http-адрес директории для закачки на сервер файлов по умолчанию.

getVersion () : String
Получить версию SmartFoxServer Flash API.

joinRoom (newRoom:*, pword:String = "", isSpectator:Boolean = false, dontLeave:Boolean = false, oldRoom:int = -1) : void
Подключиться к комнате.
newRoom - Если String, то имя комнаты, если int - идентификатор.
pword - пароль для входа, если комната приватная.
isSpectator - присоединиться в качестве наблюдателя.
dontLeave - покидать ли текущую комнату.
oldRoom - идентификатор покидаемой комнаты.
ВАЖНО: Возможно только после получения события onRoomListUpdate, автоматически генерируемого после авторизации в зоне.

leaveRoom (roomId:int) : void
Покинуть комнату.
roomId - идентификатор комнаты.

loadBuddyList () : void
Загрузить список друзей для текущего пользователя.

login (zone:String, name:String, pass:String) : void
Осуществить стандартную процедуру авторизации. Авторизация подтверждается событием onLogin.
zone - Имя зоны.
name - Имя пользователя.
pass - Пароль пользователя.

logout () : void
Выйти из текущей зоны. Выход подтверждается событием onLogout.

removeBuddy (buddyName:String) : void
Удалить друга из списка друзей.
buddyName - имя друга.

roundTripBench () : void
Послать запрос на определение скорости соединения. Ответ можно получить по событию onRoundTripResponse.

sendBuddyPermissionResponse (allowBuddy:Boolean, targetBuddy:String) : void
Послать запрос на разрешение добавить себя в список друзей.
allowBuddy - разрешить/не разрешить.
targetBuddy - имя друга.

sendPublicMessage (message:String, roomId:int = -1) : void
Послать массовое сообщение в текущую комнату.
message - текст сообщения.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

sendPrivateMessage (message:String, recipientId:int, roomId:int = -1) : void
Послать приватное сообщение пользователю.
message - текст сообщения.
recipientId - идентификатор пользователя, которому отправляется сообщение.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

sendModeratorMessage (message:String, type:String, id:int = -1) : void
Послать сообщение модератора в текущую зону, комнату, или конкретному пользователю в текущей комнате.
message - текст сообщения.
type -
MODMSG_TO_USER: сообщение пользователю,
MODMSG_TO_ROOM: сообщение в комнату,
MODMSG_TO_ZONE: сообщение в зону.
id - идентификатор зоны, комнаты, или пользователя.

sendObject (obj:Object, roomId:int = -1) : void
Послать объект Actionscript пользователям текущей комнаты.
obj - объект Actionscript.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

sendObjectToGroup (obj:Object, userList:Array, roomId:int = -1) : void
Послать объект Actionscript пользователям текущей комнаты.
obj - объект Actionscript.
userList - список идентификаторов пользователей.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

sendXtMessage (xtName:String, cmd:String, paramObj:*, type:String = "xml", roomId:int = -1) : void
Запрос на выполнение серверного скрипта (расширения).
xtName - имя серверного скрипта.
cmd - имя команды (функции), предусмотренной в скрипте.
paramObj - объект, содержащий данные для передачи в серверный скрипт
type - тип протокола для сериализации запроса.
XTMSG_TYPE_XML: формат XML
XTMSG_TYPE_STR: строка с разделителем (raw протокол)
XTMSG_TYPE_JSON: протокол JSON.
Для сокращения трафика не рекомендуется использовать XML.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

setBuddyBlockStatus (buddyName:String, status:Boolean) : void
Заблокировать/разблокировать пользователя в списке друзей.
buddyName - имя друга
status - true - заблокировать, false - разблокировать.

setBuddyVariables (varList:Array) : void
Установить переменные друга для текущего пользователя (сам пользователь рассматривается как чей-то друг).
varList - ассоциативный массив, где ключ - имя переменной, значение - значение переменной.

setRoomVariables (varList:Array, roomId:int = -1, setOwnership:Boolean = true) : void
Установить переменные комнаты. Переменные комнаты полезны для организации централизованного хранилища данных, доступных всем клиентам комнаты. При изменении/добавлении/удалении данных все пользователи уведомляются об этом событием onRoomVariablesUpdate .
varList - массив объектов переменных.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.
setOwnership - false - для предотвращения изменения переменной в случае, если ее значение изменено другим пользователем.

Объект переменной:
name : String - имя переменной.
val : * - значение переменной.
priv : Boolean - если true, изменять переменную может только ее создатель.
persistent : Boolean - если true, переменная существует до тех пор, пока ее создатель подключен к зоне, если false - переменная существует до тех пор, пока ее создатель подключен к комнате. По умолчанию - false.

setUserVariables (varObj:Object, roomId:int = -1) : void
Установить переменные одного или нескольких пользователей.
varObj - объект, в котором каждое из свойств является переменной для установки/изменения.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.

switchSpectator (roomId:int = -1) : void
Переключиться из режима наблюдателя в режим игрока. Работает при условии наличия свободного слота. Смена подтверждается событием onSpectatorSwitched.
roomId - идентификатор комнаты, в случае если пользователь соединен с несколькими комнатами.
ВАЖНО: Переключение происходит лишь один раз: наблюдатель - игрок. Обратного переключения нет. После запроса, приходит событие подтверждения переключения. Как только пользователь стал игроком, переключение можно вызывать сколько угодно - ответ от сервера не прийдет.

uploadFile (fileRef:FileReference, id:int = -1, nick:String = "", port:int = -1) : void
Загрузить файл на встроенный в SmartFoxServer веб-сервер.
Upload a file to the embedded webserver.
fileRef - объект flash.net.FileReference.
id - идентификатор текущего пользователя.
nick - имя текущего пользователя.
port - порт встроенного веб-сервера