Jump to content
Korean Random

Как получить телеметрию с танка реалтайм?


Tee-m

Recommended Posts

import game
def hookOnGeometryMapped(spaceID, path):
    hookedOnGeometryMapped(spaceID, path)
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path)

hookedOnGeometryMapped = game.onGeometryMapped
game.onGeometryMapped = hookOnGeometryMapped

Интересно , а что происходит в коде при хуке функции, не пойму что делает эта строка

hookedOnGeometryMapped = game.onGeometryMapped

 а  в момент обращения к жертве вместо ее кода подсовывается хук функция

game.onGeometryMapped = hookOnGeometryMapped

или я не так понял?

, и получается что пока мод на месте функция будет хукаться ? 

Edited by Serfer_78
Link to comment
Short link
Share on other sites

или я не так понял? , и получается что пока мод на месте функция будет хукаться ?

Любая переменная есть ссылка.

hookedOnGeometryMapped = game.onGeometryMapped
Это сохранение в локальную переменную ссылки на оригинальную функцию.

game.onGeometryMapped = hookOnGeometryMapped
Это сохранение в оригинальное место ссылки на твою функцию, хук.

Внутри хука ты вызываешь сохраненный оригинал.

Схема без хука - вызывающий код получает ссылку на функцию-оригинал из game.onGeometryMapped и вызывает ее.

Схема с хуком - вызывающий код получает ссылку на функцию-хук из game.onGeometryMapped и вызывает ее. Внутри функции-хука выполняется оригинал и еще немного кода.

 

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

Т.е.

def hookOnGeometryMapped(spaceID, path):
    result = hookedOnGeometryMapped(spaceID, path)
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path)
    return result
В случае, если функция ничего не возвращает, считается, что она возвращает None. Если ты выполнишь "проброс возврата" для такой функции - ничего плохого не случится. А вот если забудешь, там где он необходим (где функция возвращает не None), получишь некоторое количество лишних проблем. Поэтому рекомендую всегда пробрасывать возврат вне зависимости от того, что возвращает функция.
Edited by GPCracker
  • Upvote 2
Link to comment
Short link
Share on other sites

>Тут бы по идее потоки запилить но пока не созрел как правильно это реализовать.

import threading
from Queue import Queue

class UPDThreading(object):
	def __init__(self):
		self.Data = Queue()
		self.thread = threading.Thread(target = self.SendData)
		self.thread.setDaemon(True)
		self.thread.setName('Send UPD Data')
		self.thread.start()

	def SendData(self):
		while True:
			Message = self.Data.get()
			try:
				socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(_intstr(Message), (UDP_IP, UDP_PORT))
			except:
				pass
			socket.close()
			
UPDSend = UPDThreading()
UPDSend.Data.put(Message)
Edited by ShuraBB
  • Upvote 1
Link to comment
Short link
Share on other sites

Любая переменная есть ссылка.

hookedOnGeometryMapped = game.onGeometryMapped
Это сохранение в локальную переменную ссылки на оригинальную функцию.

game.onGeometryMapped = hookOnGeometryMapped
Это сохранение в оригинальное место ссылки на твою функцию, хук.

Внутри хука ты вызываешь сохраненный оригинал.

Схема без хука - вызывающий код получает ссылку на функцию-оригинал из game.onGeometryMapped и вызывает ее.

Схема с хуком - вызывающий код получает ссылку на функцию-хук из game.onGeometryMapped и вызывает ее. Внутри функции-хука выполняется оригинал и еще немного кода.

 

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

Т.е.

def hookOnGeometryMapped(spaceID, path):
    result = hookedOnGeometryMapped(spaceID, path)
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path)
    return result
В случае, если функция ничего не возвращает, считается, что она возвращает None. Если ты выполнишь "проброс возврата" для такой функции - ничего плохого не случится. А вот если забудешь, там где он необходим (где функция возвращает не None), получишь некоторое количество лишних проблем. Поэтому рекомендую всегда пробрасывать возврат вне зависимости от того, что возвращает функция.

 

 

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

 

>Тут бы по идее потоки запилить но пока не созрел как правильно это реализовать.

import threading  #импортируем библиотеку для работы с потоками
from Queue import Queue # из чего то импортируем что то страшное :) догадываюсь что это работает с очередью сообщений..

class UPDThreading(object):  # Объявляем наш класс ,мой кошмар наяву:) пока всячески их пытаюсь избегать)))
	def __init__(self): # интуиция подсказывает что идет инициализация переменных
		self.Data = Queue()
		self.thread = threading.Thread(target = self.SendData)
		self.thread.setDaemon(True)
		self.thread.setName('Send UPD Data')
		self.thread.start()

	def SendData(self): # объявили функцию
		while True:  # запускаем цикл который работает пока True т.е до первой ошибки
			Message = self.Data.get() # тут отправка сообщения
			try:
				socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(_intstr(Message), (UDP_IP, UDP_PORT)) #ну тут все понятно создается сокет- отправляем меседж)))
			except:  #если ошибка
				pass # ничего не делаем
			socket.close() # по окончании закрываем сокет
			
UPDSend = UPDThreading()
UPDSend.Data.put(Message)

 

ShuraBB вот это да...  Не ожидал однако)))  Был бы рядом проставился бы ;-)   Вот только я настолько зелен в питоне, что его классы меня слегка пугают, я с отступами то воевал долго))

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

Получается при хуке оригинальная функция:

def onGeometryMapped(spaceID, path):
    SoundGroups.g_instance.unloadAll()
    LOG_NOTE('[SPACE] Loading space: ' + path)
    SoundGroups.g_instance.preloadSoundGroups(path.split('/')[-1])

Принимает по сути вот такой вид))

def onGeometryMapped(spaceID, path):
    SoundGroups.g_instance.unloadAll()
    LOG_NOTE('[SPACE] Loading space: ' + path)
    SoundGroups.g_instance.preloadSoundGroups(path.split('/')[-1])
                   #отработал основной код функции
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path) #выполняем наш код в этой функции
    return result #(А по завершении выполнения хукнутой функции возвращаем в оригинальный код то что должна была вернуть реальная не хукнутая функция.)
А если она ничего не возвращала то просто вернется None .

Как я понял из приведенного примера , Хук это способ выполнения своего кода в теле оригинальной функции без изменения оригинального кода картошки (или других программ на python)  

 

А ведь хук удобен тем, что не нужно расписывать условия при которых выполнится код хука, ибо выполнится он как раз в нужный момент, если правильную функцию хукнуть ! :)

А есть ли раздница между таким способом

import game
def hookOnGeometryMapped(spaceID, path):
    hookedOnGeometryMapped(spaceID, path)
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path)

hookedOnGeometryMapped = game.onGeometryMapped
game.onGeometryMapped = hookOnGeometryMapped

И вот таким ?

import game

hookedOnGeometryMapped = game.onGeometryMapped

def hookOnGeometryMapped(spaceID, path):
    hookedOnGeometryMapped(spaceID, path)
    print 'mapName: %s, mapPath: %s' % (path.split('/')[-1], path)

game.onGeometryMapped = hookOnGeometryMapped
Edited by Serfer_78
Link to comment
Short link
Share on other sites

>что его классы меня слегка пугают

Они не страшные. Да и в твоем случае можно сделать и без классов, просто готовый пример под рукой такой был ;-)

 

>Тем не менее постараюсь разобраться как все это дело работает

Вот тебе дока по потокам не плохая

 

А вообще как уже не раз писали - главное уметь спросить Гугл ;-)

Python. Лекция 11 - Многопоточные вычисления.pdf

  • Upvote 1
Link to comment
Short link
Share on other sites

>что его классы меня слегка пугают

Они не страшные. Да и в твоем случае можно сделать и без классов, просто готовый пример под рукой такой был ;-)

 

>Тем не менее постараюсь разобраться как все это дело работает

Вот тебе дока по потокам не плохая

 

А вообще как уже не раз писали - главное уметь спросить Гугл ;-)

 

Сейчас ознакомлюсь.

 

!!! Прямо мысли прочитал, сижу я значит пишу вопрос на тему "в какой последовательности интерпритатор выполняет команды в питоне))))" вижу твое сообщение читаю .. открываю файл и!!! "В любой момент времени интерпретатор

Python знает, какую команду исполнить следующей. После исполнения команды

становится известно, какой команде передать управление. Эта ниточка непрерывна в

ходе выполнения программы и обрывается только по ее завершении." Бывает же так ...

 

Значит правильно Queue это очередь для потоков на выполнение своей части кода.

 

И вообще в этом документе куча интересного, причем очень коротко и... самое главное на русском!

оффтоп:

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

Edited by Serfer_78
Link to comment
Short link
Share on other sites

Как я понял из приведенного примера , Хук это способ выполнения своего кода в теле оригинальной функции без изменения оригинального кода картошки (или других программ на python)

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

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

А есть ли раздница между таким способом

А если очень хорошо подумать? (Подсказка - никакой).
  • Upvote 1
Link to comment
Short link
Share on other sites

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

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

А если очень хорошо подумать? (Подсказка - никакой).

 

Совершенно верно, разницы никакой не заметил, проверил на несколькох разных хуках только что.. 

Link to comment
Short link
Share on other sites

>Значит правильно Queue это очередь для потоков на выполнение своей части кода.

Ты про self.Data = Queue() ?

 

Нет, это стек. .put(...) заносит туда данные а .get() читает из стека

  • Upvote 1
Link to comment
Short link
Share on other sites

>Значит правильно Queue это очередь для потоков на выполнение своей части кода.

Ты про self.Data = Queue() ?

 

Нет, это стек. .put(...) заносит туда данные а .get() читает из стека

 

Не , я про

" from Queue import Queue"

Хотя про "self.Data = Queue()" тоже полезно было узнать.

Edited by Serfer_78
Link to comment
Short link
Share on other sites

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

import BigWorld, Math
from Avatar import PlayerAvatar
def speedTank():
    speed, rspeed = BigWorld.player().getOwnVehicleSpeeds()
    return '%s %d %d' % ('speed:', speed, rspeed)

не могу разобраться что передать в функцию ...


def speedTank(speed, rspeed):

#или 

def speedTank(self, getInstantaneous=False):

#а возможно 

def speedTank(self, speed, rspeed):

Самое комичное то что вчера написал функцию, она работала, передавала положительную скорость (например (10) и отрицательную (-10)) , при сохранении перезаписал документ и удалил функцию, а теперь не помню что я там накалякал))

 

возможно что то типа 

def speedTank(self):
    speed, rspeed = BigWorld.player().getSpeed()
    return '%s %d %d' % ('speed:', speed, rspeed)

Не пойму где моя ошибка, в логах питона чисто .

Edited by Serfer_78
Link to comment
Short link
Share on other sites

Кучу примеров кода модов для танков можно на гитхабе найти.

например у меня в репо https://github.com/spoter

 

Доброго времени суток , нашел в твоем моде AdvancedAimingSystem функцию :

    def getSpeed(self):
        vehicle = self.getVehicle()
        return abs(vehicle.filter.speedInfo.value[0]) if vehicle is not None else None

на ее базе попытался вывести в сообщении скорость собственного танка но результат 0, если не затруднит подскажи пожалуйста как правильно ей можно воспользоваться, может есть какие то аналоги ?

    def getSpeed(self):
        vehicle = BigWorld.entity(self.playerVehicleID)
        speed = abs(vehicle.speedInfo.value[0]) if vehicle is not None else None
        return '%s %d' % ('Speed', speed)
Edited by Serfer_78
Link to comment
Short link
Share on other sites

См. в Avatar.py функцию getOwnVehicleSpeeds (и, на всякий случай, __dumpVehicleState).

 

Я уже ее бедную замучал))


from Avatar import PlayerAvatar
def speedTank():
    speed, rspeed = BigWorld.player().getOwnVehicleSpeeds()
    return '%s %d %d' % ('speed:', speed, rspeed)

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

 

В __dumpVehicleState имеется полностью вся инфа..

 

Однажды запустил лончер дочерним процессом и в лог из этой функции получил вот такую картину..

 

 

 

2017-07-29 03:06:55.078: NOTICE: [NOTE] (scripts/client/game.py, 464): [sPACE] Loading space: spaces/19_monastery

2017-07-29 03:11:12.353: NOTICE: [NOTE] (scripts/client/Avatar.py, 3537): Arena type: ('19_monastery',)

2017-07-29 03:11:12.353: NOTICE: [NOTE] (scripts/client/Avatar.py, 3538): Vehicle position: ((45.6436, 5.31994, 420.044),)

2017-07-29 03:11:12.353: NOTICE: [NOTE] (scripts/client/Avatar.py, 3539): Vehicle direction (y, p, r): ((-3.0541555881500244, -0.02854049578309059, 0.02158796228468418),)

2017-07-29 03:11:12.354: NOTICE: [NOTE] (scripts/client/Avatar.py, 3540): Vehicle speeds: ((-3.9845138299909877e-10, -1.2582367370228553e-09),)

2017-07-29 03:11:12.354: NOTICE: [NOTE] (scripts/client/Avatar.py, 3542): Vehicle type: ('germany:G23_Grille',)

2017-07-29 03:11:12.354: NOTICE: [NOTE] (scripts/client/Avatar.py, 3543): Vehicle turret: ('Grille_mod_1',)

2017-07-29 03:11:12.354: NOTICE: [NOTE] (scripts/client/Avatar.py, 3544): Vehicle gun: ('_150mm_sFH13_L17',)

2017-07-29 03:11:12.354: NOTICE: [NOTE] (scripts/client/Avatar.py, 3545): Shot point: ((49.1623, 12.5297, -52.905),)  

Но и __dumpVehicleState не чего не отдает.. 

Но тем не менее спасибо что откликнулись...

Как видим из лога , название карты отдает game.py , а остальные данные уже идут из аватара. Как уже выше писал , у меня получалось выдернуть скорость и обновлять ее "realtime" но я по неосторожности удалил готовую функцию))  

Ребята кто шарит подскажите с аргументами, какие  указать чтобы получить результат?

def speedTank(???, ???):

Edited by Serfer_78
Link to comment
Short link
Share on other sites

def speedTank(???, ???):

from gui.Scaleform.daapi.view.meta.DamagePanelMeta import DamagePanelMeta

__speed__ = None

old_as_updateSpeedS = DamagePanelMeta.as_updateSpeedS
def new_as_updateSpeedS(self, speed):
    global __speed__
    __speed__ = speed
    return old_as_updateSpeedS(self, speed)
DamagePanelMeta.as_updateSpeedS = new_as_updateSpeedS

def speedTank():
    return __speed__
  • Upvote 1
Link to comment
Short link
Share on other sites

DesiredShotPoint - это для системы прицеливания, куда пушка наводится. ShotPoint - это передается на сервер для отрисовки камеры наблюдателя.

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

Матрица танка есть матрица преобразования из локальной координатной системы танка в глобальную спейса (карты).

Читай документацию к BigWorld. Уже неоднократно постил, поищи на форуме по аттачам.

 

День добрый!  То есть все что начинается с get  передается на сервер? Я правильно понял?

Link to comment
Short link
Share on other sites

То есть все что начинается с get  передается на сервер? Я правильно понял?

Нет. Читай документацию к BigWorld, если тебе это интересно. Почитай также про RPC в инете, base и cell модули в BigWorld. Но не думаю, что для твоих задач это реально нужно.
  • Upvote 1
Link to comment
Short link
Share on other sites

  • 2 weeks later...

 

>Тут бы по идее потоки запилить но пока не созрел как правильно это реализовать.

import threading
from Queue import Queue

class UPDThreading(object):
	def __init__(self):
		self.Data = Queue()
		self.thread = threading.Thread(target = self.SendData)
		self.thread.setDaemon(True)
		self.thread.setName('Send UPD Data')
		self.thread.start()

	def SendData(self):
		while True:
			Message = self.Data.get()
			try:
				socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(_intstr(Message), (UDP_IP, UDP_PORT))
			except:
				pass
			socket.close()
			
UPDSend = UPDThreading()
UPDSend.Data.put(Message)

 

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

def threadDecorate(object):
    def decorate(*args, **kwargs):
        th = threading.Thread(target=object, args=args, kwargs=kwargs)
        th.setDaemon = True
        th.start()
    return decorate

@threadDecorate
def sendMessage(Message):
    try:
        socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(Message, (UDP_IP, UDP_PORT))
        socket.close()
    except:
        pass

Работает как часики, но за пример благодарен. Т.к подтолкнул в нужное русло...

Edited by Serfer_78
Link to comment
Short link
Share on other sites

  • 4 weeks later...
On 25.08.2017 at 10:11 PM, Serfer_78 said:

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

Почитай про модуль adisp.

Edited by GPCracker
Link to comment
Short link
Share on other sites

22 часа назад, GPCracker сказал:

Почитай про модуль adisp.

 

Этот модуль в Bigworld или  в Pythin ? Что то мало про него на форуме, а может не нашел...

Edited by Serfer_78
Link to comment
Short link
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...