Перейти к содержимому
Для публикации в этом разделе необходимо провести 1 боёв.
MatroseFuchs

Unbound + ModsAPI

В этой теме 1 комментарий

Рекомендуемые комментарии

Разработчик
61 публикация
787 боёв

В этом руководстве разберем на простом примере как добавить и использовать технологию Unbound на сцене ModAPI.

 

Т.к. верстка Unbound обрабатывается на стороне Flash, то разработка мода будет связана в осноном с файлами ActionScript.

Итак, нам понадобится обработчик верстки и основной файл для Flash API аналогичный тому что мы уже делали в предыдущих примерах.

Но сначала подготовим XML файлик с простым кодом верстки, над которым будем эксперементировать, например нарисуем квадрат в углу.

 

test_window.xml

Создадим XML файл с простенькой версткой простого белого квадрата.

 

Скрытый текст

<ui>
    <block className="TestElement">
        <block>
            <style>
                <position value="absolute"/>
                <left value="10px"/>
                <top value="10px"/>
                <width value="100px"/>
                <height value="100px"/>
                <backgroundColor value="0xEEEEEEEE"/>
            </style>
        </block>
    </block>
</ui>

 

 

Полученный XML файл необходимо прогнать через утилиту "xml2as.bat", чтобы скомпилировать выражения верстки в SWF файл аналогично тому что мы делали с модификацией готовых XML. Полученный SWF файл положим в "..\res_mods\<X.X.X.X>\gui\unbound\flash" и добавим его путь в "..\gui\flash\USSExpressionsLoader.xml".

 

Movie.as

Для обработки XML файлов с версткой Unbound нам нужно создать инструмент обработки. Для этого откроем редактор AcrionScript (например FlashDevelop) и создадим новый проект. Основной Flash файл мода назовем, как это принято "Main.as", а для обработки верстки создадим другой и назавем его например "Movie.as" с которого и начнем.

 

Наш класс обработчика Movie нам нужно унаследовать от класса "ScaleformMovie", который мы импортируем из внешней библиотеки "wows_library.swc" (см. настройку редактора), командой "import lesta.dialogs.ScaleformMovie;". В этом родительском классе у нас будет почти весь необходимый арсенал для работы с версткой Unbound.

Далее объявим переменную для "элемента" верстки "private var unboundElement:UnboundElement;" и импортируем этот тип данных "import lesta.libs.unbound.UnboundElement;". Еще нам понадобится контроллер для нашего элемента, объявим и его "private var unboundController:UnboundElementController;", так же импортируем его класс "import lesta.dialogs.battle_window_controllers.UnboundElementController;".

 

Т.к. наш класс обработчик унаследован от родительского класса, то теперь необходимо корректно описать главную функцию класса "public function Movie()". Если мы заглянем в родительский класс, то увидим что его главная функция имеет три параметра, поэтому нам тоже нужно задать эти три параметра. При создании экземпляра нашего класса мы передадим туда все необходимые параметры.

Теперь в этой функции Movie() по правилам добавим вызов родительского класса (super()) и передадим ему параметры функции нашего класса. Здесь же добавим коллбэк, который будет обновлять размер сцены элемента.

 

Следующую функцию которую мы опишем будет основная функция обработки верстки. Итак, объявим функцию, например назавем ее "public function buildUnboundApplication():void", создадим экземпляр элемента "new UnboundElement()". Теперь нашему элементу нужно указать в свойстве "config" путь до XML файл с версткой. Это можно сделать например указав прямой путь в формате "C:\\Games\\World_of_Warships\\res_mods\\0.8.7.0\\PnFMods\\ubtest\\test_window.xml" (так указывется путь в ActionScript), или добавиф функцию поиска файла "get configPath()", это нужно из-за особенностей загрузки файлов, т.к папка с модом находится вне дериктроии загрузки файлов. После этого в свойстве элемента "rootElementId" укажем название элемента в верстке, который будет главным за отображение на сцене.

Далее нам нужно создать экземпляр контроллера элемента "new UnboundElementController()", который будет ответственным за загрузку этого элемента. В свойство "clip" нужно задать экземпляр элемента "unboundElement", через метод "setDataHub" в свойство контроллера добавим экземпляр датахаба "setDataHub(dataHub)", который мы передадим при инициализации "Movie" (этот экземпляр dataHub не будет содержать данных но добавить его нужно), через метод "setUbCentral" добавим экземпляр "protoCentral" (будет содержать все байндинги), который находится в родительском классе "ScaleformMovie", далее с помощью метода "initController()" инициализируем его.

Теперь зададим размер сцены элемента вызвав функцию "setStageSize"и передадим ей размеры сцены из оснвного класса Main мода, который мы опишем далее. В функции создадим екземпляр сцены из доступных компонентов "lesta.components.Stage", и зададим атрибуты компонента "width, height, scale и evStageSizeChanged", затем передадим эти размеры контроллеру элемента.

И наконец добавим наш элемент на сцену "addChild(unboundElement)".

 

Скрытый текст

package
{
    import flash.display.*;
    import lesta.components.*;
    import lesta.api.GameAPI;
    import lesta.api.constants.Calls;
    import lesta.constants.ComponentClass;
    import lesta.datahub.DataHub;
    import lesta.dialogs.ScaleformMovie;
    import lesta.dialogs.battle_window_controllers.UnboundElementController;
    import lesta.libs.unbound.UnboundElement;
     
    /**
     * ...
     * @author
     */
    public class Movie extends ScaleformMovie
    {
        private var unboundElement:UnboundElement;
        private var unboundController:UnboundElementController;
         
        public function Movie(param0:DataHub, stage:flash.display.Stage, gameAPI:GameAPI)
        {
            super(param0, null, stage);
            gameAPI.data.addCallBack(Calls.UPDATE_STAGE, this.setStageSize);
        }
         
        public function buildUnboundApplication():void
        {
            unboundElement = new UnboundElement();
            // unboundElement.config = "C:\\Games\\World_of_Warships\\res_mods\\0.8.7.0\\PnFMods\\ubtest\\test_window.xml";
            unboundElement.config = this.configPath;
            unboundElement.rootElementId = "TestElement";
            setupUnbound();
            unboundController = new UnboundElementController();
            unboundController.clip = unboundElement;
            unboundController.setDataHub(dataHub);
            unboundController.setUbCentral(protoCentral);
            unboundController.initController();
            setStageSize(stage.stageWidth, stage.stageHeight);
            addChild(unboundElement);
        }
         
        private function get folderPath():String
        {
            var normalisedUrl:String = this.loaderInfo.url.split('/').join('\\');
            return normalisedUrl.substr(0, normalisedUrl.lastIndexOf('\\'));
        }
 
        private function get configPath():String
        {
            return [this.folderPath, "test_window.xml"].join('\\');
        }
         
        public function setStageSize(stageW:Number, stageH:Number):void
        {
            var stage: lesta.components.Stage = this.dataHub.getSingleComponent(ComponentClass.stage) as lesta.components.Stage;
            stage.width = stageW;
            stage.height = stageH;
            stage.scale = 1.0;
            stage.evStageSizeChanged.invoke([stage]);
            unboundController.updateStageSize(stageW, stageH);
        }
    }
 
}

 

 

 

Main.as

В оснвном классе мода объявим две переменные - "dataHub:DataHub" и "movie:Movie" (наш обработчик верстки). В главной функции класса создадим экземпляр датахаба и объявим вызов "super();" главной функции родительского класса "ModBase" от которого мы наследуем наш "Main".

 

Переопределим функцию "init()" родительского класса "ModBase" и опишем ее, т.к. она будет выполняться при инициализации (при необходимости можно переопределить другие функции родительского класса). В этой функции нам так же нужно вызвать переопределяемую функцию родительского класса "super.init();", теперь создадим экземпляр обработчика верстки "movie" и передадим ему требуемые параметры "new Movie(dataHub, this.stage, gameAPI)". Далее добавим экземпляр обработчка верстки в контейнер нашего мода "addChild(movie)", добавим обработчику прослушиватель события добавления его на сцену "movie.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);" и добавим ссылку нашего мода на сцену ModAPI "gameAPI.stage.addChild(this)".

 

Опишем последнюю функцию, которая будет вызываться при загрузке обработчика на сцену "onAddedToStage(event:Event)". Чтобы Scaleform принял наш movie, нам нужно создать сущность "entity" с id сцены (id - ComponentClass.stage), компонент сцены "stageComponent" с этим же id, добавить в сущность компонент сцены, получить коллекцию сущностей с компонентами сцен и в эту коллекуию добавить нашу сущность "collection.add(entity)". Теперь мы можем использовать метод нашего обработчика для вывода результата на сцену "movie.buildUnboundApplication();" и удалим прослушиватель, т.к. он нам больше не нужен, наш элемент теперь на сцене ModAPI.

 

Скрытый текст

package
{
    import flash.events.Event;
    import lesta.api.GameAPI;
    import lesta.api.ModBase;
    import lesta.components.Stage;
    import lesta.constants.ComponentClass;
    import lesta.datahub.DataHub;
    import lesta.datahub.Collection;
    import lesta.datahub.Entity;
     
    public class Main extends ModBase
    {
        public var dataHub:DataHub;
        private var movie:Movie;
         
        public function Main()
        {
            dataHub = new DataHub();
            super();
        }
         
        override public function init():void
        {
            super.init();
            movie = new Movie(dataHub, this.stage, gameAPI);
            addChild(movie);
            movie.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            gameAPI.stage.addChild(this);
        }
         
        public function onAddedToStage(event:Event):void
        {
            var entity:Entity = dataHub.createEntity(ComponentClass.stage);
            var stageComponent:Stage = dataHub.createComponent(ComponentClass.stage) as Stage;
            entity.addComponent(stageComponent);
            var collection:Collection = this.dataHub.getCollection(ComponentClass.stage);
            collection.add(entity);
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            movie.buildUnboundApplication();
        }
    }
}

 

 

 

Mod on unbound

Скомпилируем наш проект и получившийся файл Main.swf (название конечного файла проекта можно задать в свойствах проекта) положим в папку мода. Добавим туда файл Main.py в котором напишем одну строчку "API_VERSION = 'API_v1.0'", т.к. без нее мод работать не будет. В папку с модом добавим наш подготовленный XML файл с версткой, а скомпилированный SWF файл из XML-ки положим в "gui\unbound\flash" и добавим к ней путь в "gui\flash\USSExpressionsLoader.xml". Запустим клиент игры и убедимся что наш мод обработал файл с версткой и отобразил в углу окна игры квадратик белого цвета.

 

test_window.jpg

 

Добавляем данные в скоуп

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

Итак, создадим в проекте новый *.as файл и назавем его "MyUbController", он будет наследовать от класса "UbController". В контроллере переопределим метод "override public function init(param1:Vector.<IUbExpression>):void" чтобы в него можно было передавать вычисленые аргументы. Передадим аргументы в родительский класс "super.init(param1);" и запишем в скоуп строку, которую потом отобразим "scope.myText = "Text";".

 

Скрытый текст

package
{
    import lesta.unbound.core.UbController;
    import lesta.unbound.expression.IUbExpression;
 
    public class MyUbController extends UbController
    {
         
        public function MyUbController()
        {
            super();
        }
         
        override public function init(param1:Vector.<IUbExpression>):void
        {
            super.init(param1);
            scope.myText = "Text";
        }
    }
}

 

 

Наш контроллер готов.

 

Добавим в основной файл "Main.as" контроллер через "import" если файл лежит в подкаталоге, или как в нашем случае контроллер лежит в одном каталоге с другими файлами проекта, тогда просто объявим контроллер "MyUbController;" чтобы инициализировать его и данные контроллера можно было использовать (если ваш контроллер находится в томже каталоге что и Main.as, то импортировать его не требуется), либо настроить ваш редактор таким образом, чтобы при сборке SWF файла он включал так же не используемые файлы проекта.

 

Скрытый текст

package
{
    import flash.events.Event;
    import lesta.api.GameAPI;
    import lesta.api.ModBase;
    import lesta.components.Stage;
    import lesta.constants.ComponentClass;
    import lesta.datahub.DataHub;
    import lesta.datahub.Collection;
    import lesta.datahub.Entity;
     
    public class Main extends ModBase
    {
        public var dataHub:DataHub;
        private var movie:Movie;
         
        public function Main()
        {
            dataHub = new DataHub();
            MyUbController;        // <---  initialise MyUbController
            super();
        }
         
        override public function init():void
        {
            super.init();
            movie = new Movie(dataHub, this.stage, gameAPI);
            addChild(movie);
            movie.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            gameAPI.stage.addChild(this);
        }
         
        public function onAddedToStage(... rest):void
        {
            var entity:Entity = dataHub.createEntity(ComponentClass.stage);
            var stageComponent:Stage = dataHub.createComponent(ComponentClass.stage) as Stage;
            entity.addComponent(stageComponent);
            var collection:Collection = this.dataHub.getCollection(ComponentClass.stage);
            collection.add(entity);
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            movie.buildUnboundApplication();
        }
    }
}

 

 

Теперь добавим полученный контроллер в XML файл, добавим текстовый блок и используем данные из скоупа для отображения. Не забываем что полсле изменения верстки необходимо пересобрать ее SWF-ку, в противном случае изменения мы не увидим.

 

Скрытый текст

<ui>
    <block className="TestElement">
        <bind name="controller" value="MyUbController"/>
        <block>
            <style>
                <position value="absolute"/>
                <left value="10px"/>
                <top value="10px"/>
                <width value="100px"/>
                <height value="100px"/>
                <backgroundColor value="0xEEEEEEEE"/>
            </style>
            <block type="text">
                <styleClass value="$TextDefault"/>
                <bind name="text" value="myText"/>
            </block>
        </block>
    </block>
</ui>

 

 

Запустим игру и посмотрим на результат.

 

test_window_and_controller.jpg

 

Наш простенький мод готов.

 

PS

Для того чтобы перетаскивать наш отрисованный элемент и при этом не ломалась верстка, необходимо создать файл настроек "UserPrefs" в котором они будут храниться и обновляться, и соответственно написать соответствующую логику.

 

  • Плюс 7

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах

×