Jump to content
Korean Random
SoprachevAK

Сбор статистики о попаданиях

Recommended Posts

11 hours ago, StranikS_Scan said:

Немного про механику игры, исходя из клиентского кода

 

Разброс в механике игры задается сервером как тангенс половинного угла разброса орудия dispersionAngle. Эту цифру сервер обсчитывает с тиком 0,1 сек и шлет клиенту игры. Вычисляет её он как функцию от динамических характеристик танка, путем применения дополнительных коэффициентов к базовому тангенсу разброса орудия, прописанному в файлах ТТХ для дистанции 100 метров. Все эти коэффициенты и формулу можно посмотреть в коде игры, они дублируют расчеты на сервере чтобы сглаживать движение объектов в клиенте игры. Расчеты в клиенте вынесены в отдельную функцию getOwnVehicleShotDispersionAngle. Ниже её код, а вот тут его разбор в числах, правда он мог немного устареть.

 


    def getOwnVehicleShotDispersionAngle(self, turretRotationSpeed, withShot=0):
        descr = self.__getDetailedVehicleDescriptor()
        aimingStartTime, aimingStartFactor, multFactor, gunShotDispersionFactorsTurretRotation, chassisShotDispersionFactorsMovement, chassisShotDispersionFactorsRotation, aimingTime = self.__aimingInfo
        vehicleSpeed, vehicleRSpeed = self.getOwnVehicleSpeeds(True)
        vehicleMovementFactor = vehicleSpeed * chassisShotDispersionFactorsMovement
        vehicleMovementFactor *= vehicleMovementFactor
        vehicleRotationFactor = vehicleRSpeed * chassisShotDispersionFactorsRotation
        vehicleRotationFactor *= vehicleRotationFactor
        turretRotationFactor = turretRotationSpeed * gunShotDispersionFactorsTurretRotation
        turretRotationFactor *= turretRotationFactor
        if withShot == 0:
            shotFactor = 0.0
        elif withShot == 1:
            shotFactor = descr.gun.shotDispersionFactors['afterShot']
        else:
            shotFactor = descr.gun.shotDispersionFactors['afterShotInBurst']
        shotFactor *= shotFactor
        idealFactor = vehicleMovementFactor + vehicleRotationFactor + turretRotationFactor + shotFactor
        additiveFactor = self.__getAdditiveShotDispersionFactor(descr)
        idealFactor *= additiveFactor ** 2
        idealFactor = multFactor * math.sqrt(1.0 + idealFactor)
        currTime = BigWorld.time()
        aimingFactor = aimingStartFactor * math.exp((aimingStartTime - currTime) / aimingTime)
        isGunReloading = self.guiSessionProvider.shared.ammo.isGunReloading()
        if aimingFactor < idealFactor:
            aimingFactor = idealFactor
            self.__aimingInfo[0] = currTime
            self.__aimingInfo[1] = aimingFactor
            if abs(idealFactor - multFactor) < 0.001:
                if not self.__isAimingEnded and not isGunReloading:
                    self.soundNotifications.play('sight_convergence')
                self.__isAimingEnded = True
            elif idealFactor / multFactor > 1.1:
                self.__isAimingEnded = False
        elif aimingFactor / multFactor > 1.1:
            self.__isAimingEnded = False
        return [descr.gun.shotDispersionAngle * aimingFactor, descr.gun.shotDispersionAngle * idealFactor]

 

В механике игры снаряды летят по параболе, параметры которой зависят от дистанции от танка игрока до точки прицеливания. Сервер в игре вычисляет дистанции по прямой, либо от опорной точки модели танка, либо от точки вылета снаряда. При этом снаряд на всех моделях вылетает из точки крепления пушки, она же опорная точка орудия (трассер кстати рисуется из другой точки, из конца орудия - элемент модели _GunFire). Первое юзается в механике маскировки и в засвета, второе в баллистике и прицеливании.

 

Опорная точка пушки вычисляется, например так:


startPoint = player.getOwnVehiclePosition()
startPoint += player.vehicleTypeDescriptor.hull.turretPositions[0] + player.vehicleTypeDescriptor.turret.gunPosition

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


markerPos = player.gunRotator.markerInfo[0]

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


markerDist = startPos.distTo(markerPos)

Тогда радиус круга разброса в точке прицеливания для любого танка это:


dispersionRadius = player.gunRotator.dispersionAngle * markerDist

В клиенте игры это все есть в коде, который отвечает за отрисовку сведения. Для этого используются следующие функции:

 

1. Внеклассовая функция расчета баллистических параметров в точке прицеливания getCappedShotTargetInfos


def getCappedShotTargetInfos(shotPos, shotVec, gravity, shotDescr, vehicleID, minBounds, maxBounds, collisionStrategy):
    endPos, direction, collData, usedMaxDistance = BigWorld.wg_getCappedShotTargetInfos(BigWorld.player().spaceID, shotPos, shotVec, gravity, shotDescr.maxDistance, vehicleID, minBounds, maxBounds, collisionStrategy)
    if collData != 0:
        collData = EntityCollisionData(*collData)
    else:
        collData = None
    return (endPos, direction, collData, usedMaxDistance)

Она обсчитывает траекторию нативно, но как именно она считает можно глянуть под спойлером. В списке выходных параметров direction это вектор попадания снаряда с учетом баллистической траектории.

 

  Reveal hidden contents

 


Модуль projectile_trajectory.py содержит неиспользуемые сегодня, но все еще актуальные, функции расчета траектории, это BigWorld.wg_computeProjectileTrajectory и пайтон аналог её, когда-то давно использовавшийся:

 



def computeProjectileTrajectory(beginPoint, velocity, gravity, time, epsilon):
    checkPoints = []
    endPoint = beginPoint + velocity.scale(time) + gravity.scale(time * time * 0.5)
    stack = [(velocity, beginPoint, endPoint)]
    while len(stack) > 0:
        lastIdx = len(stack) - 1
        v1, p1, p2 = stack[lastIdx]
        del stack[lastIdx]
        delta = p2 - p1
        xzNormal = Math.Vector3(-delta.z, 0.0, delta.x)
        normal = xzNormal * delta
        if abs(normal.y) < epsilon:
            checkPoints.append(p2)
            continue
        normal.normalise()
        extremeTime = normal.dot(v1) / (-gravity.y * normal.y)
        extremePoint = v1.scale(extremeTime) + gravity.scale(extremeTime * extremeTime * 0.5)
        dist = abs(normal.dot(extremePoint))
        if dist > epsilon:
            extremeVelocity = v1 + gravity.scale(extremeTime)
            stack.append((extremeVelocity, p1 + extremePoint, p2))
            stack.append((v1, p1, p1 + extremePoint))
        checkPoints.append(p2)

    return checkPoints



computeProjectileTrajectory.thumb.jpg.d928831c8d87dd6d5a654f22c6951068.jpg
 

 

2. Классовая функция расчета баллистических параметров и разброса в точке прицеливания __getGunMarkerPosition, использующая функцию из п.1


    def __getGunMarkerPosition(self, shotPos, shotVec, dispersionAngles):
        shotDescr = self._avatar.getVehicleDescriptor().shot
        gravity = Math.Vector3(0.0, -shotDescr.gravity, 0.0)
        testVehicleID = self.getAttachedVehicleID()
        collisionStrategy = AimingSystems.CollisionStrategy.COLLIDE_DYNAMIC_AND_STATIC
        minBounds, maxBounds = BigWorld.player().arena.getSpaceBB()
        endPos, direction, collData, usedMaxDistance = AimingSystems.getCappedShotTargetInfos(shotPos, shotVec, gravity, shotDescr, testVehicleID, minBounds, maxBounds, collisionStrategy)
        distance = shotDescr.maxDistance if usedMaxDistance else (endPos - shotPos).length
        markerDiameter = 2.0 * distance * dispersionAngles[0]
        idealMarkerDiameter = 2.0 * distance * dispersionAngles[1]
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isClientReady:
            markerDiameter, endPos, direction = replayCtrl.getGunMarkerParams(endPos, direction)
        return (endPos, direction, markerDiameter, idealMarkerDiameter, collData)

Как видим, диаметр круга разброса в точке прицеливания это удвоенное текущее значение тангенса половинного угла разброса орудия танка 2*dispersionAngles[0] помноженное на дистанцию distance = .... (endPos - shotPos).length между опорной точкой орудия shotPos и точкой прицеливания endPos.

 

3. Далее находим, где используется __getGunMarkerPosition. В функции обновления сведения прицела __updateGunMarker, которая вызывается пока игрок в бою с периодичностью 0,1 сек, что составляет тик сервера:


    def __updateGunMarker(self, forceRelaxTime=None):
        if self._avatar.getVehicleAttached() is None:
            return
        else:
            shotPos, shotVec = self.getCurShotPosition()
            markerPos, markerDir, markerSize, idealMarkerSize, collData = self.__getGunMarkerPosition(shotPos, shotVec, self.__dispersionAngles)
            replayCtrl = BattleReplay.g_replayCtrl
            if replayCtrl.isRecording and not replayCtrl.isServerAim:
                replayCtrl.setGunMarkerParams(markerSize, markerPos, markerDir)
            if not self.__targetLastShotPoint:
                self.__lastShotPoint = markerPos
            replayCtrl = BattleReplay.g_replayCtrl
            if replayCtrl.isPlaying and replayCtrl.isUpdateGunOnTimeWarp:
                self._avatar.inputHandler.updateGunMarker(markerPos, markerDir, (markerSize, idealMarkerSize), 0.001, collData)
            else:
                relaxTime = self.__ROTATION_TICK_LENGTH if forceRelaxTime is None else forceRelaxTime
                self._avatar.inputHandler.updateGunMarker(markerPos, markerDir, (markerSize, idealMarkerSize), relaxTime, collData)
            self.__markerInfo = (markerPos, markerDir, markerSize)
            if self._avatar.inCharge:
                self._updateMultiGunCollisionData()
            return

А еще в дублирующей её setShotPosition, которая обеспечивает автовозвышение орудия танка и обновление, упомянутого выше публичного буфера player.gunRotator.markerInfo.

 

4. Теперь нужно лезть в дебри модулей, отвечающих за управление прицелом и отрисовку сведения через флэшку, именно туда ведет вызов _avatar.inputHandler.updateGunMarker из кода выше. Если опустить подробности то, передача данных идет через объект DataProvider, который по сути является прокладкой для передачи данных в код флэшки прицела. Здесь же стоит отметить, что версии провайдера разные для прицела арты и для остальных прицелов танков.

 

Для прицела арты создается он так:


    def _makeSPGProvider():
        dataProvider = GUI.WGSPGGunMarkerDataProvider(aih_constants.SPG_GUN_MARKER_ELEMENTS_COUNT, aih_constants.SPG_GUN_MARKER_ELEMENTS_RATE)
        dataProvider.positionMatrixProvider = Math.MatrixAnimation()
        dataProvider.maxTime = 5.0
        dataProvider.serverTickLength = constants.SERVER_TICK_LENGTH
        dataProvider.sizeScaleRate = aih_constants.SPG_GUN_MARKER_SCALE_RATE
        dataProvider.sizeConstraint = (aih_constants.SPG_GUN_MARKER_MIN_SIZE, aih_constants.SPG_GUN_MARKER_MAX_SIZE)
        dataProvider.setRelaxTime(constants.SERVER_TICK_LENGTH)
        return dataProvider

А для всех остальных вот так


    def _makeDefaultProvider():
        dataProvider = GUI.WGGunMarkerDataProvider()
        dataProvider.positionMatrixProvider = Math.MatrixAnimation()
        dataProvider.setStartSize(_setupGunMarkerSizeLimits(dataProvider)[0])
        return dataProvider

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


GUN_MARKER_MIN_SIZE = 32.0
SPG_GUN_MARKER_ELEMENTS_COUNT = 37
SPG_GUN_MARKER_ELEMENTS_RATE = 10
SPG_GUN_MARKER_MIN_SIZE = 50.0
SPG_GUN_MARKER_MAX_SIZE = 100.0
SPG_GUN_MARKER_SCALE_RATE = 10.0

Обращаем внимание на последний параметр, у сведения арты есть дополнительный коэф. масштаба SPG_GUN_MARKER_SCALE_RATE.

 

Передача данных в провайдер прицела арты выглядит вот так:


    def update(self, markerType, position, direction, size, relaxTime, collData):
        super(_SPGGunMarkerController, self).update(markerType, position, direction, size, relaxTime, collData)
        positionMatrix = Math.Matrix()
        positionMatrix.setTranslate(position)
        self._updateMatrixProvider(positionMatrix, relaxTime)
        self._size = size[0]  #################################################
        self._update()        
        
    def _update(self):
        pos3d, vel3d, gravity3d = self._getCurrentShotInfo() 
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isClientReady:
            self.__updateRelaxTime()
        self._updateDispersionData() 
        self._dataProvider.update(pos3d, vel3d, gravity3d, self._size)

    def _getCurrentShotInfo(self):
        gunMat = AimingSystems.getPlayerGunMat(self._gunRotator.turretYaw, self._gunRotator.gunPitch)
        position = gunMat.translation
        velocity = gunMat.applyVector(Math.Vector3(0, 0, self._shotSpeed))
        return (position, velocity, Math.Vector3(0, -self._shotGravity, 0)) #########################        
        
    def _updateDispersionData(self):
        dispersionAngle = self._gunRotator.dispersionAngle #########################
        isServerAim = self._gunMarkerType == _MARKER_TYPE.SERVER
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isClientReady:
            d, s = replayCtrl.getSPGGunMarkerParams()
            if d != -1.0 and s != -1.0:
                dispersionAngle = d
        elif replayCtrl.isRecording:
            if replayCtrl.isServerAim and isServerAim:
                replayCtrl.setSPGGunMarkerParams(dispersionAngle, 0.0)
            elif not isServerAim:
                replayCtrl.setSPGGunMarkerParams(dispersionAngle, 0.0)
        self._dataProvider.setupConicDispersion(dispersionAngle) 

В то время как для остальных танков вот так:


    def update(self, markerType, pos, direction, sizeVector, relaxTime, collData):
        super(_DefaultGunMarkerController, self).update(markerType, pos, direction, sizeVector, relaxTime, collData)
        positionMatrix = Math.Matrix()
        positionMatrix.setTranslate(pos)
        self._updateMatrixProvider(positionMatrix, relaxTime)
        size = sizeVector[0]
        idealSize = sizeVector[1]
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isClientReady:
            s = replayCtrl.getArcadeGunMarkerSize()
            if s != -1.0:
                size = s
        elif replayCtrl.isRecording:
            if replayCtrl.isServerAim and self._gunMarkerType == _MARKER_TYPE.SERVER:
                replayCtrl.setArcadeGunMarkerSize(size)
            elif self._gunMarkerType == _MARKER_TYPE.CLIENT:
                replayCtrl.setArcadeGunMarkerSize(size)
        positionMatrixForScale = self.__checkAndRecalculateIfPositionInExtremeProjection(positionMatrix)
        worldMatrix = _makeWorldMatrix(positionMatrixForScale)
        currentSize = _calcScale(worldMatrix, size) * self.__screenRatio
        idealSize = _calcScale(worldMatrix, idealSize) * self.__screenRatio
        self.__sizeFilter.update(currentSize, idealSize)
        self.__curSize = self.__sizeFilter.getSize()
        if self.__replSwitchTime > 0.0:
            self.__replSwitchTime -= relaxTime
            self._dataProvider.updateSize(self.__curSize, 0.0)
        else:
            self._dataProvider.updateSize(self.__curSize, relaxTime)

Рассмотрим сначала второй код. Для аркадного и снайперского прицелов размер сведения в пикселях вычисляется непосредственно в функции update() и затем отдается провайдеру. Для этого берется диаметр мгновенного значения круга разброса в текущей точке прицеливания size = sizeVector[0], высчитывается его масштаб для экрана игрока через функцию _calcScale и этот масштаб умножается на половину ширины экрана в пикселях self.__screenRatio. Последняя величина находится вот так self.__screenRatio = GUI.screenResolution()[0] * 0.5. Чтобы сведение в игре не было очень маленьким или очень большим, а оно будет таковыми, имеется фильтр self.__sizeFilter, который ограничивает минимально и максимально возможное значение круга сведения. Лимиты, которые задаются в него, вычисляются вот так:


def _setupGunMarkerSizeLimits(dataProvider, scale=None):
    if scale is None:
        settingsCore = dependency.instance(ISettingsCore)
        scale = settingsCore.interfaceScale.get()
    limits = (aih_constants.GUN_MARKER_MIN_SIZE * scale, min(GUI.screenResolution()))
    dataProvider.sizeConstraint = limits
    return limits

Переходим к арт-прицелу. У арты расчеты в пикселях в функции update() не выполняются, вместо этого данные о точке выстрела, векторах начальной скорости и гравитации и текущем диаметре круга разброса в точке прицеливания - pos3d, vel3d, gravity3d и self._size - передаются прямо в провайдер. А также в него передается текущее значение тангенса угла разброса орудия dispersionAngle. Что со всем этим делает провайдер WGSPGGunMarkerDataProvider сказать трудно, т.к. он нативный.

 

Если глянуть список доступных атрибутов и функций у WGSPGGunMarkerDataProvider, то там можно увидеть:


*** enableSmoothFiltering
*** getPointsInside
*** maxTime
*** positionMatrixProvider
*** relaxTime
*** reset
*** serverTickLength
*** setRelaxTime
*** setStartSize
*** setupConicDispersion
*** setupFlatRadialDispersion
*** sizeConstraint
*** sizeScaleRate
*** update
*** updateSize

Функция setupFlatRadialDispersion тоже встречается в коде клиента игры. Это код, который отвечает за отрисовку новой игровой фичи - подсветки на игровом поле места, куда стреляет или будет стрелять арта. Код класса можно глянуть тут. В качестве аргумента в функцию передается игровая константа areaRadius.

Весьма интересная инфа, спасибо.
Однако, сведение который отрисовывается в игре, и которое по факту на сервере весьма разные вещи.
Моя задачам -- определить насколько выстрел отклонился от маркера относительно разброса на момент выстрела. Я вижу 2 пути:

  1. Запоминать состояние маркера на момент выстрела и в момент попадания искать пересечение плоскости маркера с лучом от опорной точки до попадания
  2. Запоминать состояние маркера на момент выстрела, хукать трасер, после чего искать пересечение параболы с плоскостью маркера. Так я делаю сейчас, не самый простой способ, зато даёт больше информации для дебага 

Где плоскость маркера это плоскость ортогональная направлению от маркера к опорной точки танка
Ну и вопрос в том, насколько это корректно для всех типов танков.
 

Share this post


Link to post

Short link
Share on other sites

Если у кого то будет интерес к моду и желание чёнить допилить, могу пригласить в гитхаб. Публичным делать не буду из соображений защиты от мамкиных хацкеров, которые захотят заспамить сервер левыми пакетами  

Share this post


Link to post

Short link
Share on other sites
8 часов назад, SoprachevAK сказал:

Публичным делать не буду из соображений защиты от мамкиных хацкеров, которые захотят заспамить сервер левыми пакетами  

 

Дык убери реквизиты сервера из исходников мода на гитхабе и всё, их будет безопасно публиковать.

Share this post


Link to post

Short link
Share on other sites
8 часов назад, SoprachevAK сказал:

Если у кого то будет интерес к моду и желание чёнить допилить, могу пригласить в гитхаб. Публичным делать не буду из соображений защиты от мамкиных хацкеров, которые захотят заспамить сервер левыми пакетами  

Какие-то очень странные "соображения".

Закрытость кода мода вообще никак не помешает спамить на сервер тем, кто захочет так делать.

А вот на скорость развития и на качество мода закрытость точно повлияет негативно.

Share this post


Link to post

Short link
Share on other sites
13 часов назад, SoprachevAK сказал:

Однако, сведение который отрисовывается в игре, и которое по факту на сервере весьма разные вещи.

 

На сервере, как я понимаю, сведения нет вообще. Оно там просто не нужно. С сервера на клиент приходит вот такая инфа shotPos, shotVec, dispersionAngle. А клиент может на её основе построить "серверное сведение" (включается в настройках игры) и делает это он по тем же формулам и кодам, что он строит клиентское сведение. С той лишь разницей, что клиентское сведение строиться на основе dispersionAngle, которое клиент считает сам.

 

13 часов назад, SoprachevAK сказал:

Моя задачам -- определить насколько выстрел отклонился от маркера относительно разброса на момент выстрела. Я вижу 2 пути:

  1. Запоминать состояние маркера на момент выстрела и в момент попадания искать пересечение плоскости маркера с лучом от опорной точки до попадания
  2. Запоминать состояние маркера на момент выстрела, хукать трасер, после чего искать пересечение параболы с плоскостью маркера. Так я делаю сейчас, не самый простой способ, зато даёт больше информации для дебага 

Где плоскость маркера это плоскость ортогональная направлению от маркера к опорной точки танка
Ну и вопрос в том, насколько это корректно для всех типов танков.

 

Я бы вот так делал:

 

1. Работал с с данными серверного прицела. Так как только они отвечает тому, что реально происходит на сервере. Можно параллельно и клиентские брать, чтоб сравнивать и видеть расхождение. Чтоб инфа приходила о серверном прицеле в updateGunMarker в PlayerAvatar, нужно в моде принудительно включать получение данных о прицеле с сервера. Делается так BigWorld.player().enableServerAim(True).

 

2. Отклонение снаряда рассчитывал по следующей модели:

 

2042054359_.thumb.png.dc2abeaecaa8e84cdfb491417fdba540.png

 

А) В последний момент перед выстрелом фиксируем ShotPos, EndPos, direction, dispersionAngle

Б) При попадании снаряда в танк или землю получаем hitPoint (можно еще декодировать hitDir, но он ниже не нужен)

В) Строим по точкам с малым шагом обратную траекторию из точки EndPos, используя инвертированное значение direction

Г) Путем перебора точек траектории находим точку nearestPoint, в которой deviation минимально, а также дистанцию до неё npDistance от точки ShotPos

Д) Вычисляем радиус круга исходного разброса орудия в точке nearestPoint, как dispRadius = dispersionAngle * npDistance

Е) Сравниваем отклонение снаряда deviation c радиусом круга разброса dispRadius

 

3. Как это всё реализовать в моде я знаю, все эти этапы я проходил, когда работал над кое-чем, только с другими целями.

Edited by StranikS_Scan
  • Upvote 1

Share this post


Link to post

Short link
Share on other sites
12 hours ago, StranikS_Scan said:

Дык убери реквизиты сервера из исходников мода на гитхабе и всё, их будет безопасно публиковать.

 

12 hours ago, yepev said:

Закрытость кода мода вообще никак не помешает спамить на сервер тем, кто захочет так делать.


Реквизиты сервера легко можно считать монитором http трафика, ровно как содержание запроса, однако имея эти данные, можно только отправить их повторно, что проигнорируется сервером и никак на статистику не повлияет. 
Мод от примитивной декомпиляии защищён обфускацией и протекцией 
Следующий шаг "хакера" найти исходник мода и посмотреть что он там вообще отправляет, и найдя на гитхабе мод, где он увидит и полный запрос и алгоритм шифрования (если вынести алгоритм шифрования в отдельный модуль, то имея модель запроса и результат её шифрования, можно вычислить алгоритм)

Думаю такие шаги защиты отбросят 90% взломщиков. Если человек специалист и очень будет хотеть взломать, он взломает при любых защитах, но есть люди которые хотят взломать по приколу, напакостить, сломать статистику, вот от них, я надеюсь, мод защищён

Share this post


Link to post

Short link
Share on other sites

Очень наивно. Всё, что касается защиты сервера, нужно делать именно на сервере. Возня с закрытием и усложнением клиента никак не помешает вредителям, она помешает только нормальным людям.

Edited by yepev

Share this post


Link to post

Short link
Share on other sites
12 hours ago, StranikS_Scan said:

BigWorld.player().enableServerAim(True)

Проверю, попробую, добавлю
 

12 hours ago, StranikS_Scan said:

Строим по точкам с малым шагом обратную траекторию из точки EndPos, используя инвертированное значение direction

Тут есть проблема: снаряд мог попасть по траектории сильно дальше или сильно ближе EndPos, а мог и в целом улететь очень далеко (например при выстреле по танку на холме, промазать и улететь в скайбокс, тут ещё отдельный вопрос о попадание по скайбоксу)

Ты уверен, что плоскость разброса (зелёная полоска на картинке) ортогональна вектору скорости снаряда (производной траектории)?
Если да, deviation можно найти аналитически двумя способами
1. найти nearestPoint, как точку траектории EndPos, лежащую на плоскости заданной hitPoint и нормалью = производной от траектории

2. найти пересечение траектории hitPoint с плоскостью через EndPos 

Я сейчас использую второй способ, но беру траекторию трассера, однако с плоскостью разброса вопрос остаётся открытым

 

Edited by SoprachevAK

Share this post


Link to post

Short link
Share on other sites
8 minutes ago, yepev said:

Очень наивно. Всё, что касается защиты сервера, нужно делать именно на сервере. Возня с закрытием и усложнением клиента никак не помешает вредителям, она помешает только нормальным людям.

Ну слушай, сделать защиту от данных, которые пользователи должны отправлять сами -- невозможно никак.
Можно только усложнить жизнь злоумышленникам, это как кодовый замок на сейфе, взломать можно, но если не выкладывать его код в открытый доступ на гитхаб, это будет сильно сложнее. 

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

screen.png

Edited by SoprachevAK

Share this post


Link to post

Short link
Share on other sites
8 часов назад, SoprachevAK сказал:

 


Реквизиты сервера легко можно считать монитором http трафика, ровно как содержание запроса, однако имея эти данные, можно только отправить их повторно, что проигнорируется сервером и никак на статистику не повлияет. 
Мод от примитивной декомпиляии защищён обфускацией и протекцией 
Следующий шаг "хакера" найти исходник мода и посмотреть что он там вообще отправляет, и найдя на гитхабе мод, где он увидит и полный запрос и алгоритм шифрования (если вынести алгоритм шифрования в отдельный модуль, то имея модель запроса и результат её шифрования, можно вычислить алгоритм)

Думаю такие шаги защиты отбросят 90% взломщиков. Если человек специалист и очень будет хотеть взломать, он взломает при любых защитах, но есть люди которые хотят взломать по приколу, напакостить, сломать статистику, вот от них, я надеюсь, мод защищён

 

Модуль отправки данных на гитхаб не заливать и всё. В .gitignore его добавить.

Share this post


Link to post

Short link
Share on other sites
6 minutes ago, StranikS_Scan said:

 

Модуль отправки данных на гитхаб не заливать и всё. В .gitignore его добавить.

Ну я же там в скобочках написал, что если так сделать, найдут модель данных, которая в этот модуль передаётся. Ну или придётся делать функцию Send на 100500 параметров и собирать модель уже внутри, что мне конечно не очень нравится

Но если есть жалеющие улучшать и допиливать, тогда подумаю как там можно правильно декомпозировать

Share this post


Link to post

Short link
Share on other sites

У тебя в принципе неправильный подход к "защите", которая и не защита вовсе, а просто костыль до первого любопытствующего, которому будет не лень напакостить.

Исходить нужно не из сложности разобрать отправку данных, а из невозможности засрать чужие данные в принципе.

 

Посмотри на опыт XVM и сделай также:

  1. Чтобы общаться с сервером пользователь сначала обязан получить собственный уникальный секретный токен, привязанный к ID.
  2. Любое дальнейшее общение с сервером происходит именно через токен, а не через ID. Т.е. всегда понятно, что данные отправляются с конкретного аккаунта и это проверенно на 100%. С таким подходим можно насрать максимум в СВОИ же данные и невозможно никак навредить данным других юзеров.

А играть в "шифрование", оставляя всё на клиенте - это просто смешно :wink:

Share this post


Link to post

Short link
Share on other sites
7 часов назад, SoprachevAK сказал:

Тут есть проблема: снаряд мог попасть по траектории сильно дальше или сильно ближе EndPos, а мог и в целом улететь очень далеко (например при выстреле по танку на холме, промазать и улететь в скайбокс, тут ещё отдельный вопрос о попадание по скайбоксу)

 

Ближе если, то модель та же. Если очень близки, т.е. меньше 100 метров, то баллистика не учитывается и можно с проекциями точек работать. А вот если точка попадания дальше точки прицеливания, тогда нужно сделать так:

 

61767365_.thumb.png.cf1459bbde8cba765c626d28c144ae80.png

 

...

Б) При попадании снаряда в танк или землю получаем hitPoint и декодируем hitDir

В) Строим по точкам с малым шагом обратную траекторию из точки hitPoint, используя инвертированное значение hitDir

Г) Путем перебора точек траектории находим точку nearestPoint, в которой deviation минимально, а также дистанцию до неё npDistance от точки ShotPos

Д) Вычисляем радиус круга исходного разброса орудия в точке endPoint, как dispRadius = dispersionAngle * distance

Е) Сравниваем отклонение снаряда deviation c радиусом круга разброса dispRadius

 

8 часов назад, SoprachevAK сказал:

Я сейчас использую второй способ, но беру траекторию трассера, однако с плоскостью разброса вопрос остаётся открытым

 

Ты должен знать, что трассер - это не траектория снаряда. Трассер это примерная визуализация и рисуется он условно и часто приближенно. Вектор скорости и точку начала трассера - сервер может от балды прислать, а может вообще не прислать. Отчасти это делается еще и для того чтобы отслеживание трассеров игроками не повлияло на геймплей. В таком моде как у тебя его использовать не следует.

 

8 часов назад, SoprachevAK сказал:

Ты уверен, что плоскость разброса (зелёная полоска на картинке) ортогональна вектору скорости снаряда (производной траектории)?
Если да, deviation можно найти аналитически двумя способами
1. найти nearestPoint, как точку траектории EndPos, лежащую на плоскости заданной hitPoint и нормалью = производной от траектории

2. найти пересечение траектории hitPoint с плоскостью через EndPos 

 

Это такой вариант из возможных вариантов модели. В действительности эту плоскость можно сориентировать как угодно и сделать даже не плоскостью, а поверхностью. Все зависит от того, что мы хотим получить в итоге и как лучше всего это оценить. Но нужно помнить с чего всё начинается. А в механике игры все начинается с того, что сервер генерирует случайным образом dispersionAngle. А это как мы знаем тангенс угла отклонения начального вектора снаряда в опорной точке орудия. Если брать это за аксиому, то получаем модели ниже.

 

2055745466_.thumb.png.52a800d6792f64e00b02c1f9fef35757.png

 

1190899117_.thumb.png.3b7e51b3e4d6729f25ee33297c38b0fe.png

 

26936923_.thumb.png.3e186b972ef20da84d85c4ca397c6a81.png

 

На рисунках выше самой правильной будет последняя модель, т.к. она предполагает, путем построения обратных траекторий, восстановить вектор вылета снаряда и затем определить исходный тангенс угла разброса. Однако в этой модели погрешность напрямую зависит от дальности стрельбы. И по моему опыту врать она будет очень много и часто, если речь идет о стрельбе арты, так как чем длиннее восстанавливаемая баллистическая траектория, тем больше отклонение от реальной траектории. Это вызвано тем, что данные о точке попадания снаряда и восстановленный вектор часто не точны. Сервер их присылает только лишь для того чтобы клиент плюху нарисовал. Следовательно строить длинные траектории на их основе - не выгодно.

 

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

Share this post


Link to post

Short link
Share on other sites
16 minutes ago, yepev said:

У тебя в принципе неправильный подход к "защите", которая и не защита вовсе, а просто костыль до первого любопытствующего, которому будет не лень напакостить.

Исходить нужно не из сложности разобрать отправку данных, а из невозможности засрать чужие данные в принципе.

 

Посмотри на опыт XVM и сделай также:

  1. Чтобы общаться с сервером пользователь сначала обязан получить собственный уникальный секретный токен, привязанный к ID.
  2. Любое дальнейшее общение с сервером происходит именно через токен, а не через ID. Т.е. всегда понятно, что данные отправляются с конкретного аккаунта и это проверенно на 100%. С таким подходим можно насрать максимум в СВОИ же данные и невозможно никак навредить данным других юзеров.

А играть в "шифрование", оставляя всё на клиенте - это просто смешно :wink:

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

10 hours ago, yepev said:

помешает только нормальным людям

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

 

20 minutes ago, yepev said:

первого любопытствующего

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


Вот мод, вот сайт который в реалтайм отображает состояние бд, более чем уверен, что не сможешь взломать быстрее, чем пропадёт энтузиазм, именно для 95% таких взломщиков и существует защита

mod.wotStat_0.0.7.wotmod

Share this post


Link to post

Short link
Share on other sites
3 часа назад, SoprachevAK сказал:

Ну я же там в скобочках написал, что если так сделать, найдут модель данных, которая в этот модуль передаётся. Ну или придётся делать функцию Send на 100500 параметров и собирать модель уже внутри, что мне конечно не очень нравится

Но если есть жалеющие улучшать и допиливать, тогда подумаю как там можно правильно декомпозировать

 

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

 

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

Edited by StranikS_Scan

Share this post


Link to post

Short link
Share on other sites
24 минуты назад, SoprachevAK сказал:

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

Я понимаю за что ты переживаешь, и именно привязанность данных к человеку как раз решает твою проблему. Ведь ему придётся завести огромное количество аккаунтов и айпишников, чтобы статистически значимо заспамить сервер в таком раскладе. Если привязать данные к аккаунтам через токены и сделать грамотные лимиты по приёму данных с каждого токена (на основе IP, rate limits итд), то проблема будет решена на корню, а не полумерами с детским псевдошифрованием.

Share this post


Link to post

Short link
Share on other sites

Да, чуть не забыл, я выше писал, что сервер присылает нам тангенс угла разброса, однако возникает вопрос, как именно на сервере идет генерация разброса. В своё время Med443 показал (тыц, третий спойлер), что в танках сервер оперирует распределением Релея. Именно это распределение при генерации случайного радиуса R и угла его поворота А дает картинку разброса снарядов и их распределение как в игре. 

Edited by StranikS_Scan

Share this post


Link to post

Short link
Share on other sites
1 hour ago, StranikS_Scan said:

сложных матричных аналитических вычислений

Считается в 15 элементарных операций и 3 корня, и считается на сервере. Клиент отправляет только исходные данные

   static float intersectTime(Vector3 velosity, Vector3 start, Vector3 marker, float gravity)
   {
       Vector3 norm = marker - start;
       double C1 = norm.magnitude * norm.magnitude;
       double C2 = Vector3.Dot(norm, velosity);
       double C3 = norm.y * -gravity / 2.0;
     
       double time = (-C2 + System.Math.Sqrt(C2 * C2 + 4 * C1 * C3)) / (2.0 * C3);
       return (float)time;
   }

Ну а дальше по времени находилась точка на траектории трассера, что вообще легко
 

1 hour ago, StranikS_Scan said:

Трассер это примерная визуализация и рисуется он условно и часто приближенно

Если так, то согласен, трассёр использовать плохо.

 

1 hour ago, StranikS_Scan said:

точке попадания снаряда

часто не точны

Думаю можно считать, что для игрока точка попадания снаряда пришедшая с сервера, это и есть фактический "разброс" выстрела.

1 hour ago, StranikS_Scan said:

она предполагает, путем построения обратных траекторий,

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

 

Ближе к вечеру попробую сравнить разные способы. Из того что я тестил, и трассер даёт приемлемый результат (визуально)

 

Edited by SoprachevAK

Share this post


Link to post

Short link
Share on other sites
17 minutes ago, StranikS_Scan said:

показал (тыц, третий спойлер), что в танках сервер оперирует распределением Реле

Ну насколько я понял, он как раз показал, что сервер НЕ оперирует распределение Релея, в отличие от новости на портале. Тк распределение Релея = 0 в центре круга, а в танках оно нулю не равно, что видно из его же графика ниже.

Что неправильно, но "Зачем ломать то, что и так приносит неплохой доход"

Судя по моим данным, с 2015 года ничего так и не поменялось 

Edited by SoprachevAK

Share this post


Link to post

Short link
Share on other sites
1 hour ago, StranikS_Scan said:

Меня вообще больше интересует только та часть пайтон-кода, которая у тебя будет отвечать за математическую модель

Самое смешное в этой ситуации, что все расчёты вынесены на сервер. Мод всего лишь хукает и отправляет исходные данные

Я подумаю как можно открыть проект. Сейчас он состоит из 4х частей
1. Мод который просто получает и отправляет данные
2. C# веб сервер, задача которого получить данные от мода и положить их в бд, попутно досчитав недостающие значения. Его код писал не я, и лично мне крайне не нравится что там получилось, как по мне оверархитектура, разбитая ещё на 3 подпроекта, да ещё и с отсутствием стилистики, но человек хотел попробовать и грех отказываться от бесплатной рабочий силы
3. VueJS сайт
4. NodeJS кеш веб сервер, достаёт данные из бд, все графики считаются напрямую на бд, и этот веб сервер просто формирует SQL запрос и сохраняет его в кеш бд, а ещё занимается всякой дополнительной работой необходимой для обеспечения работы сайта
*5. Продет на Unity для визуализации записанной модом инфы, просто потому что самый простой 3д рендер. Вот например выстрел арты по записи трассера. 

И по хорошему для автономного существования и развития проекта надо публиковать всё, что весьма долго

image.png

Снимок экрана 2021-08-01 в 11.58.25.png

Edited by SoprachevAK

Share this post


Link to post

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...