Jump to content
Korean Random
SoprachevAK

[WOT STAT] Мод для анализа подкруток

Recommended Posts

1 hour ago, Slava7572 said:

ну я как бы выстрелы не чекаю,лично мне ясно,что клиент один для всех в этом плане.А вот альфа конкретно моего танка и сколько прилетает по мне,реальная средняя альфа(сколько не считал,всегда выходит примерно на 10% меньше заявленной),есть ли зависимость от сессий.

На том же Т-45 намеренно стал играть хуже(статистика меня мало интересует по акку) и уже в топ почаще попадать стал,совпадение?Не думаю:sceptic:

https://docs.google.com/spreadsheets/d/1iJBJfSvDoH47NWPHrO9iOiDHpBL8-jaoy7DfzifHfks/edit#gid=232571049

тут смотрел - альфа честная, распределение нормальное и нормальное :)

Share this post


Link to post

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

тут смотрел - альфа честная

не совсем,это выстрелы разных игроков,а пробовал с одного акка популять,я сколько не считал с завидной регулярностью получалось чуть ниже среднего,чаще всего от 5 до 10% разница в меньшую сторону.Не то чтоб это было критично,можно считать погрешностью,но почему всегда меньше?Ни одной сессии не было с альфой например 500 у того же скорпа,всегда 470-480,иногда даже меньше...на фраги,где добиваешь танк подобное не спишешь даже если представить чисто теоретически,что все добивающие выстрелы будут с максимальным уроном(612,5 у скорпа насколько я помню),их не так много этих фраговых выстрелов:sceptic:

  • Upvote 1

Share this post


Link to post

Short link
Share on other sites
49 минут назад, Slava7572 сказал:

одного акка популять

 

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

Share this post


Link to post

Short link
Share on other sites
45 минут назад, StranikS_Scan сказал:

Ты столько не напуляешь, чтоб выборка стала репрезентативной

т.е. с точки зрения программы этот генератор псевдослучайных чисел всегда работает по разному?А может там вообще не ГПСЧ:mellow:

Я правда слабо верю,что сервер прям каждого обсчитывает по своему(довольно распространенное мнение как оказалось),но какие то границы по группам статистики за крайние 100 боев например можно же задать?Особенно когда есть внутренний рейтинг и +-25%.

Share this post


Link to post

Short link
Share on other sites

Ну уж это 100% подкрутка

Причём лично мне)

https://wotstat.soprachev.com/analytics/613c3d975b256a0828485432

Почему у меня разброс меньше понятно (мне), а вот почему у Стервы меньше, чем у пары ТТ-10?

Upd.: Можно даже ещё веселее

https://wotstat.soprachev.com/analytics/613c53475b256a082849f625

123.jpg.4c66392a4fff2e0ed3d0c1891960ca05.jpg

Edited by KPOT2338
  • Upvote 1

Share this post


Link to post

Short link
Share on other sites
On 9/11/2021 at 8:29 AM, KPOT2338 said:

Ну уж это 100% подкрутка

Причём лично мне)

https://wotstat.soprachev.com/analytics/613c3d975b256a0828485432

Почему у меня разброс меньше понятно (мне), а вот почему у Стервы меньше, чем у пары ТТ-10?

Upd.: Можно даже ещё веселее

https://wotstat.soprachev.com/analytics/613c53475b256a082849f625

123.jpg.4c66392a4fff2e0ed3d0c1891960ca05.jpg

Реально необычно и вроде бы всё верно с точки зрения выборок
Такой разброс даже на распределение видно image.thumb.png.0e1c58912c247f719b75a60f260665be.png

Share this post


Link to post

Short link
Share on other sites

Кто нибудь знает какая примерно аудитория у танковых модов?
Хотя бы порядок, если договорюсь с модпакерами, то на какие числа рассчитывать. На WGMods не нашел каких либо показателей кроме количества скачиваний за всё время 

Share this post


Link to post

Short link
Share on other sites
14 minutes ago, KPOT2338 said:

Вопрос

При просмотре реплея выстрелы в базу не заносятся?

Нет

Сделано для защиты от дубликатов

Share this post


Link to post

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

Кто нибудь знает какая примерно аудитория у танковых модов?
Хотя бы порядок, если договорюсь с модпакерами, то на какие числа рассчитывать. На WGMods не нашел каких либо показателей кроме количества скачиваний за всё время 

https://wot-news.com/stat/server/ru/norm/ru

Share this post


Link to post

Short link
Share on other sites
56 минут назад, spoter сказал:

 

Это не моды жы.

 

------------------------

 

По модам, XVM раньше писал на сайте о кол-во активных юзверов (как реклама), последний раз когда видел лейбл, было вроде написано об 3+ млн, из них думаю не менее 50% ставят его через толстые модпаки, так что 1-1,5 млн активного онлайна точно юзают модпаки. 

 

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

Жовопак ~ 12 млн

Корбен ~ 0,5 млн

Юшапак - 11 + 19 +1 = 31 млн

Трамвай - 3,5 млн

Вспышка - 0,5 млн ... дальше мелочь.

Итого: ~47,5 млн, если добрать мелочь, то будет красивая цифра 50 млн.

 

Из этой цифры активноиграющие игорьки, это 10%, что получаем 5 млн. Что вроде бы говорит о том, что они могут юзать потенциально твой мод, если модпакеры решат его включить в свой паки.

 

Но есть один важный момент, который ломает эту картинку, это % игроков с запрещенными модами и паками. Из активного онлайна, кто рубится в тынки, 40-60% всегда играет с какой-то запрещенкой, большинство по мелочи, аля "мине нада тока тундру остальное фигня", а кто-то и по крупному с платными модпаками. Эти товарищи наоборот - будут избегать юзать твой мод, ибо он сливает инфу на твой сервер.

 

Что в сухом остатке, думаю , если (SoprachevAK) договоришься с @Yusha и мод будет в модпаке, то 5-10 тыс. онлайна вполне может появится и база начнет быстро расти.

Edited by StranikS_Scan
  • Upvote 1

Share this post


Link to post

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

то 5-10 тыс

Спасибо, примерно на такие нагрузи и буду рассчитывать. 

Share this post


Link to post

Short link
Share on other sites

Обновление темы.

Перенёс мод в новый репозиторий. Теперь абсолютно всё в опенсорс. Общая архитектура готова, остаётся дорабатывать и расширять. 

В связи с этим обращаюсь за помощью к опытным мододелам, добавьте какие нибудь события, которые однозначно знаете как сделать (если пулл реквестору сделать времени нет, можно просто сюда кодом). 

События которые можно добавить

  • @MoD, у тебя точно есть кусок для сбора урона, его можно прямо в OnShot 
  • Круто было бы добавить ещё приведённую броню в точке попадания, можно у тебя это тоже есть
  • Попадание по своему танку
  • Изменение ХП своего танка
  • Декодировать больше результатов боя, чем есть сейчас
  • Выбор динамического снаряжения
  • Засвет
  • Ассист
  • Танкование
  • Фраг
  • Смерть

 

Ещё есть идеологический вопрос типа возможно ли вообще
Боты умели стрелять, а значит была возможность как то это находить прострелы, кроме как рейкастом у центру танка. И как следствие вопрос, можно ли в момент выстрела кидать рейкасты по траектории дуги (арта умеет определять есть ли прострел по дуге), сеткой внутри сведения. В результате получится картинка например 32x32 пикселя, где каждый пиксель будет отвечать за количество приведённой брони в этом месте (если рельеф то броня -1). Если сделать такой рейкаст "размазанным по времени" -- разбить на секции и проверять согласно скорости полёта снаряда, то можно будет понять "притягиваются" ли снаряды к танкам. Потому что ощущение подкрутки возникает не когда снаряд летит в центр, а когда снаряд без сведения летит по противнику в место где можно пробить. 

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

 

Можно ли как то добавить вкладку в результат боя с браузером? Или там сейчас с браузером какие то проблемы в танках

Edited by SoprachevAK

Share this post


Link to post

Short link
Share on other sites

И есть ещё вопрос, кто нибудь работал с WG API, там есть автономные приложения (которые напрямую обращаются к серверам WG), и есть application_id, который нельзя компрометировать, но при этом надо указывать в url запроса
Как у них это сочетается и что делать?

На форуме вг ничего не ответили
(url запросов легко перехватываются и значит их содержание компрометируется)

Share this post


Link to post

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

И есть ещё вопрос, кто нибудь работал с WG API, там есть автономные приложения (которые напрямую обращаются к серверам WG), и есть application_id, который нельзя компрометировать, но при этом надо указывать в url запроса
Как у них это сочетается и что делать?

На форуме вг ничего не ответили
(url запросов легко перехватываются и значит их содержание компрометируется)

 

Там всё через токены application_id, разница только в ограничениях. Автономные приложения могут слать запросы с любых айпи, ибо будут запускаться разными юзверами. А серверное только с фиксированных, заранее перечисленных в кабинете, айпи. И для серверного токена больше лимит по запросам в секунду (вроде). Про компрометацию, это я не понял о чем ты. Если про перехват, то API - публичный, какие вопросы перехвата тут могут быть?

Edited by StranikS_Scan

Share this post


Link to post

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

И есть ещё вопрос, кто нибудь работал с WG API, там есть автономные приложения (которые напрямую обращаются к серверам WG), и есть application_id, который нельзя компрометировать, но при этом надо указывать в url запроса
Как у них это сочетается и что делать?

На форуме вг ничего не ответили
(url запросов легко перехватываются и значит их содержание компрометируется)

Там есть два вида токенов. Для клиентских приложений (Standalone applications) и для серверных (Server applications).

 

Если запросы шлются с твоего сервера, то скрыть application_id можно без проблем.

 

Если у тебя запрос делают сами клиенты, и поэтому видят application_id, то тебе нужно получать токен для Standalone application. Его можно светить, это же клиентское приложение, никак иначе его не сделаешь. А вот если бы ты делал серверное приложение, то его токен компрометировать нельзя.

 

Edited by yepev
  • Upvote 1

Share this post


Link to post

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

Боты умели стрелять, а значит была возможность как то это находить прострелы, кроме как рейкастом у центру танка. И как следствие вопрос, можно ли в момент выстрела кидать рейкасты по траектории дуги (арта умеет определять есть ли прострел по дуге), сеткой внутри сведения. В результате получится картинка например 32x32 пикселя, где каждый пиксель будет отвечать за количество приведённой брони в этом месте (если рельеф то броня -1). Если сделать такой рейкаст "размазанным по времени" -- разбить на секции и проверять согласно скорости полёта снаряда, то можно будет понять "притягиваются" ли снаряды к танкам. Потому что ощущение подкрутки возникает не когда снаряд летит в центр, а когда снаряд без сведения летит по противнику в место где можно пробить. 

 

Не знаю, что такое рейкаст. В танках оценка столкновений идет путем вызова функции расчета столкновения, они разные есть. Есть для ландшафта BigWorld.wg_collideSegment, а есть и для моделей танков BigWorld.wg_collideDynamic или обе сразу BigWorld.wg_collideDynamicStatic. Ниже под спойлерами некоторая инфа по этому поводу, которую я собирал раньше. Она будет полезна при реализации.

 

 
Новая логика 1.2.0
============================================================================

БАЗОВЫЕ ФУНКЦИИ:

BigWorld.wg_simulateProjectileTrajectory(r0, v0, g0, SERVER_TICK_LENGTH, SHELL_TRAJECTORY_EPSILON_CLIENT, 128)
-> (0.10825327783823013 время полёта, (29.4889, 6.65568, -380.688) точка попадания, (-236.108, -25.4297, -805.754) конечная скорость) или None

BigWorld.wg_collideSegment(BigWorld.player().spaceID, start, end, 128, 8)
0,   0   - любые
0,   128 - только хрупкие
128, 0   - без хрупких
8,   0   - без террейна
0,   8   - только террейн
Первый флаг исключающий, второй флаг обязывающий

Результат: PyCollideSegment(closestPoint, isTerrain(), matKind, normal)
           ((86.1162, 11.1196, -215.831), False, 111, (-0.702107, 0.624444, 0.342221))
closestPoint - точка столкновения, isTerrain() - это земля, а не объект на ней, normal - вектор нормали в точке столкновения
    
BigWorld.wg_collideDynamic(BigWorld.player().spaceID, startPoint, endPoint, ignoreID, -1 if skipGun else TankPartNames.getIdx(TankPartNames.GUN)) - проверяем танки, игнорируя танк в ignoreID (или 0)
-> точка столкновения, вида (distance, hitPoint, если ==3, то это танк, vehicleID (если это танк), partIndex, matKind)
(0.19484993815422058, (-0.759788, -0.0839233, -0.644732), 3, 1117367, 2, 25) или None

BigWorld.wg_collideDynamicStatic(BigWorld.player().spaceID, startPoint, endPoint, collisionFlags, ignoreDynamicID, -1 if skipGun else TankPartNames.getIdx(TankPartNames.GUN)) - проверяем танки и землю, игнорируя ignoreDynamicID (или 0)
-> точка столкновения, вида (hitPoint, isVehicle, entityID, partIndex, matKind)
((-196.565, 6.95257, -316.327), True, 1117352, 3, 1) или ((-196.565, 6.95257, -316.327), False, -1, -1, 111)

---

entity.appearance.collisions.collideAllWorld(start, end) - проверяет все детали машины, используя глобальные координаты
-> массив точек вида (distance, hitsAngleCos, matKind, partIndex)
((14.677664756774902, 0.5502769351005554, 24, 0), (15.51591682434082, 0.5425591468811035, 24, 0))

  entity.appearance.collisions.collideLocal(compIdx, startPoint, endPoint) - тоже самое но в локальных координатах для одной части танка
  compIdx номер части в TankPartIndexes

  entity.appearance.collisions.collideWorld(compIdx, startPoint, endPoint) - тоже самое но в глобальных координатах для одной части танка
  compIdx номер части в TankPartIndexes


Обвязка от ВГ:

Результат: либо None либо (hitPoint, None) либо (hitPoint, ECD) где ECD.hitAngleCos=0.0, либо ECD.isVehicle()=False и ECD.entity=None, либо есть ECD.armor
def collideDynamicAndStatic(startPoint, endPoint, exceptIDs, collisionFlags=128, skipGun=False):
    ignoreDynamicID = 0
    if exceptIDs:
        ignoreDynamicID = exceptIDs[0]
    testRes = BigWorld.wg_collideDynamicStatic(BigWorld.player().spaceID, startPoint, endPoint, collisionFlags, ignoreDynamicID, skipGun)
    if testRes is not None:
        if testRes[1]:
            return (testRes[0], EntityCollisionData(testRes[2], testRes[3], testRes[4], True))
        return (testRes[0], None)
    else:
        return

Результат: либо None либо (hitPoint, None) либо (hitPoint, ECD) где ECD.hitAngleCos=0.0, либо ECD.isVehicle()=False и ECD.entity=None, либо есть ECD.armor
def collideDynamic(startPoint, endPoint, exceptIDs, skipGun=False):
    ignoreID = 0
    if exceptIDs:
        ignoreID = exceptIDs[0]
    res = BigWorld.wg_collideDynamic(BigWorld.player().spaceID, startPoint, endPoint, ignoreID, -1 if skipGun else TankPartNames.getIdx(TankPartNames.GUN))
    if res is not None:
        res = (res[0], EntityCollisionData(res[3], res[4], res[5], res[2] == 0))
    return res

class EntityCollisionData(object):
    __slots__ = ('hitAngleCos', 'armor', '__isVehicle', 'entity')

    def __init__(self, entityID, partIndex, matKind, isVehicle=True):
        self.hitAngleCos = 0.0
        self.__isVehicle = isVehicle
        if isVehicle:
            self.entity = BigWorld.entity(entityID)
            matInfo = self.entity.getMatinfo(partIndex, matKind)
            self.armor = matInfo.armor if matInfo is not None else 0.0
        else:
            self.entity = None
        return

    def isVehicle(self):
        return self.__isVehicle

def collideSegmentExt(self, startPoint, endPoint):
    if self.appearance.collisions is not None:
        collisions = self.appearance.collisions.collideAllWorld(startPoint, endPoint)
        if collisions:
            res = []
            for collision in collisions:
                matInfo = self.getMatinfo(collision[3], collision[2])
                res.append(SegmentCollisionResultExt(collision[0], collision[1], matInfo, collision[3]))

            return res

SegmentCollisionResultExt = namedtuple('SegmentCollisionResultExt', ('dist', 'hitAngleCos', 'matInfo', 'compName'))

def getMatinfo(self, parIndex, matKind):
    matInfo = None
    if parIndex == TankPartIndexes.CHASSIS:
        matInfo = self.typeDescriptor.chassis.materials.get(matKind)
    elif parIndex == TankPartIndexes.HULL:
        matInfo = self.typeDescriptor.hull.materials.get(matKind)
    elif parIndex == TankPartIndexes.TURRET:
        matInfo = self.typeDescriptor.turret.materials.get(matKind)
    elif parIndex == TankPartIndexes.GUN:
        matInfo = self.typeDescriptor.gun.materials.get(matKind)
    return matInfo

 

 

 
Добавлено в 1.3
============================================================================

def getShotTargetInfo(vehicle, preferredTargetPoint, gunRotator):
    shotPos, shotVec, gravity = gunRotator.getShotParams(preferredTargetPoint, True)
    minBounds, maxBounds = BigWorld.player().arena.getArenaBB()
    endPos, direction, _, _ = getCappedShotTargetInfos(shotPos, shotVec, gravity, vehicle.typeDescriptor.shot, vehicle.id, minBounds, maxBounds, CollisionStrategy.COLLIDE_VEHICLES_AND_STATIC_SCENE)
    return (endPos, direction)

#Возвращает collData=(id=1293187, partIndex=2, matKind=3, isVehicle=True) or 0; usedMaxDistance = bool
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)

def collideDynamicAndStatic(startPoint, endPoint, exceptIDs, collisionFlags=128, skipGun=False):
    ignoreDynamicID = 0
    if exceptIDs:
        ignoreDynamicID = exceptIDs[0]
    testRes = BigWorld.wg_collideDynamicStatic(BigWorld.player().spaceID, startPoint, endPoint, collisionFlags, ignoreDynamicID, -1 if skipGun else TankPartNames.getIdx(TankPartNames.GUN))
    if testRes is not None:
        if testRes[1]:
            return (testRes[0], EntityCollisionData(testRes[2], testRes[3], testRes[4], True))
        return (testRes[0], None)
    else:
        return

def collideVehiclesAndStaticScene(startPoint, endPoint, vehicles, collisionFlags=128, skipGun=False):
    testResStatic = BigWorld.wg_collideSegment(BigWorld.player().spaceID, startPoint, endPoint, collisionFlags)
    testResDynamic = collideDynamic(startPoint, endPoint if testResStatic is None else testResStatic.closestPoint, vehicles, skipGun)
    if testResStatic is None and testResDynamic is None:
        return
    else:
        distDynamic = 1000000.0
        if testResDynamic is not None:
            distDynamic = testResDynamic[0]
        distStatic = 1000000.0
        if testResStatic is not None:
            distStatic = (testResStatic.closestPoint - startPoint).length
        return (startPoint + (endPoint - startPoint) * distDynamic, testResDynamic[1]) if distDynamic <= distStatic else (testResStatic.closestPoint, None)

def collideDynamic(startPoint, endPoint, exceptIDs, skipGun=False):
    ignoreID = 0
    if exceptIDs:
        ignoreID = exceptIDs[0]
    res = BigWorld.wg_collideDynamic(BigWorld.player().spaceID, startPoint, endPoint, ignoreID, -1 if skipGun else TankPartNames.getIdx(TankPartNames.GUN))
    if res is not None:
        isVehicle = res[2] == ColliderTypes.VEHICLE_COLLIDER
        res = (res[0], EntityCollisionData(res[3], res[4], res[5], isVehicle))
    return res

 

 

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

 

У коллайдов есть два минуса - если их много и часто вызывать, то жрут время, игра может тормозить. Ну и их нельзя вызывать в потоках. Клиент крашится.

Edited by StranikS_Scan
  • Upvote 1

Share this post


Link to post

Short link
Share on other sites
6 hours ago, yepev said:

Его можно светить

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

Quote

На основании application_id, указанного в запросе, происходит идентификация приложения, а также выделяется определённая квота на количество выполняемых запросов.

Будьте внимательны при использовании application_id и убедитесь, что ваш ключ не стал известен третьим лицам.

И тут не указано что это только для серверных.


Я по этому и спросил, потому что "клиентские приложения" и "ключ не стал известен третьим лицам" вообще несовместимые понятия.

Будем считать, что это просто косяк доки, и максимум что сможет сделать скомпрометированный клиентский ключ, это получить таймаут на отдельный ip

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.

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   1 member

×
×
  • Create New...