Jump to content
Korean Random

aks1983

User
  • Content Count

    23
  • Joined

  • Last visited

Everything posted by aks1983

  1. есть некоторые проблемы с сборке полноценных флешек, смотри https://koreanrandom.com/forum/topic/37496-%D0%BF%D1%80%D0%B8%D1%86%D0%B5%D0%BB%D1%8B-%D0%B2-09171/
  2. Но всё же в аркадном прицеле перезарядка не отображается, падение в методе as_setAmmoStock, и вкладка с настройками прицела - висит.
  3. Спасибо, всё получилось, есть некоторые косяки с расположением и цветом текста, но в целом флешки собираются и работает в 0.9.17.1 Supertest. Можно использовать в качестве отправной точки. Crosshairs.zip
  4. это я знаю, вопрос в другом - как в Adobe Flash выглядит правильный импорт? я добавлял символы в библиотеку через "Import for runtime sharing", при этом, если эти символы не используются, они не импортируются (отсутствует ImportAssets2), при их использовании - флешка не работает. я декомпилирую в JPEXS FFDec оригинальные флешки в xfl формат. в этом файле отсутствуют символы, которые должны быть импортированы, а вручную помещать их в библиотеку и дальше - на место - очень неудобно. в идеале, я хотел бы получить *.xfl-проект, в котором легко изменять изображения и скрипты и компилировать через publish.
  5. нужна информация о том, как собирать arcadeCrosshair.swf crosshairControls.swf crosshairPanelContainer.swf postmortemCrosshair.swf sniperCrosshair.swf strategicCrosshair.swf файлы импортируют друг друга, каким образом добиться этого в редакторе Flash? например, arcadeCrosshair.swf имеет зависимость от crosshairControls.swf, каким образом правильно указать импортирование в Adobe Flash? Как должен называться этот символ в библиотеке, и в какие символы его добавить?
  6. Идея отличнейшая, поскольку накопилось уже достаточно материалов и понимания структуры движка, часть из которых являются догадками. Конечно, жаль что так поздно вы до нас снизошли.
  7. Вы забываете, для чего пишут игры, WoT в том числе. Я вас уверяю, если бы танки делали люди, для которым важно внимание к таким мелочам, игра бы не стали известной. И у этой ниши другое название - инди игры. В первую очередь игра должна стать коммерчески успешной, так как это бизнес, который извлекает максимальную прибыль и не должен нести убытки - а для этого не обязательно выверять каждый полигон и строчку кода - рядовому пользователю дела нет до этого. Гораздо важнее правильная реклама, чемпионаты, и прочее. В WG разработчиков можно пересчитать по пальцам, зато PR-щиков, аналитиков и менеджеров на порядки больше, и это нормально. Ради этого можно закрыть глаза на некоторые некритические ошибки. Есть системные требования, и в этих рамках игра работает нормально - следовательно, задача разработчиков выполнена (не важно, каким образом), они получили зарплату и пошли домой. Есть финансовые показатели, и иногда они падают. За это отвечают не разработчики, а отдел маркетинга. Тогда у нас и появляются ненужные HD-модели и т.п. А по поводу вопроса автора темы - это всё адекватно в рамках такого видения мира.
  8. I have no idea without datails - how did you load your hook and what is inside python.log?
  9. Итак, вы уже создали библиотеки 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) Вот такой результат получился у меня, кнопки нажимаются (две голубые кнопки вверху - другой эксперимент): Думаю, теперь понятно, как делать более сложные интерфейсы - надо импротировать другие контролы. Где они находятся, можно выяснить только посмотрев, что внутри файлов gui*.swf Подводные камни: во Flash не видно размеров контролов, вообще ничего не видно (не проверял, но думаю что) не все gui*.swf можно использовать, некоторые - не загружены
  10. Делаю переход свободная камера <-> привязанная камера. Штатно это работает по нажатию 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) Кто-нибудь исследовал этот вопрос?
  11. Спасибо, продвинулся, но проблема осталась. Сейчас реализация такая - 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, в этом случае не валится, но и контролов не видно (графика не загрузилась? или контролы не проинициализировались?) Попробуем сделать для теста простейшее окно с кнопкой и дропдауном на странице логина?
  12. 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();
  13. Привет! 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 (но в него тоже надо вникать).
  14. Пробую сделать переключение свободной камеры в привязанную, '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
  15. Простым способом никак, в battle.swf нет класса BrowserWindow, который представляет собой окно браузера в лобби, и текстуры нет - LobbyApp_browserBgClassValue. Нужно делать флешку с текстурой и свой контроллер браузера, где реализовать открытие/закрытие/обработку ввода и пр. Наверное, стоит рассказать как работает браузер...
  16. 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()}
  17. Мало что понял, поэтому вопросы: Из-за чего WoT-клиент не поддерживает загрузку обычных .pyd? Можно ли используя исходники pyd, скажем, Pillow, собрать тот, который загрузится? Можно ли сделать pyd-обёртку, который загрузит обычный модуль pyd?
  18. По этому поводу есть несколько замечаний: Распаковывать egg-архив можно в любую директорию из sys.path Скомпилировать, python -m compileall [path_to_extracted] Брекпоинты в декомпилированных скриптах работать не будут (или будут работать неправильно), т.к. другие номера строк Чтобы имена файлов были идентичны, можно декомпилированные скрипты прогнать через такой bash-скрипт: (все *.pyc res и res_bw копируются в директорию in~, на которую натравливается декомпилятор): 'bash script'
  19. К сожалению, Wargaming не предоставляет документации или API по интеграции с движком, поэтому основное время уходит на реверс-инжениринг (что является юридически спорным). Понять логику работы кода будет проще, если настроить в IDE code hinting и гулять по коду, как по гиперссылкам. Здесь я бы хотел поделиться своим опытом по созданию удобного окружения для разработки и автоматизации сборки модов. В качестве среды разработки я использую IntelliJ IDEA с плагинами python, flex, ant. Сборку осуществляю в ней же. Как правило мод представляет собой проект с несколькими модулями - flex и python: Пара внешних модулей есть в каждом проекте - это 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, автоимпорт и обнаружение ошибок, а так же можно легко гулять по коду клиента и исследовать его. Про сборку мода. Флеш можно собирать в IDEA, однако, чтобы одной командой собирать все флешки и .pyc, копировать их в клиент вместе с прочими ресурсами и собирать .zip архив, я использую Apache Ant. Ничего хитрого нет, просто один раз сделал и пользуюсь. Чтобы подключаться в рантайме, я использую этот проект - https://github.com/juho-p/wot-debugserver, в принципе удобно просматривать внутренние структуры через автокомплит по TAB и выполнять какие-нибудь действия для тестов. Так же пробовал для отладки pydev.egg из pycharm, но есть нюансы.
  20. Флеш можно поставить плагином 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
  21. Всё, забудь про executeJavascript, этого интерфейса в CEF больше нет. Кроме того, CEF при загрузке странички с флешом запускает cmd.exe, что вызывает сворачивание WoT с фуллскрина И зачем WG надо было менять шило на мыло? Awesomium тот же chrome...
×
×
  • Create New...