Jump to content
Korean Random

aks1983

User
  • Posts

    23
  • Joined

  • Last visited

Posts posted by aks1983

  1. из импортов там:

    два шрифта ($FieldFont и $TitleFont) из gfxfontlib.swf 

    три символа барабанов (LightClipQuantityBar, MediumClipQuantityBar и HeavyClipQuantityBar) из crosshairClipQuantityBars.swf 

    таймер перезарядки (ReloadingTimeFieldUI) из crosshairReloadingTimeField.swf

     

    это я знаю, вопрос в другом - как в Adobe Flash выглядит правильный импорт? я добавлял символы в библиотеку через "Import for runtime sharing", при этом, если эти символы не используются, они не импортируются (отсутствует ImportAssets2), при их использовании - флешка не работает.

     

    я декомпилирую в JPEXS FFDec оригинальные флешки в xfl формат. в этом файле отсутствуют символы, которые должны быть импортированы, а вручную помещать их в библиотеку и дальше - на место - очень неудобно.

     

    в идеале, я хотел бы получить *.xfl-проект, в котором легко изменять изображения и скрипты и компилировать через publish.

     

    • Upvote 1
  2. нужна информация о том, как собирать arcadeCrosshair.swf crosshairControls.swf crosshairPanelContainer.swf postmortemCrosshair.swf sniperCrosshair.swf strategicCrosshair.swf

    файлы импортируют друг друга, каким образом добиться этого в редакторе Flash? например, arcadeCrosshair.swf имеет зависимость от crosshairControls.swf, каким образом правильно указать импортирование в Adobe Flash? Как должен называться этот символ в библиотеке, и в какие символы его добавить?

     

  3. Небольшой спойлер: у нас в планах есть открытие подраздела официальной танковой вики про мододельство - аналогично тому, как это сделано у Бетесды. Сразу там, конечно, доков по всей архитектуре танков не появится, но тем не менее какая-то полезная информация для мододельства будет наливаться как со стороны WG, так и (надеюсь) со стороны коммьюнити мододелов. По изменениям в патчах/микропатчах можно сваливать все замеченное туда, чтобы каждому мододелу не приходилось самостоятельно все искать. Но тут все сильно зависит от того, захотите ли вы сами таким заниматься и шарить полученную информацию с другими мододелами в вики.

     

    Идея отличнейшая, поскольку накопилось уже достаточно материалов и понимания структуры движка, часть из которых являются догадками. Конечно, жаль что так поздно вы до нас снизошли.

  4. Вы забываете, для чего пишут игры, WoT в том числе. Я вас уверяю, если бы танки делали люди, для которым важно внимание к таким мелочам, игра бы не стали известной. И у этой ниши другое название - инди игры.

     

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

     

    Есть системные требования, и в этих рамках игра работает нормально - следовательно, задача разработчиков выполнена (не важно, каким образом), они получили зарплату и пошли домой.

     

    Есть финансовые показатели, и иногда они падают. За это отвечают не разработчики, а отдел маркетинга. Тогда у нас и появляются ненужные HD-модели и т.п.

     

    А по поводу вопроса автора темы - это всё адекватно в рамках такого видения мира.

    • Upvote 1
  5. Итак, вы уже создали библиотеки lobby.swc, battle.swc и common.swc, а потом программным образом создали окно, а в нём контролы.

    Всё хорошо, но хотелось бы в визуальный редактор, типа gui-builder. К тому же, чтобы сделать окно, нужно создавать классы, и добавлять в него контент программно. На самом деле это можно делать во Flash, только с некоторыми оговорками.

     

    Для начала, рассмотрим как работает GUI в танках. Что мы знаем:

    • есть набор классов net.wg.gui
    • есть файлы gui*.swf c графикой и анимацией
    • во Flash есть возможность использовать символы из внешних swf
    • во Flash есть возможность подключать swc

    Итак, поехали.

    Делаем окно с кастомными кнопками - MainView.as

    import net.wg.gui.components.controls.SoundButtonEx;
    import net.wg.gui.lobby.header.FightButton;
    import net.wg.infrastructure.base.AbstractWindowView;
    
    import scaleform.clik.events.ButtonEvent;
    
    public class MainView extends AbstractWindowView {
    
        public var redButton:FightButton;
        public var buttonNormal:SoundButtonEx;
    
        public function MainView() {
            super();
        }
    
        override protected function configUI():void {
            super.configUI();
            window.title = "Моё окно";
            if (redButton) { // можно смело убрать эти if
                redButton.label = "Просто кнопка";
            }
            if (buttonNormal) { // можно смело убрать эти if
                buttonNormal.label = "Закрыть окно";
                buttonNormal.addEventListener(ButtonEvent.CLICK, this.onClickHandler);
            }
        }
    
        override protected function onDispose():void {
            if (redButton) { // можно смело убрать эти if
                redButton.dispose();
            }
            if (buttonNormal) { // можно смело убрать эти if
                buttonNormal.removeEventListener(ButtonEvent.CLICK, this.onClickHandler);
                buttonNormal.dispose();
            }
            super.onDispose();
        }
    
        private function onClickHandler(param1:ButtonEvent):void {
            onWindowCloseS();
        }
    }
    

    Создаём пустой Flash, идём в File -> ActionScript Settings... и добавляем в Source Path путь к MainView.as; На втором табе подключаем lobby.swc; снимаем галку "Automatically declare stage instances". В поле Document Class вписываем MainView.

    Нажимаем Ctrl+L, создаём новый символ - RedButton с классом RedButton ставим галку "Import for runtime sharing" и вписываем в поле "guiControlsLogin.swf". Аналогично, делаем ButtonNormal, только вместо guiControlsLogin.swf импортируем из guiControlsLoginBattle.swf

    Теперь надо создать инстансы символов. Перетащим на сцену RedButton и назовём его redButton, перетащим ButtonNormal и назовём его buttonNormal (они выглядят пустыми). Вы заметили, что в классе MainView есть два публичных поля с аналогичными именами? Попробуем сделать Publish и полученный файл - MainView.swf - поместим в \res_mods\[VERSION]\gui\flash

     

    Когда эта swf загрузится, она будет иметь класс документа MainView, в котором redButton и buttonNormal проинициализируются импортированными символами.

    Последнее - загрузчик в \res_mods\[VERSION]\scripts\client\gui\mods\mod_test.py:

    #
    # mod_test.py
    #
    
    from gui.Scaleform.framework import ViewTypes
    from gui.Scaleform.framework import g_entitiesFactories, ViewSettings, ScopeTemplates
    from gui.Scaleform.framework.entities.abstract.AbstractWindowView import AbstractWindowView
    from gui.app_loader import g_appLoader
    from gui.app_loader.settings import APP_NAME_SPACE
    from gui.shared import EVENT_BUS_SCOPE
    from gui.shared import events
    from gui.shared import g_eventBus
    
    MAIN_VIEW_ALIAS = 'test/mainview'
    
    
    class MainViewMeta(AbstractWindowView):
        pass
    
    
    class MainView(MainViewMeta):
        def __init__(self, ctx):
            super(MainView, self).__init__()
    
        def _populate(self):
            super(MainView, self)._populate()
    
        def _dispose(self):
            super(MainView, self)._dispose()
    
        def onWindowClose(self):
            self.destroy()
    
    
    def onLobbyAppInitialized(event):
        if event.ns != APP_NAME_SPACE.SF_LOBBY:
            return
    
        app = g_appLoader.getDefLobbyApp()
        app.loadView(MAIN_VIEW_ALIAS, ctx={})
    
    
    g_entitiesFactories.addSettings(ViewSettings(MAIN_VIEW_ALIAS, MainView, 'MainView.swf', ViewTypes.WINDOW, None, ScopeTemplates.GLOBAL_SCOPE, False))
    
    # покажем окно сразу после загрузки лобби
    g_eventBus.addListener(events.AppLifeCycleEvent.INITIALIZED, onLobbyAppInitialized, EVENT_BUS_SCOPE.GLOBAL)
    

    Вот такой результат получился у меня, кнопки нажимаются (две голубые кнопки вверху - другой эксперимент):

    shot_004.jpg

     

     

    Думаю, теперь понятно, как делать более сложные интерфейсы - надо импротировать другие контролы. Где они находятся, можно выяснить только посмотрев, что внутри файлов gui*.swf

     

    Подводные камни:

    • во Flash не видно размеров контролов, вообще ничего не видно
    • (не проверял, но думаю что) не все gui*.swf можно использовать, некоторые - не загружены
    • Upvote 4
  6. Делаю переход свободная камера <-> привязанная камера. Штатно это работает по нажатию CAPS+F3, но мне требуется своя реализация.

    Код таков:

    # sometimes we need to do it
    def checkAndRetry(check, retry):
        BigWorld.callback(0.2, lambda: check() and retry())
    
    def switchFreeCamera(attemps=5):
        aih = BigWorld.player().inputHandler
    
        # enable switchung before battle start
        aih._AvatarInputHandler__isStarted = True
    
        # 0.9.17 intoduced isObserverFPV
        if not aih.isObserverFPV and attemps > 0:
            prev_mode = aih.ctrlModeName
            if prev_mode == 'video':
                mode = 'postmortem' if BigWorld.player().isObserver() else 'arcade'
                aih.ctrl.setForcedGuiControlMode(False)
                aih.onControlModeChanged(mode, prevModeName=prev_mode)
                checkAndRetry(lambda: aih.ctrlModeName != mode, lambda: switchFreeCamera(attemps - 1))
            else:
                cam_matrix = Math.Matrix(BigWorld.camera().matrix)
                aih.onControlModeChanged('video', prevModeName=prev_mode, camMatrix=cam_matrix)
                # leave inertia for smoother movement
                if BigWorld.player().vehicle is not None:
                    aih.ctrl._cam._VideoCamera__velocity = Math.Vector3(BigWorld.player().vehicle.filter.velocity)
    

    В 0.9.17 появился баг - камера улетает под землю, на ghost-танк наблюдателя. При возврате в arcade/postmortem выбирается совсем не тот танк, от которого я отвязывался.

    Исследовав метод onControlModeChanged, я ужаснулся его неструктуированности. Практически невозможно понять, как ведёт себя поток исполнения. Нашел конечные точки -
    это BigWorld.player().cell.bindToVehicle(vehicleID), BigWorld.player().cell.moveTo(pos) и BigWorld.player().cell.switchViewpoint(toPrevious)
     

    Кто-нибудь исследовал этот вопрос?

    • Upvote 1
  7. Спасибо, продвинулся, но проблема осталась.

    Сейчас реализация такая -

        private var _librariesLoaded:Boolean = false;
        private var _controlPopulated:Boolean = false;
    
    //в конструкторе:
    
            App.instance.loaderMgr.addEventListener(LibraryLoaderEvent.LOADED, this.onLoaderMangerLoadedHandler);
            App.instance.loaderMgr.loadLibraries(Vector.<String>([
                "guiControlsLobby.swf",
                "guiControlsLobbyBattle.swf",
                "guiControlsLobbyBattleDynamic.swf",
                "guiControlsLobbyDynamic.swf",
                "guiControlsLogin.swf",
                "guiControlsLoginBattle.swf",
                "guiControlsLoginBattleDynamic.swf"
            ]));
    
    // и далее:
    
        protected override function onPopulate():void {
            _controlPopulated = true;
            super.onPopulate();
            initControls();
        }
    
        private function onLoaderMangerLoadedHandler(e:LibraryLoaderEvent):void {
            // ловим загрузку последней либы из списка
            if (e.url.indexOf("guiControlsLoginBattleDynamic.swf") >= 0) {
                App.instance.loaderMgr.removeEventListener(LibraryLoaderEvent.LOADED, onLoaderMangerLoadedHandler);
                _librariesLoaded = true;
                initControls();
            }
        }
    
        private function initControls():void {
            DebugUtils.LOG_ERROR('!!!STATUS!!!', _librariesLoaded  + " : "  + _controlPopulated);
    
            // учитываем, что загрузка либ асинхронна (!!!):
            if (_librariesLoaded && _controlPopulated) {
                try {
                    // тут создаёся спрайт с контролами net.wg.gui.components.controls...
                    _panel = new MySuperPanel(this);
                    addChild(_panel);
                }
                catch (e:Error) {
                    DebugUtils.LOG_ERROR('!!!ERROR!!!', e);
                }
    
                DebugUtils.LOG_ERROR('!!!DONE!!!');
            }
        }
    
    

    Всё равно валится по 'Error extracting object with linkage: DropdownMenu'. Ж*па...

     

    Раньше (еще до решения с загрузкой либ) я указывал имя класса по полному имени - например net.wg.gui.components.controls::DropdownMenu, в этом случае не валится, но и контролов не видно (графика не загрузилась? или контролы не проинициализировались?)

     

    Попробуем сделать для теста простейшее окно с кнопкой и дропдауном на странице логина?
     

  8. W G что-то сделал с флешом. Теперь не создаются контролы:

            import net.wg.gui.components.controls.SoundButton;
    
    ...
    
            var btnZero:SoundButton = App.utils.classFactory.getComponent(
                    "net.wg.gui.components.controls::SoundButton",
                    SoundButton,
                    {label: "0:0", x: 150, y: 43, width: 27, height: 23}
            );
            btnZero.addEventListener(ButtonEvent.CLICK, handleZeroButtonPress);
            addChild(btnZero);
    

    Есть какие-нибудь идеи?

     

    UPD: так же не работают такие конструкции:

            var b:SoundButton = new SoundButton();
    
            b.label = 'test';
            b.x = 10;
            b.y = 10;
            b.width = 27;
            b.height= 23;
    
            addChild(b);
    
            b.validateNow();
    
            var b2:Button = new Button();
            b2.textField = new TextField();
            b2.textField.text = 'test1';
            b2.label = 'test2';
    
            b2.x = 100;
            b2.y = 10;
            b2.width = 27;
            b2.height= 23;
    
            addChild(b2);
    
            b2.validateNow();
    
  9. Смертельный, между прочим, для меня оказался, номер.

    Я сдался на третьи сутки, наткнувшись глазом на сук в виде import BigWorld

    Сдался, потому что подозреваю что этот объект, бигворльд, прячется внути флэшек,

    которые не могу подлинковать внутри PyCharm и не понимаю как при помощи https://www.free-decompiler.com/flash/

    распотрошить c:\Games\WoT\res_mods\0.9.15.2\gui\flash\* и главное, как подлинковать.

    Если этот путь уже кем-то пройден, оставьте вешку, может скриншот готового каталога, может копию потрошёных флэшек,

    или удастся вспомнить какие были грабли с ошибками декомпиляции флэшек.

     

    Мне тут в ЛС прочили что меньше чем за три месяца зависалова с потрохами танковых исходников въехать не получится.

    Боюсь, есть недооценка запутанности процесса.

     

     

     

    Привет!

     

    BigWorld - это built-in модуль движка (как и GUI, Math, ResMgr, _Scaleform и может что-то еще), по сути это API для связи Python <---> Движок

     

    В контексе флеша - BigWorld'а нет, флэш работает исключительно внутри Scaleform, который раскрыт в питоне модулем _Scaleform (смотрим scripts/client/gui/Scaleform/Flash.py)

     

    Если непонятно, то Scaleform это аналог Adobe Flash Player, имеет свой движок и набор базовый AS3-классов для построения интерфейса (как у Flash есть Flex). Кроме того, Wargaming создал свой набор классов для построения интерфейса игры - окна, кнопки и т.д. (это как Spark у Flex). Вот эти два набора нам и нужны для успешного собирания своих флешек, неймспейсы scaleform.click, scaleform.net (это классы Scaleform) и net.wg.* (это классы Wargaming). lobby.swf содержит наиболее полный набор классов для лобби, поэтому берем его, и battle.swf для боя.

     

    Создавать открытые репозитории этого кода мне кажется незаконным. Инструменты для автоматизации есть в репозитории XVM (но в него тоже надо вникать).

    • Upvote 1
  10. Пробую сделать переключение свободной камеры в привязанную, 'video' -> 'postmortem', и наткнулся на переполнение стека рекурсией

    # switch between modes
    def switchFreeCamera():
        pih = BigWorld.player().inputHandler
        if pih.ctrlModeName == 'video':
            mode = 'postmortem' if BigWorld.player().isObserver() else 'arcade'
            pih.onControlModeChanged(mode, prevModeName=pih.ctrlModeName)
        else:
            cam_matrix = Math.Matrix(BigWorld.camera().matrix)
            pih.onControlModeChanged('video', prevModeName=pih.ctrlModeName, camMatrix=cam_matrix)
        pih.ctrl.setForcedGuiControlMode(False)
    
    # switch to player from any mode
    def switchToPlayer():
        pih = BigWorld.player().inputHandler
        if pih.ctrlModeName != 'postmortem':
            pih._AvatarInputHandler__observerVehicle = vid
            pih.onControlModeChanged('postmortem', prevModeName=pih.ctrlModeName)
        else:
            pih.selectPlayer(vid)
    
    """
    python.log:
    
    
    2016-08-29 15:14:59.824: ERROR: [EXCEPTION] (scripts/common/Event.py, 46):
    Traceback (most recent call last):
      File "scripts/common/Event.py", line 44, in __call__
      File "scripts/client/AvatarInputHandler/__init__.py", line 582, in __onVehicleChanged
      File "scripts/client/AvatarInputHandler/__init__.py", line 610, in onControlModeChanged
      File "scripts/client/AvatarPositionControl.py", line 130, in bindToVehicle
      File "scripts/client/AvatarPositionControl.py", line 63, in notifyPreBind
      File "scripts/client/AvatarPositionControl.py", line 86, in __setTarget
      File "scripts/common/Event.py", line 46, in __call__
      File "scripts/common/debug_utils.py", line 158, in LOG_CURRENT_EXCEPTION
      File "scripts/common/Lib/traceback.py", line 141, in format_exception
      File "scripts/common/Lib/traceback.py", line 76, in format_tb
      File "scripts/common/Lib/traceback.py", line 100, in extract_tb
    RuntimeError: maximum recursion depth exceeded
    """
    

    Такое происходит при отлете свободной камерой далеко от танка, при этом BigWorld выгружает модели танка (BigWorld.entity(vid) == None), а при переключении ждет их загрузки. Я бы понял, если бы оно одинаково падало, однако в чистом клиенте возврат из свободной камеры по CAPS + F3 срабатывает всегда, а у меня - нет.
    Во время проигрывания реплея - та же картина.

    recursion_overflow.wotreplay

  11. Простым способом никак, в battle.swf нет класса BrowserWindow, который представляет собой окно браузера в лобби, и текстуры нет - LobbyApp_browserBgClassValue. Нужно делать флешку с текстурой и свой контроллер браузера, где реализовать открытие/закрытие/обработку ввода и пр.

     

    Наверное, стоит рассказать как работает браузер...

     

    # вот так можно открыть браузер в лобби:
    from gui.game_control import getBrowserCtrl
    getBrowserCtrl().load(url='http://ya.ru/')(lambda success: True)
    
    # более сложный (и правильный) пример:
    from adisp import process
    from gui.game_control import getBrowserCtrl
    
    @process
    def showBrowser():
    
        # все аргументы:
        kwargs = {
            'url': 'http://ya.ru/', # адрес, https://example.com
            'title': None, # текст заголовка окна
            'showActionBtn': True, # показывать кнопку "рефреш/стоп"
            'showWaiting': True, # использовать крутящуюся шестерню во время загрузки контента
            'browserID': None, # уникальный ID этого бразера, чтобы получать его через BrowserController.getBrowser(browserID)
            'isAsync': False, # флаг асинхронности
            'browserSize': None, # размер браузера, tuple([width,height])
            'isDefault': True, # флаг нестандартной текстуры
            'callback': None, # callback, который получит сгененрированный browserID, если его не было в аргументах
            'showCloseBtn': False, # показывать кнопку "закрыть" снизу
            'useWhitelisting': False # начиная c 9.15.1 не используется
        }
    
        # пример
        browser_ctl = getBrowserCtrl()
        browserID = yield browser_ctrl.load(**kwargs)
    
    showBrowser()
    
    

    при этом происходит следующее:

    1. Получаем инстанс контроллера браузера BrowserController
    2. Вызываем асинхронный метод load()
      1. Он создаёт новый инстанс WebBrowser
      2. Создаёт каллбек на показ окна BrowserWindow после загрузки страницы
      3. Если в настоящий момент происходит создание браузера (ожидание п.2), добавляет создание в очередь

    WebBrowser представляет собой обертку над BigWorld.WebBrowserProvider - BigWorld.createBrowser(browserID). У этого объекта заполняется аттрибут script, который является подписчиком событий браузера (onAddConsoleMessage, onBeginLoadingFrame, onChangeCursor, onChangeTitle, onDocumentReady, onFailLoadingFrame, onFilterNavigation, onFinishLoadingFrame, onShowCreatedWebView, onWhitelistMiss), настраиваются обработчики кнопок и мыши, устанавливается текстура (имя) для рендеринга контента в неё.

     

    • Upvote 1

  12. from gui.app_loader import g_appLoader
    from gui.Scaleform.genConsts.BATTLE_VIEW_ALIASES import BATTLE_VIEW_ALIASES
    from gui.Scaleform.framework import ViewTypes

    app = g_appLoader.getDefBattleApp()
    view = app.containerManager.getContainer(ViewTypes.VIEW).getView()
    minimap = view.components[BATTLE_VIEW_ALIASES.MINIMAP]
    vehicles_plugin = minimap.getPlugin('vehicles')
    entries = vehicles_plugin._entries # dict of vid : gui.Scaleform.daapi.view.battle.shared.minimap.entries.VehicleEntry
    entries_on_minimap = {vid: v_entry for vid, v_entry in vehicles_plugin._entries.iteritems() if v_entry.isInAoI()}

     

  13. Мало что понял, поэтому вопросы:

    • Из-за чего WoT-клиент не поддерживает загрузку обычных .pyd?
    • Можно ли используя исходники pyd, скажем, Pillow, собрать тот, который загрузится?
    • Можно ли сделать pyd-обёртку, который загрузит обычный модуль pyd?
  14. В клиенте танков есть встроенный remote debug, по умолчанию настроенный на Pycharm, но никто не запрещает подключатся к нему из другой IDE

    достаточно закинуть содержимое архива pycharm-debug.egg из дистрибутив pycharm в папку \World_of_Tanks\res_bw\scripts\common\pydev\pycharm\

    и вписать в свой скрипт

    import bwpydevd

    bwpydevd.startDebug()

    главное следите чтобы скрипты были идентичны

     

    По этому поводу есть несколько замечаний:

    1. Распаковывать egg-архив можно в любую директорию из sys.path
    2. Скомпилировать, python -m compileall [path_to_extracted]
    3. Брекпоинты в декомпилированных скриптах работать не будут (или будут работать неправильно), т.к. другие номера строк
    4. Чтобы имена файлов были идентичны, можно декомпилированные скрипты прогнать через такой bash-скрипт:

      (все *.pyc res и res_bw копируются в директорию in~, на которую натравливается декомпилятор):

      'bash script'

      #!/bin/bash
      
      # bash script for filename case conversion
      # decompiled files have prefix:
      # Embedded file name: [type]/scripts/[original_pathname_here]
      #
      # it tries to extract original names and rename them
      # files moved from in~/[type]/script
      # to [type]/script directory
      # extensions are changed to .py also
      
      
      fixname ()
      {
          local TYPE=$1
          local OLDFILE=$2
      
          # make new filename
          local NEWFILE=$(head -n 1 $OLDFILE | sed -e "s/# Embedded file name: /$TYPE\//g")
      
          # detect if it is correct
          if [[ ! $NEWFILE =~ ^$TYPE/scripts/ ]];
          then
              # fallback to default, just move in~/ -> .
              NEWFILE=$(echo "${OLDFILE%.*}.py" | sed -e "s/in~\///g")
              echo "Bad header in $OLDFILE, using $NEWFILE"
          fi
      
          if [[ $NEWFILE != $OLDFILE ]];
          then
              echo "$OLDFILE -> $NEWFILE"
              DIR=$(dirname $NEWFILE)
              # make proper dir if necessary
              [ -d $DIR ] || mkdir -p $DIR
              mv $OLDFILE $NEWFILE
          else
              echo "$OLDFILE -> no change"
          fi
      }
      
      
      find in~/ -name '*.pyc' -delete
      
      find in~/res -name '*.pyc_dis*' | while IFS=$'\n' read -r FILE;
      do
          fixname res $FILE
      done
      
      find in~/res_bw -name '*.pyc_dis*' | while IFS=$'\n' read -r FILE;
      do
          fixname res_bw $FILE
      done
      
      # wow!
      

       

    • Upvote 1
  15. К сожалению, Wargaming не предоставляет документации или API по интеграции с движком, поэтому основное время уходит на реверс-инжениринг (что является юридически  спорным). Понять логику работы кода будет проще, если настроить в IDE code hinting и гулять по коду, как по гиперссылкам.

     

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

     

    В качестве среды разработки я использую IntelliJ IDEA с плагинами python, flex, ant. Сборку осуществляю в ней же. Как правило мод представляет собой проект с несколькими модулями - flex и python:

    post-37520-0-51152900-1470221305.png

    Пара внешних модулей есть в каждом проекте - это wotres и wotswf, и они импортированы как зависимости. Это исходники клиента python и as3 из lobby/battle. Каждый под управлением git, любое обновление клиента отражается коммитами с номером версии, иначе сложно отслеживать ошибки, к сожалению, WG часто меняет базовый код.

    • wotres содержит scripts из res и res_bw (последний содержит common/Lib, где можно посмотреть доступные пакеты python), я получаю исходники через uncompyle2
    • wotswf содержит as3 из battle.swf, lobby.swf, common_i18n.swf, а так же библиотеки org.idmedia.as3commons, com.adobe.serialization.json и fl.*, которые можно скачать отдельно. Для декомпиляции я использую jpexs-decompiler, далее пробую собрать swc-библиотеки из lobby и battle, исправляя ошибки декомпиляции. Этот процесс долгий, но требуется один раз - в итоге получаются lobby.swc и battle.swc, готовые для подключения как внешние библиотеки.

    Таким образом, в правильно настроенной IDE появляется code hinting, автоимпорт и обнаружение ошибок, а так же можно легко гулять по коду клиента и исследовать его.

    post-37520-0-06192300-1470222091_thumb.png

    post-37520-0-66139000-1470221309_thumb.png

     

    Про сборку мода. Флеш можно собирать в IDEA, однако, чтобы одной командой собирать все флешки и .pyc, копировать их в клиент вместе с прочими ресурсами и собирать .zip архив, я использую Apache Ant. Ничего хитрого нет, просто один раз сделал и пользуюсь.

    post-37520-0-98969200-1470221300_thumb.png

    Чтобы подключаться в рантайме, я использую этот проект - https://github.com/juho-p/wot-debugserver, в принципе удобно просматривать внутренние структуры через автокомплит по TAB и выполнять какие-нибудь действия для тестов. Так же пробовал для отладки pydev.egg из pycharm, но есть нюансы.

    • Upvote 6
  16. Без флеша ж.

    Флеш можно поставить плагином PPAPI. По этому поводу столкнулся сейчас с таким глюком - при внедрении флешки в страничку, например через swfobject.js, клиент вылетает из фуллскрина и сворачивается.

    Причина этому - описана здесь - https://bugs.chromium.org/p/chromium/issues/detail?id=508002(TL;DR: вызов system('echo NOT SANDBOXED') запускается cmd.exe /c echo NOT SANDBOXED, перехватывая фокус)

    Нашел корявый выход из этой ситуации - подменить %COMSPEC% чем-то другим, что не создаёт консоли/окна, на практике это любой бинарник сервиса, например svchost

     

    то есть вот так:

    import os
    comspec = os.environ.get('COMSPEC', 'C:\\Windows\\system32\\cmd.exe').replace('cmd.exe', 'svchost.exe')
    os.environ['COMSPEC'] = comspec
    
    • Upvote 1
  17.  

    Я не могу понять как передавать данные на вывод.

    Вроде как метод остался но он у меня не отрабатывает в прежнем виде

    AttributeError: 'BigWorld.WebBrowserProvider' object has no attribute 'executeJavascript'

     

    Всё, забудь про executeJavascript, этого интерфейса в CEF больше нет.

    Кроме того, CEF при загрузке странички с флешом запускает cmd.exe, что вызывает сворачивание WoT с фуллскрина

    И зачем WG надо было менять шило на мыло? Awesomium тот же chrome...

    • Upvote 1
×
×
  • Create New...