kharlashkin 239 Posted September 16, 2015 Доброе время суток всему уважаемому korean-random сообществу! С последним обновлением 0.9.10 не работает вибрация. Учитывая огромную нехватку времени и постоянные командировки в страны, где очень плохо с интернетом - наверное проще кому-то заплатить обоснованную сумму. Потому как геймплей очень плох с геймпадом без "вибры". Любую информацию интересующимся предоставлю :) 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292543 Posted September 18, 2015 (edited) Вспомнил напутствие @sirmax попробовал запускать посторонние процессы (GPService.pyc) через subprocess - ничего не получилось. Может картоха теперь блокирует запуск посторонних процессов из игры? P.S. Увидел на dev.modxvm.com что ребята используют свои библиотеки в XVM, мне не показалось? Возможно ли тогда ctypes прикрутить? Поспешил я немного с выводом относительно запуска - всё работает, но не вибрация. os.spawnl(os.P_NOWAIT, self.__sysPythonPath + ' ' + fileNameGPService) Подскажите кто нибудь, что где менять чтобы загружался мод с помощью XFW? init.py XFW_MOD_INFO = { 'VERSION': '0.6.0', 'URL': 'http://www.koreanrandom.com/forum/user/16753-inj3ct0r/', 'UPDATE_URL': 'http://www.koreanrandom.com/forum/user/19155-kharlashkin/', 'GAME_VERSIONS': ['0.9.10'] } from xfw import * from GamePadVibration import GamePadVibration from Vibroeffects.VibroManager import VibroManager def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) RegisterEvent(VibroManager, '__init__', myVibroManager__init__) GamePadVibration.py import urllib2 class GamePadVibration: def __init__(self, originalVibrationObject): self.__originalVibrationObject = originalVibrationObject self.__gpServiceAddress = 'http://127.0.0.1:5000/' self.__gpServiceAddressTimeOut = 0.25 self.__sysPythonPath = 'c:/python27/pythonw.exe' import os fileNameGPService = os.path.dirname(os.path.realpath(__file__)) + '/GPService.pyc' os.spawnl(os.P_NOWAIT, self.__sysPythonPath + ' ' + fileNameGPService) def __del__(self): address = self.__gpServiceAddress try: urllib2.urlopen(address + 'disconnect') except urllib2.URLError as e: print 'urllib2.URLError (disconnect):', e except urllib2.HTTPError as e: print 'urllib2.HTTPError (disconnect):', e except: print 'urllib2: Unexpected error (disconnect)' def reset(self): self.__originalVibrationObject.reset() def setGain(self, gain): self.__originalVibrationObject.setGain(gain) def createEffect(self): effectHandle = self.__originalVibrationObject.createEffect() return effectHandle def getEffectLength(self, handle): durationInMs = self.__originalVibrationObject.getEffectLength(handle) return durationInMs def deleteEffect(self, handle): self.__originalVibrationObject.deleteEffect(handle) def connect(self): address = self.__gpServiceAddress isServiceRunning = False try: isServiceRunning = urllib2.urlopen(address + 'connect').read() except urllib2.URLError as e: print 'urllib2.URLError (connect):', e except urllib2.HTTPError as e: print 'urllib2.HTTPError (connect):', e except: print 'urllib2: Unexpected error (connect)' if isServiceRunning == 'True': return True else: return False def loadEffectFromFile(self, effectHandle, fileName): self.__originalVibrationObject.loadEffectFromFile(effectHandle, fileName) address = self.__gpServiceAddress timeOut = self.__gpServiceAddressTimeOut urlSafeOpen(address, '?effectHandle=' + str(effectHandle) + '&fileName=' + str(fileName), 'loadEffectFromFile', timeOut) def startEffect(self, handle, effectsSettingsCount): address = self.__gpServiceAddress timeOut = self.__gpServiceAddressTimeOut urlSafeOpen(address, '?handle=' + str(handle) + '&count=' + str(effectsSettingsCount), 'startEffect', timeOut) def stopEffect(self, handle): address = self.__gpServiceAddress timeOut = self.__gpServiceAddressTimeOut urlSafeOpen(address, '?handle=' + str(handle), 'stopEffect', timeOut) def setEffectGain(self, vibroEffectHandle, effectGain): address = self.__gpServiceAddress timeOut = self.__gpServiceAddressTimeOut urlSafeOpen(address, '?vibroEffectHandle=' + str(vibroEffectHandle) + '&effectGain=' + str(effectGain), 'setEffectGain', timeOut) def cloneEffect(self, sourceEffectHandle): destEffectHandle = self.__originalVibrationObject.cloneEffect(sourceEffectHandle) address = self.__gpServiceAddress timeOut = self.__gpServiceAddressTimeOut urlSafeOpen(address, '?sourceEffectHandle=' + str(sourceEffectHandle) + '&destEffectHandle=' + str(destEffectHandle), 'cloneEffect', timeOut) return destEffectHandle def urlSafeOpen(addr, req, funcName, timeOut = 0.25): try: urllib2.urlopen(addr + funcName + req, None, timeOut) except urllib2.URLError as e: print funcName, 'urllib2.URLError:', e except urllib2.HTTPError as e: print funcName, 'urllib2.HTTPError:', e except: print funcName, 'urllib2: Unexpected error' return import datetime def _log_ms(msg): dt = datetime.datetime.now() print datetime.datetime.now().strftime('%H:%M:%S.') + str(dt.microsecond)[0:3] + ':', msg GPService.py TIME_DELTA = 10 K_SIT_LEFT = [0.7, 0.0] K_SIT_RIGHT = [0.7, 0.0] K_BACK_LOW_LEFT = [0.3, 0.3] K_BACK_LOW_RIGHT = [0.3, 0.3] K_BACK_MID_LEFT = [0.0, 0.7] K_BACK_MID_RIGHT = [0.0, 0.7] LOG_CLASS_ON = False LOG_ROUTE_ON = False LOG_SERV_ON = False transferCoefficientDict = {1: K_SIT_RIGHT, 2: K_BACK_LOW_RIGHT, 3: K_BACK_MID_RIGHT, 9: K_SIT_LEFT, 10: K_BACK_LOW_LEFT, 11: K_BACK_MID_LEFT} def _testBit(zone_group, zone): mask = 1 << zone return bool((zone_group & mask) >> zone) import threading, time from gpXInput import gpXInputClass class gpVibroEffect: isRunning = property(lambda self: self.__isRunning) stopEvent = property(lambda self: self.__stopEvent) fileName = property(lambda self: self.__fileName) effectLength = property(lambda self: self.__effectLength) def __init__(self): self.__isRunning = False self.__isLoaded = False self.__effectLength = 0 self.__vibrationsArrayLeftMotor = [] self.__vibrationsArrayRightMotor = [] self.__effectGain = 1.0 self.__stopEvent = threading.Event() self.__stopEvent.clear() def setXInputObject(self, gpXInputObject): self.__gpXInputObject = gpXInputObject def play(self, count = 1): startTime = time.clock() if LOG_CLASS_ON: print self.__fileName, 'is started' lValue = 0.0 rValue = 0.0 gain = self.__effectGain import sys if count > sys.maxint: count = sys.maxint for c in xrange(count): if self.__stopEvent.isSet(): break for x in range(int(self.__effectLength / TIME_DELTA)): if x == 0 and c == 0: lDelta = self.__vibrationsArrayLeftMotor[x] rDelta = self.__vibrationsArrayRightMotor[x] else: lDelta = self.__vibrationsArrayLeftMotor[x] - self.__vibrationsArrayLeftMotor[x - 1] rDelta = self.__vibrationsArrayRightMotor[x] - self.__vibrationsArrayRightMotor[x - 1] lValue += lDelta rValue += rDelta self.__gpXInputObject.adjust_vibration(lDelta * gain, rDelta * gain) if LOG_CLASS_ON: print x, '%0.2f, %0.2f' % (lValue, rValue) if self.__stopEvent.isSet(): break time.sleep(2 * TIME_DELTA / 1000.0) lDelta = -lValue lValue += lDelta rDelta = -rValue rValue += rDelta self.__gpXInputObject.adjust_vibration(lDelta * gain, rDelta * gain) finishTime = time.clock() self.__isRunning = False if LOG_CLASS_ON: print x + 1, '%0.2f, %0.2f' % (lValue, rValue) print 'Time elapsed: %.3fs' % (finishTime - startTime) print self.__fileName, 'is stopped' def loadEffectFromFile(self, fileName): self.__isLoaded = False self.__fileName = fileName if LOG_CLASS_ON: print 'loading', self.__fileName from xml.etree import ElementTree as ET uwvTree = ET.parse(self.__fileName) uwvRoot = uwvTree.getroot() effectLength = 0 for node in uwvRoot.getiterator(): if 'time' in node.attrib: if int(node.attrib['time']) > effectLength: effectLength = int(node.attrib['time']) self.__effectLength = effectLength for i in range(int(self.__effectLength / TIME_DELTA)): self.__vibrationsArrayLeftMotor.append(0) self.__vibrationsArrayRightMotor.append(0) for vibration in uwvRoot.getchildren(): if 'vibration' in vibration.tag: timePrev = 0 amplPrev = 0 zones = int(vibration.attrib['zones'], 16) zoneLength = 0 for vpoint in vibration.getchildren(): if int(vpoint.attrib['time']) > zoneLength: zoneLength = int(vpoint.attrib['time']) self.__zonesGroupArrayLeftMotor = [] self.__zonesGroupArrayRightMotor = [] for i in range(int(zoneLength / TIME_DELTA) + 1): self.__zonesGroupArrayLeftMotor.append(0) self.__zonesGroupArrayRightMotor.append(0) for vpoint in vibration.getchildren(): timeCur = int(vpoint.attrib['time']) amplCur = float(vpoint.attrib['amplitude']) if timePrev == timeCur and amplPrev != amplCur: x = int(timeCur / TIME_DELTA) ampl = amplCur for key in transferCoefficientDict.keys(): if _testBit(zones, key): pass elif timePrev != timeCur and amplPrev == amplCur: for x in range(int(timePrev / TIME_DELTA), int(timeCur / TIME_DELTA)): ampl = amplCur for key in transferCoefficientDict.keys(): if _testBit(zones, key): self.__zonesGroupArrayLeftMotor[x] += ampl * transferCoefficientDict[key][0] self.__zonesGroupArrayRightMotor[x] += ampl * transferCoefficientDict[key][1] elif '1' in vpoint.tag and timeCur != 0: x = int(timeCur / TIME_DELTA) ampl = amplCur for key in transferCoefficientDict.keys(): if _testBit(zones, key): pass elif timePrev != timeCur and amplPrev != amplCur: x1 = int(timePrev / TIME_DELTA) x2 = int(timeCur / TIME_DELTA) - 1 y1 = amplPrev y2 = amplCur try: k = (y2 - y1) / (x2 - x1) b = y2 - k * x2 except: k = 0 b = 0 for x in range(int(timePrev / TIME_DELTA), int(timeCur / TIME_DELTA)): ampl = k * x + b for key in transferCoefficientDict.keys(): if _testBit(zones, key): self.__zonesGroupArrayLeftMotor[x] += ampl * transferCoefficientDict[key][0] self.__zonesGroupArrayRightMotor[x] += ampl * transferCoefficientDict[key][1] timePrev = timeCur amplPrev = amplCur looped = vibration.attrib['looped'] if looped == 'true': y = 0 for x in range(int(effectLength / TIME_DELTA)): self.__vibrationsArrayLeftMotor[x] += self.__zonesGroupArrayLeftMotor[y] self.__vibrationsArrayRightMotor[x] += self.__zonesGroupArrayRightMotor[y] y += 1 if y == int(zoneLength / TIME_DELTA): y = 0 else: for x in range(int(zoneLength / TIME_DELTA)): self.__vibrationsArrayLeftMotor[x] += self.__zonesGroupArrayLeftMotor[x] self.__vibrationsArrayRightMotor[x] += self.__zonesGroupArrayRightMotor[x] self.__isLoaded = True def startEffect(self, count = 1): if not self.__isLoaded: return if self.__isRunning: self.__stopEvent.set() while self.__isRunning: pass self.__stopEvent.clear() self.__thread = threading.Thread(target=self.play, args=(count,)) self.__isRunning = True self.__thread.start() def stopEffect(self): self.__stopEvent.set() def setEffectGain(self, effectGain): self.__effectGain = effectGain / 100.0 effectsDict = dict() gpXInputObject = gpXInputClass() gpXInputObject.stop_vibration() from flask import Flask, request if not LOG_SERV_ON: import logging log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) app = Flask(__name__) def shutdown_server(): func = request.environ.get('werkzeug.server.shutdown') if func is None: raise RuntimeError('Not running with the Werkzeug Server') func() return @app.route('/disconnect') def disconnect(): shutdown_server() for effect in effectsDict: effectsDict[effect].stopEffect() gpXInputObject.stop_vibration() time.sleep(2 * TIME_DELTA / 1000.0) return 'Server shutting down...' @app.route('/connect') def connect(): if LOG_ROUTE_ON: print 'Connection checked - Ok.' return 'True' @app.route('/loadEffectFromFile') def loadEffectFromFile(): effectHandle = request.args.get('effectHandle') fileName = request.args.get('fileName') import os fileName = os.path.dirname(__file__) + '/' + fileName if os.path.exists(fileName): effectsDict[effectHandle] = gpVibroEffect() effectsDict[effectHandle].setXInputObject(gpXInputObject) effectsDict[effectHandle].loadEffectFromFile(fileName) else: print 'loadEffectFromFile Error: file not found:', fileName if LOG_ROUTE_ON: print print 'loadEffectFromFile' print 'effectHandle =', effectHandle print 'fileName =', fileName return '' @app.route('/startEffect') def startEffect(): handle = request.args.get('handle') count = int(request.args.get('count')) if handle in effectsDict: effectsDict[handle].startEffect(count) else: print 'startEffect Error: Handle', handle, 'is empty' if LOG_ROUTE_ON: print print 'startEffect' print 'handle =', handle print 'count =', str(count) return '' @app.route('/stopEffect') def stopEffect(): handle = request.args.get('handle') if handle in effectsDict: effectsDict[handle].stopEffect() else: print 'stopEffect Error: Handle', handle, 'is empty' if LOG_ROUTE_ON: print print 'stopEffect' print 'handle =', handle return '' @app.route('/setEffectGain') def setEffectGain(): vibroEffectHandle = request.args.get('vibroEffectHandle') effectGain = float(request.args.get('effectGain')) if vibroEffectHandle in effectsDict: effectsDict[vibroEffectHandle].setEffectGain(effectGain) else: print 'setEffectGain Error: Handle', vibroEffectHandle, 'is empty' if LOG_ROUTE_ON: print print 'setEffectGain' print 'vibroEffectHandle =', vibroEffectHandle print 'effectGain =', effectGain return '' @app.route('/cloneEffect') def cloneEffect(): sourceEffectHandle = request.args.get('sourceEffectHandle') destEffectHandle = request.args.get('destEffectHandle') if sourceEffectHandle in effectsDict: effectsDict[destEffectHandle] = gpVibroEffect() effectsDict[destEffectHandle].setXInputObject(gpXInputObject) effectsDict[destEffectHandle].loadEffectFromFile(effectsDict[sourceEffectHandle].fileName) else: print 'cloneEffect Error: sourceHandle', sourceEffectHandle, 'is empty' if LOG_ROUTE_ON: print print 'cloneEffect' print 'sourceEffectHandle =', sourceEffectHandle print 'destEffectHandle =', destEffectHandle return '' if __name__ == '__main__': app.run() gpXInput.py import ctypes class XINPUT_VIBRATION(ctypes.Structure): _fields_ = [('wLeftMotorSpeed', ctypes.c_ushort), ('wRightMotorSpeed', ctypes.c_ushort)] class gpXInputClass: def __init__(self): xInputDLLFileName = 'xinput1_3' xinput = ctypes.WinDLL(xInputDLLFileName) self.__XInputSetState = xinput.XInputSetState self.__XInputSetState.argtypes = [ctypes.c_uint, ctypes.POINTER(XINPUT_VIBRATION)] self.__XInputSetState.restype = ctypes.c_uint self.__l = 0 self.__r = 0 def adjust_vibration(self, left_motor_delta, right_motor_delta, set = False, controller = 0): if set: self.__l = left_motor self.__r = right_motor else: self.__l += left_motor_delta self.__r += right_motor_delta tempL = self.__l tempR = self.__r if self.__l > 255: tempL = 255 elif self.__l < 0: tempL = 0 if self.__r > 255: tempR = 255 elif self.__r < 0: tempR = 0 vibration = XINPUT_VIBRATION(int(tempL * 65535 / 255), int(tempR * 65535 / 255)) self.__XInputSetState(controller, ctypes.byref(vibration)) def stop_vibration(self, controller = 0): vibration = XINPUT_VIBRATION(0, 0) self.__XInputSetState(controller, ctypes.byref(vibration)) gpXInputObject = gpXInputClass() Edited October 1, 2015 by kharlashkin Quote Share this post Link to post Short link Share on other sites
sirmax 5,499 #292619 Posted September 18, 2015 Надо кое чего переделать под новый формат. Как-то так: @registerEvent(VibroManager, '__init__') def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292639 Posted September 19, 2015 Надо кое чего переделать под новый формат. Как-то так: @registerEvent(VibroManager, '__init__') def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) Спасибо! Попробую. Я в принципе уже докопался по исходникам XVM, что метод RegisterEvent устаревший (# deprecated) и нашел пример реализации @registerEvent в исходниках. Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292725 Posted September 20, 2015 Не сработало. Уважаемый @sirmax, а не могли бы Вы более полную инструкцию дать по методу @registerEvent? Читая Ваши исходники мне почему то кажется что мне необходимо каждый метод в классе VibroManager таким образом дополнить. Quote Share this post Link to post Short link Share on other sites
sirmax 5,499 #292730 Posted September 20, 2015 Мне некогда сейчас этим заниматься. 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292738 Posted September 20, 2015 Мне некогда сейчас этим заниматься. Так я и не прошу Вас сделать что-то за меня (ну или за того кто захочет помочь) ;) Просто судя по исходникам XVM с помощью @registerEvent в классах нужно расширять все методы по отдельности - собственно я и спрашиваю "Стоит ли пробовать?". Quote Share this post Link to post Short link Share on other sites
sirmax 5,499 #292740 Posted September 20, 2015 Просто судя по исходникам XVM с помощью @registerEvent в классах нужно расширять все методы по отдельности - собственно я и спрашиваю "Стоит ли пробовать?". Только те методы, которые надо переопределить. Тут надо бы питон знать, чтобы разобраться. Иначе это выльется в лекцию по программированию. 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292754 Posted September 20, 2015 Только те методы, которые надо переопределить. Тут надо бы питон знать, чтобы разобраться. Иначе это выльется в лекцию по программированию. Вот же, как раз под вторым спойлером и видно все методы которые необходимо расширить. А лекцию я бы послушал с удовольствием :) Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292807 Posted September 20, 2015 "Пришла беда откуда не ждали..." Может кто встречался с подобным? Quote Share this post Link to post Short link Share on other sites
GPCracker 2,088 #292861 Posted September 21, 2015 (edited) Вот же, как раз под вторым спойлером и видно все методы которые необходимо расширить.У тебя хук по факту ставится только на один метод __init__, он подсовывает игре нужный класс.@registerEvent(..) это декоратор, по сути функция, которая получает аргументом функцию-хук. registerEvent - функция, которая возвращает декоратор. Есть статья по этой теме на хабре. Что касаемо инструкции на registerEvent, @registerEvent(VibroManager, '__init__') def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject)в некотором приближении эквивалентно def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) return wgVibroManager__init__(self) wgVibroManager__init__ = VibroManager.__init__ VibroManager.__init__ = myVibroManager__init__Опять же повторюсь - в приближении. На самом деле там алгоритм несколько сложнее, работает через event'ы. Думаю, тебе стоит проверить вызываются ли методы твоего класса или нет. Принты допиши, посмотри что и как. А дальше уже будет видно, в какую сторону копать. Надо кое чего переделать под новый формат. Как-то так:Тоже тут написал одно время немного кода) import functools import types class HookFunction(object): CALL_ORIGIN_BEFORE_HOOK = 0x0 CALL_HOOK_BEFORE_ORIGIN = 0x1 CALL_ORIGIN_INSIDE_HOOK = 0x2 CALL_TYPE_DEFAULT = CALL_ORIGIN_BEFORE_HOOK def __init__(self, origin, hook, type = CALL_TYPE_DEFAULT, active = True): if not isinstance(hook, (types.FunctionType, types.LambdaType)): raise TypeError('Hook must be function or lambda') self.__name__ = hook.__name__ self.origin = origin self.hook = hook self.type = type self.active = active return def __call__(self, *args, **kwargs): if self.active and self.type == self.CALL_ORIGIN_BEFORE_HOOK: result = self.origin(*args, **kwargs) self.hook(*args, **kwargs) elif self.active and self.type == self.CALL_HOOK_BEFORE_ORIGIN: self.hook(*args, **kwargs) result = self.origin(*args, **kwargs) elif self.active and self.type == self.CALL_ORIGIN_INSIDE_HOOK: result = self.hook(self.origin, *args, **kwargs) else: result = self.origin(*args, **kwargs) return result def __get__(self, instance, type = None): return types.MethodType(self, instance, type) @classmethod def makeMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method).__func__ override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, override) else: setattr(target, method, override.__get__(target, types.TypeType(target))) return hook @classmethod def makeStaticMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method) override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, staticmethod(override)) else: setattr(target, method, override) return hook @classmethod def makeClassMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method).__func__ override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, classmethod(override)) else: setattr(target, method, override.__get__(types.TypeType(target), types.TypeType)) return hook @classmethod def methodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeMethodHook, target, method, type = type, active = active) @classmethod def staticMethodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeStaticMethodHook, target, method, type = type, active = active) @classmethod def classMethodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeClassMethodHook, target, method, type = type, active = active)Последние три метода - декораторы. Edited September 21, 2015 by GPCracker 3 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #292862 Posted September 21, 2015 У тебя хук по факту ставится только на один метод __init__, он подсовывает игре нужный класс. @registerEvent(..) это декоратор, по сути функция, которая получает аргументом функцию-хук. registerEvent - функция, которая возвращает декоратор. Есть статья по этой теме на хабре. Что касаемо инструкции на registerEvent, @registerEvent(VibroManager, '__init__') def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) в некотором приближении эквивалентно def myVibroManager__init__(self): self._VibroManager__vibrationObject = GamePadVibration(self._VibroManager__vibrationObject) return wgVibroManager__init__(self) wgVibroManager__init__ = VibroManager.__init__ VibroManager.__init__ = myVibroManager__init__ Опять же повторюсь - в приближении. На самом деле там алгоритм несколько сложнее, работает через event'ы. Думаю, тебе стоит проверить вызываются ли методы твоего класса или нет. Принты допиши, посмотри что и как. А дальше уже будет видно, в какую сторону копать. Тоже тут написал одно время немного кода) import functools import types class HookFunction(object): CALL_ORIGIN_BEFORE_HOOK = 0x0 CALL_HOOK_BEFORE_ORIGIN = 0x1 CALL_ORIGIN_INSIDE_HOOK = 0x2 CALL_TYPE_DEFAULT = CALL_ORIGIN_BEFORE_HOOK def __init__(self, origin, hook, type = CALL_TYPE_DEFAULT, active = True): if not isinstance(hook, (types.FunctionType, types.LambdaType)): raise TypeError('Hook must be function or lambda') self.__name__ = hook.__name__ self.origin = origin self.hook = hook self.type = type self.active = active return def __call__(self, *args, **kwargs): if self.active and self.type == self.CALL_ORIGIN_BEFORE_HOOK: result = self.origin(*args, **kwargs) self.hook(*args, **kwargs) elif self.active and self.type == self.CALL_HOOK_BEFORE_ORIGIN: self.hook(*args, **kwargs) result = self.origin(*args, **kwargs) elif self.active and self.type == self.CALL_ORIGIN_INSIDE_HOOK: result = self.hook(self.origin, *args, **kwargs) else: result = self.origin(*args, **kwargs) return result def __get__(self, instance, type = None): return types.MethodType(self, instance, type) @classmethod def makeMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method).__func__ override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, override) else: setattr(target, method, override.__get__(target, types.TypeType(target))) return hook @classmethod def makeStaticMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method) override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, staticmethod(override)) else: setattr(target, method, override) return hook @classmethod def makeClassMethodHook(sclass, target, method, hook, type = CALL_TYPE_DEFAULT, active = True): origin = getattr(target, method).__func__ override = sclass(origin, hook, type, active) if isinstance(target, (types.TypeType, types.ClassType)): setattr(target, method, classmethod(override)) else: setattr(target, method, override.__get__(types.TypeType(target), types.TypeType)) return hook @classmethod def methodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeMethodHook, target, method, type = type, active = active) @classmethod def staticMethodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeStaticMethodHook, target, method, type = type, active = active) @classmethod def classMethodHook(sclass, target, method, type = CALL_TYPE_DEFAULT, active = True): return functools.partial(sclass.makeClassMethodHook, target, method, type = type, active = active) Последние три метода - декораторы. Жаль что плюсик один (допишу ещё жирных) - плюс, плюс, плюс! Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #293389 Posted September 25, 2015 Декораторы - это хорошо конечно, но блин я никак не могу понять что изменилось то у картошек. def start(self): from gui.app_loader import g_appLoader g_appLoader.onGUISpaceChanged += self.__onGUISpaceChanged def __onGUISpaceChanged(self, spaceID): from gui.app_loader.settings import GUI_GLOBAL_SPACE_ID if spaceID == GUI_GLOBAL_SPACE_ID.LOGIN: self.stopAllEffects() Quote Share this post Link to post Short link Share on other sites
sirmax 5,499 #293409 Posted September 25, 2015 Декораторы - это хорошо конечно, но блин я никак не могу понять что изменилось то у картошек. def start(self): from gui.app_loader import g_appLoader g_appLoader.onGUISpaceChanged += self.__onGUISpaceChanged def __onGUISpaceChanged(self, spaceID): from gui.app_loader.settings import GUI_GLOBAL_SPACE_ID if spaceID == GUI_GLOBAL_SPACE_ID.LOGIN: self.stopAllEffects() В XFW изменен инициализатор, и теперь он стартует позже, чем было до этого. Возможно событие срабатывает до того, как ты его привязываешь. Вообще, если ты ждешь какой-то толковый ответ, хотя бы логи покажи, и исходники. Кроме того, тебе уже говорили вставить в методы вывод в логи отладочной информации, чтобы можно было определить что вызывается, а что нет. 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #293411 Posted September 25, 2015 (edited) В XFW изменен инициализатор, и теперь он стартует позже, чем было до этого. Возможно событие срабатывает до того, как ты его привязываешь. Вообще, если ты ждешь какой-то толковый ответ, хотя бы логи покажи, и исходники. Кроме того, тебе уже говорили вставить в методы вывод в логи отладочной информации, чтобы можно было определить что вызывается, а что нет. Вот же - я прихожу к тому же выводу, что мой сервис хоть и стартует но игрой не обрабатывается. Исходники мода сверху под спойлерами кроме серверной части с Flask и скриптом для вибрации с ctypes. Прикол в том что логи чистые :) print добавлю. python.log xvm.log Edited September 25, 2015 by kharlashkin Quote Share this post Link to post Short link Share on other sites
sirmax 5,499 #293413 Posted September 25, 2015 исходники нужны после того, как в логах будет хоть что-то, откуда можно смотреть. компилять и запускать их никто не будет. пока ты логи не сделаешь, ничего не будет 1 Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #293414 Posted September 25, 2015 исходники нужны после того, как в логах будет хоть что-то, откуда можно смотреть. компилять и запускать их никто не будет. пока ты логи не сделаешь, ничего не будет Вместо плюсика :) Quote Share this post Link to post Short link Share on other sites
fecell 125 #293595 Posted September 27, 2015 Возможно ли тогда ctypes прикрутить? что конкретно надо из ctypes? этот функционал можно сделать отдельным пидом под танковый питон. Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #293600 Posted September 28, 2015 что конкретно надо из ctypes? этот функционал можно сделать отдельным пидом под танковый питон. Собственно вот думаю будет понятно: import ctypes class XINPUT_VIBRATION(ctypes.Structure): _fields_ = [('wLeftMotorSpeed', ctypes.c_ushort), ('wRightMotorSpeed', ctypes.c_ushort)] class gpXInputClass: def __init__(self): xInputDLLFileName = 'xinput1_3' xinput = ctypes.WinDLL(xInputDLLFileName) self.__XInputSetState = xinput.XInputSetState self.__XInputSetState.argtypes = [ctypes.c_uint, ctypes.POINTER(XINPUT_VIBRATION)] self.__XInputSetState.restype = ctypes.c_uint self.__l = 0 self.__r = 0 def adjust_vibration(self, left_motor_delta, right_motor_delta, set = False, controller = 0): if set: self.__l = left_motor self.__r = right_motor else: self.__l += left_motor_delta self.__r += right_motor_delta tempL = self.__l tempR = self.__r if self.__l > 255: tempL = 255 elif self.__l < 0: tempL = 0 if self.__r > 255: tempR = 255 elif self.__r < 0: tempR = 0 vibration = XINPUT_VIBRATION(int(tempL * 65535 / 255), int(tempR * 65535 / 255)) self.__XInputSetState(controller, ctypes.byref(vibration)) def stop_vibration(self, controller = 0): vibration = XINPUT_VIBRATION(0, 0) self.__XInputSetState(controller, ctypes.byref(vibration)) gpXInputObject = gpXInputClass() Quote Share this post Link to post Short link Share on other sites
kharlashkin 239 #293699 Posted September 29, 2015 (edited) исходники нужны после того, как в логах будет хоть что-то, откуда можно смотреть. компилять и запускать их никто не будет. пока ты логи не сделаешь, ничего не будет Добавил принты в код - ничего не получилось внятное у меня. Никогда логами не занимался, подскажите пример хороший пожалуйста. Edited September 29, 2015 by kharlashkin Quote Share this post Link to post Short link Share on other sites