📜 ⬆️ ⬇️

WoT gamepad feedback support

Good time of day, dear habrasoobschestvo!

Soon there will be a year, as I play on the gamepad in World of Tanks , if someone missed, as I chose the first PC in my life for the game, I ask here .

It is interesting to play a gamepad, but the developers do not want to officially support it, respectively, it is necessary to distort in every possible way to get "some functionality".
')


I will start with a small digression and describe the details of the game in WoT on the gamepad from the "box 360".

For more or less sane game you need an Xpadder . Video, as I set up


How to play? An example of an ordinary battle


Retreat. Since I’m not a wizard, I’m just learning, a lot of the code below was not written by me, I’m writing how I did what I’ve written by my own understanding, and I’m happy to receive any comments and help.

Now to the point.
Everyone knows that in many games the so-called feedback from the gamepad or ForceFeedback is used, which gives a deeper immersion in the game process due to vibrations (you go over bumps - there is vibration, you get hit by the enemy - there is vibration, etc.). Of course, that I was interested in the opportunity to receive vibration feedback on the gamepad in the “tanchiki”.
Digging this topic found the following points, allowing it to do:
1. All that is needed is written in python, it is this language that is used in the game to perform everything and everything (I think that except for the BigWorld core).
2. On stackoverflow , I found the code I needed, which allows to transfer vibrations to the gamepad.
3. Wargaming has already built into its game the vibrations for the GameTrix vibrocall, the vibroning project itself is open and the entire SDK is available for study and download.
4. Search the game folders for the location of the scripts "World_of_Tanks \ res \ scripts \ client \ vibroeffect".

After sorting out the SDK vibronakdki “on the shelves, scripts of the game - it turns out that using XVM (eXtended Visualization Mod for World of Tanks), you can try to replace the BigWorld.WGVibration on GamePadVibration, directly through which to call the necessary vibration methods directly in the gamepad.
But it turned out that in the game python there is no full-fledged ctypes, respectively, there is a need to make a service that allows you to perform a "vibrating" script on a regular python, receiving commands from the game. This service was created using Flask . Below I give the code of the executable script, which transmits the vibration to the gamepad during shots, receiving hits / bounce and damage to the tank. Vibration effects were written by me from the original ones for vibroncaps.
GPService.py
ENABLE_LOG = False d = dict() from flask import Flask from flask import request import ctypes # Define necessary structures class XINPUT_VIBRATION(ctypes.Structure): _fields_ = [("wLeftMotorSpeed", ctypes.c_ushort), ("wRightMotorSpeed", ctypes.c_ushort)] xinput = ctypes.windll.xinput1_3 # Load Xinput.dll # Set up function argument types and return type XInputSetState = xinput.XInputSetState XInputSetState.argtypes = [ctypes.c_uint, ctypes.POINTER(XINPUT_VIBRATION)] XInputSetState.restype = ctypes.c_uint # You can also create a helper function like this: def set_vibration(controller, left_motor, right_motor): vibration = XINPUT_VIBRATION(int(left_motor * 65535), int(right_motor * 65535)) XInputSetState(controller, ctypes.byref(vibration)) if not ENABLE_LOG: import logging log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) app = Flask(__name__) @app.route('/connect') def connect(): print 'Connection checked - Ok.' return 'True' @app.route('/loadEffectFromFile') def loadEffectFromFile(): effectHandle = request.args.get('effectHandle') fileName = request.args.get('fileName') #print #print 'loadEffectFromFile' #print 'effectHandle =', request.args.get('effectHandle') #print 'fileName =', request.args.get('fileName') if not effectHandle in d: d[effectHandle] = fileName return '' @app.route('/getEffectLength') def getEffectLength(): #print #print 'getEffectLength' #print 'effectHandle =', request.args.get('effectHandle') #print 'returnedLength =', request.args.get('returnedLength') return '' import threading, time def shot_main(): set_vibration(0, 1.0, 1.0) time.sleep(0.15) set_vibration(0, 0, 0) time.sleep(0.25) set_vibration(0, 0.5, 0) time.sleep(0.25) set_vibration(0, 0.0, 0.0) def shot_large(): set_vibration(0, 0.5, 0.6) time.sleep(0.1) set_vibration(0, 0.3, 0) time.sleep(0.1) set_vibration(0, 0.1, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.5) time.sleep(0.1) set_vibration(0, 0.0, 0.0) def shot_medium(): set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.6, 0.6) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.1) set_vibration(0, 0.2, 0) time.sleep(0.1) set_vibration(0, 0, 0.6) time.sleep(0.2) set_vibration(0, 0.0, 0.0) def shot_small(): set_vibration(0, 0.6, 0.8) time.sleep(0.1) set_vibration(0, 0, 0.4) time.sleep(0.1) set_vibration(0, 0.0, 0.0) def hit_nonpenetration(): set_vibration(0, 0.5, 0.5) time.sleep(0.1) set_vibration(0, 0.0, 0.0) def hit_ricochet(): set_vibration(0, 0.8, 0.8) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.2) set_vibration(0, 0.0, 0.5) time.sleep(0.05) set_vibration(0, 0, 0) def hit_splash(): set_vibration(0, 0.8, 0) time.sleep(0.1) set_vibration(0, 0.4, 0.8) time.sleep(0.1) set_vibration(0, 0, 0.4) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.05) set_vibration(0, 0, 0.4) time.sleep(0.15) set_vibration(0, 0, 0) def hit(): set_vibration(0, 1, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.05) set_vibration(0, 0, 1) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.05) set_vibration(0, 0.6, 0.6) time.sleep(0.1) set_vibration(0, 0.5, 0.5) time.sleep(0.05) set_vibration(0, 0.25, 0.25) time.sleep(0.05) set_vibration(0, 0, 0) def crit_contusion(): set_vibration(0, 1, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.2) set_vibration(0, 0, 0.4) time.sleep(0.2) set_vibration(0, 0, 0) time.sleep(0.3) set_vibration(0, 0, 0.3) time.sleep(0.2) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0, 0.25) time.sleep(0.2) set_vibration(0, 0, 0) def crit_death(): set_vibration(0, 1, 1) time.sleep(0.1) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 1) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.8) time.sleep(0.1) set_vibration(0, 0.8, 0) time.sleep(0.1) set_vibration(0, 0, 0.8) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.5, 0.5) time.sleep(0.1) set_vibration(0, 0.4, 0.3) time.sleep(0.1) set_vibration(0, 0.3, 0.1) time.sleep(0.1) set_vibration(0, 0.2, 0) time.sleep(0.1) set_vibration(0, 0.1, 0) time.sleep(0.1) set_vibration(0, 0, 0) def crit_engine(): set_vibration(0, 1, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.1) set_vibration(0, 0.4, 0.6) time.sleep(0.3) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.6) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.4, 0.6) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.1) set_vibration(0, 0.4, 0.6) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.6) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.4, 0.6) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.2) set_vibration(0, 0, 0) def crit_fire(): set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0) time.sleep(0.1) set_vibration(0, 0, 0.3) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.5) set_vibration(0, 0.5, 0.5) time.sleep(2) set_vibration(0, 0, 0) def crit_run(): set_vibration(0, 1, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.2) set_vibration(0, 0, 0.8) time.sleep(0.3) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.5) time.sleep(0.3) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.8, 0) time.sleep(0.1) set_vibration(0, 0.6, 0) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.1) set_vibration(0, 0.2, 0) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.4, 0) time.sleep(0.1) set_vibration(0, 0.2, 0) time.sleep(0.1) set_vibration(0, 0.1, 0) time.sleep(0.1) set_vibration(0, 0, 0) def crit_track_move(): set_vibration(0, 0.6, 0.2) time.sleep(0.1) set_vibration(0, 0, 0.1) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.4) set_vibration(0, 0, 0.1) time.sleep(0.1) set_vibration(0, 0, 0.05) time.sleep(0.1) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.1) time.sleep(0.1) set_vibration(0, 0, 0.05) time.sleep(0.1) set_vibration(0, 0, 0) def crit_track(): set_vibration(0, 0.8, 0) time.sleep(0.05) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0, 0.8) time.sleep(0.05) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.5, 0.5) time.sleep(0.05) set_vibration(0, 0, 0) time.sleep(0.1) set_vibration(0, 0.5, 0.5) time.sleep(0.05) set_vibration(0, 0, 0) @app.route('/startEffect') def startEffect(): handle = request.args.get('handle') count = request.args.get('count') if handle in d: print 'startEffect: '+ d[handle] if 'shot_main' in d[handle]: print 'shot_main' # init thread t1 = threading.Thread(target=shot_main) # start threads t1.start() if 'shot_large' in d[handle]: print 'shot_large' # init thread t1 = threading.Thread(target=shot_large) # start threads t1.start() if 'shot_medium' in d[handle]: print 'shot_medium' # init thread t1 = threading.Thread(target=shot_medium) # start threads t1.start() if 'shot_small' in d[handle]: print 'shot_small' # init thread t1 = threading.Thread(target=shot_small) # start threads t1.start() if 'hit_nonpenetration' in d[handle]: print 'hit_nonpenetration' # init thread t1 = threading.Thread(target=hit_nonpenetration) # start threads t1.start() if 'hit_ricochet' in d[handle]: print 'hit_ricochet' # init thread t1 = threading.Thread(target=hit_ricochet) # start threads t1.start() if 'hit_splash' in d[handle]: print 'hit_splash' # init thread t1 = threading.Thread(target=hit_splash) # start threads t1.start() if 'hit' in d[handle]: print 'hit' # init thread t1 = threading.Thread(target=hit) # start threads t1.start() if 'crit_contusion' in d[handle]: print 'crit_contusion' # init thread t1 = threading.Thread(target=crit_contusion) # start threads t1.start() if 'crit_death' in d[handle]: print 'crit_death' # init thread t1 = threading.Thread(target=crit_death) # start threads t1.start() if 'crit_engine' in d[handle]: print 'crit_engine' # init thread t1 = threading.Thread(target=crit_engine) # start threads t1.start() if 'crit_fire' in d[handle]: print 'crit_fire' # init thread t1 = threading.Thread(target=crit_fire) # start threads t1.start() if 'crit_run' in d[handle]: print 'crit_run' # init thread t1 = threading.Thread(target=crit_run) # start threads t1.start() if 'crit_track_move' in d[handle]: print 'crit_track_move' # init thread t1 = threading.Thread(target=crit_track_move) # start threads t1.start() if 'crit_track' in d[handle]: print 'crit_track' # init thread t1 = threading.Thread(target=crit_track) # start threads t1.start() # print # print 'startEffect' # print 'handle =', handle # print 'count =', count return '' if __name__ == "__main__": app.debug = True app.run() 



Also for the work of vibrations on the gamepad:
1. It is necessary to install Python (latest version ), let the folder be by default “C: \ Python27”.

2. You need to install Flask, I did this instruction . Download the distribute_setup.py file to the “C: \ temp” folder (for example), launch the “Win ​​+ R” console - cmd and execute the “C: \ Python27 \ python.exe C: \ temp \ distribute_setup.py” command and watch the boot process the necessary files in the folder “C: \ Python27 \ Scripts”, then in the console run the commands in turn and observe their execution:
C: \ Python27 \ python.exe C: \ Python27 \ Scripts \ easy_install-2.7-script.py Flask
C: \ Python27 \ python.exe C: \ Python27 \ Scripts \ easy_install-2.7-script.py Jinja2
C: \ Python27 \ python.exe C: \ Python27 \ Scripts \ easy_install-2.7-script.py Werkzeug
C: \ Python27 \ python.exe C: \ Python27 \ Scripts \ easy_install-2.7-script.py Virtualenv

The hidden launch of system python from the default folder “C: \ Python27” is registered in the GPsettings.xml file.

Currently, I am testing a script for taking effects directly from files for vibroning with mixing effects.

Good luck to everyone in the battles!

PS In connection with the low interest of the habrasoobshchestva, all interested in the official forum WoT .

Source: https://habr.com/ru/post/208478/


All Articles