Jump to content
Korean Random
ProstoNoob

PNShared - отображение противник без засвета

Recommended Posts

Мои исходники. Необходимо запустить server_ в PjOrion или на сервере и в mod_ заменить IP на localhost если на вашей машине или на IP-сервера

 

 

# -*- coding: utf-8 -*-


import ast
import zlib
import binascii
import cPickle

import time
import random
import marshal
import traceback
import functools
import threading

import socket
import urllib2


class server_PNShared(object):

__autor__ = 'ProstoNoob'
__build__ = '00.0000.00 Beta'

__startedConnect__ = ('0.0.0.0', 10100)
__tracingConnect__ = ('0.0.0.0', 10200)
__receiptConnect__ = ('0.0.0.0', 10300)

def threadDecorate(object):
 
  def decorate(*args, **kwargs):
  
   th = threading.Thread(target=object, args=args, kwargs=kwargs)
   th.setName = object.func_name
   th.setDaemon = True
   th.start()
  
  return decorate
 
def __init__(self):
 
  self.arenaUniqueID = dict()
  self.addressConnected = dict()
 
  self.startedFunction()
  self.tracingFunction()
  self.receiptFunction()
 
  self.handlerFunction()
 
def encodedFunction(self, *args):
 
  if args[0] == 'zlib':
   return zlib.compress(str(args[1]))
  elif args[0] == 'binascii':
   return binascii.hexlify(str(args[1]))
  elif args[0] == 'cPickle':
   return cPickle.dumps(args[1], 1)
  
def decodedFunction(self, *args):
      
  if args[0] == 'zlib':
   return zlib.decompress(args[1])
  elif args[0] == 'literal':
   return ast.literal_eval(args[1])
  elif args[0] == 'cPickle':
   return cPickle.loads(args[1])
  elif args[0] == 'binascii':
   return binascii.unhexlify(args[1])
 
@threadDecorate
def handlerFunction(self):

  while True:
   keyboardCommand = raw_input('>>> ')
  
   try:
    if keyboardCommand == 'cmd stop_server':
     del self.startedSocket
     del self.tracingSocket
     del self.receiptSocket
    
    elif keyboardCommand == 'cmd start_server':
     self.startedFunction()
     self.tracingFunction()
     self.receiptFunction()
   
    else:
     exec keyboardCommand
   
   except Exception, error:
    print traceback.print_exc()

@threadDecorate
def startedFunction(self):
 
 
  if not getattr(self, 'startedSocket', None):
   self.startedSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.startedSocket.bind(self.__startedConnect__)
  
   print [traceback.extract_stack(None, 2)[1][2]], 'start while'
  
   try:
    while getattr(self, 'startedSocket', None):
     recive, address = self.startedSocket.recvfrom(1024)
     print recive[:1], recive[1:]
     if recive[1:] not in self.arenaUniqueID:
      self.arenaUniqueID.update({recive[1:]: {
     
       0: {'ready': list(), 'shared': 0}, 1: {'ready': list(), 'shared': 0}}})
     
     if address[0] not in self.arenaUniqueID[recive[1:]][int(recive[:1])]['ready']:
      self.arenaUniqueID[recive[1:]][int(recive[:1])]['ready'].append(address[0])
      
     if address[0] not in self.addressConnected:
      self.addressConnected.update({address[0]: recive[1:]})
     
     self.startedSocket.sendto(
      str(len(self.arenaUniqueID[recive[1:]][not int(recive[:1])]['ready'])), address)
     
   except Exception as error:
    if not isinstance(error, socket.timeout):
     print traceback.print_exc()
     
   finally:
    print [traceback.extract_stack(None, 2)[1][2]], 'stopped'
  
@threadDecorate
def tracingFunction(self):
   
  if not getattr(self, 'tracingSocket', None):
   self.tracingSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.tracingSocket.bind(self.__tracingConnect__)
  
   print [traceback.extract_stack(None, 2)[1][2]], 'start while'
  
   try:
    while getattr(self, 'tracingSocket', None):
     recive, address = self.tracingSocket.recvfrom(2048)
    
     addressConnected = self.addressConnected[address[0]]
     self.arenaUniqueID[addressConnected][int(recive[:1])].update({'shared': recive[1:]})
   
   except Exception as error:
    if not isinstance(error, socket.timeout):
     print traceback.print_exc()
   
   finally:
    print [traceback.extract_stack(None, 2)[1][2]], 'stopped'
  
@threadDecorate
def receiptFunction(self):
 
  if not getattr(self, 'receiptSocket', None):
   self.receiptSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.receiptSocket.bind(self.__receiptConnect__)

   print [traceback.extract_stack(None, 2)[1][2]], 'start while'

   try:
    while getattr(self, 'receiptSocket', None):
     recive, address = self.receiptSocket.recvfrom(1024)
    
     addressConnected = self.addressConnected[address[0]]
     arenaUniqueID = self.arenaUniqueID[addressConnected][not int(recive[:1])]['shared']
    
     if arenaUniqueID:
      self.receiptSocket.sendto(arenaUniqueID, address)
   
   except Exception as error:
    if not isinstance(error, socket.timeout):
     print traceback.print_exc()
   
   finally:
    print [traceback.extract_stack(None, 2)[1][2]], 'stopped'


PNShared = server_PNShared()
# -*- coding: utf-8 -*-


import ast
import zlib
import binascii
import cPickle

import time
import random
import marshal
import traceback
import functools
import threading

import socket
import urllib2

import Math
import helpers
import BigWorld

from Avatar import PlayerAvatar

from Vehicle import Vehicle
from Account import PlayerAccount

from AvatarInputHandler import mathUtils
from ConnectionManager import connectionManager

from PlayerEvents import g_playerEvents
from BattleReplay import g_replayCtrl

from gui.app_loader import g_appLoader
from gui.battle_control import g_sessionProvider


class mod_PNShared(object):

__autor__ = 'ProstoNoob'
__build__ = '00.0000.00 Beta'

def __init__(self, *args):
 
  self.clientLanguage = helpers.getClientLanguage()
  self.clientPatchVersion = helpers.getFullClientVersion()
 
  self.__addrr__ = args[0]
 
  def add_playerEvents_onAvatarReady(*args, **kwargs):
 
   pass
 
  def add_playerEvents_onArenaPeriodChange(*args, **kwargs):
  
   if args[0] == 2:
  
    self.context = g_sessionProvider.getCtx()
    self.arenaDatabase = g_sessionProvider.getArenaDP()
    self.battle = g_appLoader.getDefBattleApp()
   
    self.player = BigWorld.player()
   
    self.playerTeam = self.player.team
    self.arenaBattle = self.player.arena
    self.vehicleID = self.player.playerVehicleID
    self.arenaUniqueID = self.player.arenaUniqueID
    self.arenaFormatBattle = self.player.arena.guiType
    self.arenaVehicles = self.player.arena.vehicles
   
    self.clientVehicle = dict()
    self.modelsVehicle = dict()

    self.serverTeam = self.playerTeam - 1
   
    for vehicleID, vehicleDescriptor in self.arenaVehicles.items():
     if vehicleDescriptor['isAlive']:
      if vehicleDescriptor['team'] != self.playerTeam:
       descriptorType = vehicleDescriptor['vehicleType']
       self.modelsVehicle.update({
        vehicleID: {
         'chassis': {
          'servo': Math.Matrix(),
          'descr': descriptorType.chassis['hullPosition'],
          'model': BigWorld.Model(descriptorType.chassis['models']['undamaged'])
         },
         'hull': {
          'servo': Math.Matrix(),
          'descr': descriptorType.hull['turretPositions'][0],
          'model': BigWorld.Model(descriptorType.hull['models']['undamaged'])
         },
         'turret': {
          'servo': Math.Matrix(),
          'descr': descriptorType.turret['gunPosition'],
          'model': BigWorld.Model(descriptorType.turret['models']['undamaged'])
         },
         'gun': {
          'servo': Math.Matrix(),
          'model': BigWorld.Model(descriptorType.gun['models']['undamaged'])
         }
        }})
   
    self.battleMinimap = self.battle.minimap
    self.battleMarkerManager = self.battle.markersManager

   if args[0] in [2, 3]:
    self.startedFunction()
   
  def new_ConnectionManager_serverResponseHandler(*args, **kwargs):
   pre_ConnectionManager_serverResponseHandler(*args, **kwargs)

   if args[0] == 1 and args[1] == 'LOGGED_ON':
    self.userDatabaseID = self.decodedFunction('literal', args[2])['token2'].split(':')[0]
  
  pre_ConnectionManager_serverResponseHandler = connectionManager._ConnectionManager__serverResponseHandler
  connectionManager._ConnectionManager__serverResponseHandler = new_ConnectionManager_serverResponseHandler
 
  def new_PlayerAvatar_onEnterWorld(cls, *args, **kwargs):
   pre_PlayerAvatar_onEnterWorld(cls, *args, **kwargs)
  
  pre_PlayerAvatar_onEnterWorld = PlayerAvatar.onEnterWorld
  PlayerAvatar.onEnterWorld = new_PlayerAvatar_onEnterWorld

  def new_PlayerAvatar_onLeaveWorld(cls, *args, **kwargs):
   pre_PlayerAvatar_onLeaveWorld(cls, *args, **kwargs)
  
  pre_PlayerAvatar_onLeaveWorld = PlayerAvatar.onLeaveWorld
  PlayerAvatar.onLeaveWorld = new_PlayerAvatar_onLeaveWorld
 
  def new_PlayerAccount_onBecomePlayer(cls, *args, **kwargs):
   pre_PlayerAccount_onBecomePlayer(cls, *args, **kwargs)
  
  pre_PlayerAccount_onBecomePlayer = PlayerAccount.onBecomePlayer
  PlayerAccount.onBecomePlayer = new_PlayerAccount_onBecomePlayer
 
  g_playerEvents.onAvatarReady += add_playerEvents_onAvatarReady
  g_playerEvents.onArenaPeriodChange += add_playerEvents_onArenaPeriodChange
  
def threadDecorate(object):
 
  def decorate(*args, **kwargs):
  
   th = threading.Thread(target=object, args=args, kwargs=kwargs)
   th.setName = object.func_name
   th.setDaemon = True
   th.start()
  
  return decorate
  
def encodedFunction(self, *args):
 
  if args[0] == 'zlib':
   return zlib.compress(str(args[1]))
  elif args[0] == 'binascii':
   return binascii.hexlify(str(args[1]))
  elif args[0] == 'cPickle':
   return cPickle.dumps(args[1], 1)
  
def decodedFunction(self, *args):
 
  if args[0] == 'zlib':
   return zlib.decompress(args[1])
  elif args[0] == 'literal':
   return ast.literal_eval(args[1])
  elif args[0] == 'cPickle':
   return cPickle.loads(args[1])
  elif args[0] == 'binascii':
   return binascii.unhexlify(args[1])

def mappingFunction(self, *args):

  matrixTranslate = Math.Matrix()
  matrixTranslate.setTranslate((0, 0, 0))
 
  markerScaleSize = self.battleMinimap._Minimap__markerScale
 
  coordinateMatrix = Math.Matrix()
  coordinateMatrix.setTranslate(Math.Matrix(matrixTranslate).applyPoint(args[0]))
 
  if not markerScaleSize:
   return coordinateMatrix
 
  else:
   scaleMatrix = Math.Matrix()
   scaleMatrix.setScale(Math.Vector3(markerScaleSize, markerScaleSize, markerScaleSize))
   
   return mathUtils.MatrixProviders.product(scaleMatrix, coordinateMatrix)

def textureFunction(self, *args):

  ModelA = Math.Matrix()
  ModelB = Math.Matrix()
  ModelB.setRotateY(args[1][0])
  ModelA.preMultiply(ModelB)
 
  ModelB = Math.Matrix()
  ModelB.setRotateX(args[1][1])
  ModelA.preMultiply(ModelB)
 
  ModelB = Math.Matrix()
  ModelB.setRotateZ(args[1][2])
  ModelA.preMultiply(ModelB)
  ModelA.translation = args[2]
 
  ModelC = Math.Matrix()
  ModelC.setTranslate(Math.Vector3(0, 0, 0))
  ModelA.preMultiply(ModelC)
 
  args[0]['chassis']['servo'].setIdentity()
  args[0]['chassis']['servo'].preMultiply(ModelA)
 
  ModelC = Math.Matrix()
  ModelC.translation = args[0]['chassis']['descr']
 
  ModelD = Math.Matrix(ModelA)
  ModelD.preMultiply(ModelC)
 
  args[0]['hull']['servo'].setIdentity()
  args[0]['hull']['servo'].preMultiply(ModelD)
 
  ModelC = Math.Matrix()
  ModelC.setRotateY(args[1][6])
  ModelC.translation = args[0]['hull']['descr']
 
  ModelE = Math.Matrix(ModelD)
  ModelE.preMultiply(ModelC)
 
  args[0]['turret']['servo'].setIdentity()
  args[0]['turret']['servo'].preMultiply(ModelE)
 
  ModelC = Math.Matrix()
  ModelC.setRotateX(args[1][7])
  ModelC.translation = args[0]['turret']['descr']
 
  ModelF = Math.Matrix(ModelE)
  ModelF.preMultiply(ModelC)
 
  args[0]['gun']['servo'].setIdentity()
  args[0]['gun']['servo'].preMultiply(ModelF)
 
@threadDecorate
def startedFunction(self):

  if not getattr(self, 'startedSocket', None):
   self.startedSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.startedSocket.settimeout(1.5)
  
   try:
    self.startedSocket.sendto(
     str(self.serverTeam) + str(self.arenaUniqueID), (self.__addrr__, 10100))
   
    if self.arenaBattle.period == 3:
     recive, address = self.startedSocket.recvfrom(1024)
     startedDecode = int(recive)
   
     if startedDecode:
      self.tracingFunction()
      self.receiptFunction()
      self.processFunction()
     
   except Exception as error:
    if not isinstance(error, socket.timeout):
     print traceback.print_exc()
    
   finally:
    self.startedSocket = self.startedSocket.close()

  if self.arenaBattle.period == 3:
   if not locals().get('startedDecode'):
    if getattr(self.player, 'isOnArena', None):
     loadingPlayer = 0
   
     for vehicleID, vehicleDescriptor in self.arenaVehicles.items():
      if vehicleDescriptor['team'] is not self.playerTeam:
       loadingPlayer -= 1
       if vehicleDescriptor['isAvatarReady']:
        loadingPlayer += 1
    
     if loadingPlayer:
      BigWorld.callback(0.1,
       functools.partial(self.startedFunction))
 
@threadDecorate
def tracingFunction(self):

  if not getattr(self, 'tracingSocket', None):
   self.tracingSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.tracingSocket.settimeout(1.5)

   while getattr(self.player, 'isOnArena', None):
    try:
     clientVehicle = list()
 
     for vehicleID, vehicleDescriptor in BigWorld.entities.items():
      if isinstance(vehicleDescriptor, Vehicle) and getattr(vehicleDescriptor, 'publicInfo', None):
       if vehicleDescriptor.publicInfo.team == self.playerTeam:
        if vehicleDescriptor.isAlive():
         coordinateVehicle = vehicleDescriptor.position
         clientVehicle.append((
          vehicleID, (
           vehicleDescriptor.yaw,
           vehicleDescriptor.pitch,
           vehicleDescriptor.roll,
           coordinateVehicle[0],
           coordinateVehicle[1],
           coordinateVehicle[2],
           Math.Matrix(vehicleDescriptor.appearance.turretMatrix).yaw,
           Math.Matrix(vehicleDescriptor.appearance.gunMatrix).pitch
         )))
       
     if clientVehicle:
      self.tracingSocket.sendto(str(self.serverTeam) + self.encodedFunction(
       'zlib', self.encodedFunction('cPickle', clientVehicle)), (self.__addrr__, 10200))
      
    except Exception as error:
     if not isinstance(error, socket.timeout):
      print traceback.print_exc()
      
    finally:
     pass #time.sleep(0.05)
    
   else:
    self.tracingSocket = self.tracingSocket.close()
  
@threadDecorate
def receiptFunction(self):

  if not getattr(self, 'receiptSocket', None):
   self.receiptSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   self.receiptSocket.settimeout(1.5)
  
   while getattr(self.player, 'isOnArena', None):
    try:
     self.receiptSocket.sendto(str(self.serverTeam), (self.__addrr__, 10300))
    
     recive, address = self.receiptSocket.recvfrom(2048)
     decodedRecive = self.decodedFunction('cPickle', self.decodedFunction('zlib', recive))
    
     for vehicleID, vehicleDescriptor in decodedRecive:
      coordinateVehicle = Math.Vector3(vehicleDescriptor[3:6])
     
      clientVehicle = self.clientVehicle.get(vehicleID)
      modelsVehicle = self.modelsVehicle.get(vehicleID)
     
      if clientVehicle:
       self.textureFunction(modelsVehicle, vehicleDescriptor, coordinateVehicle)
      
       if clientVehicle['coordinateVehicle'] != coordinateVehicle:
        mappingFunction = self.mappingFunction(coordinateVehicle)
       
        self.battleMinimap._Minimap__ownUI.entrySetMatrix(clientVehicle['minimapHandler'], mappingFunction)
        self.clientVehicle[vehicleID].update({'coordinateVehicle': coordinateVehicle})
       
      else:
       if not BigWorld.entities.get(vehicleID):
        if not self.arenaBattle.positions.get(vehicleID):
       
         for vehicleModel, modelsDescriptor in modelsVehicle.items():
          self.player.addModel(modelsDescriptor['model'])
         
          modelsDescriptor['model'].visible = True
          modelsDescriptor['model'].addMotor(BigWorld.Servo(modelsDescriptor['servo']))
         
         vehicleInfo = self.arenaDatabase.getVehicleInfo(vehicleID).vehicleType
         minimapHandler = self.battleMinimap._Minimap__ownUI.addEntry(self.mappingFunction(coordinateVehicle), vehicleID)
        
         self.battleMinimap._Minimap__ownUI.entryInvoke(minimapHandler,
          ('init', ['enemy', 'enemy', vehicleInfo.classTag, '', vehicleInfo.shortNameWithPrefix]))
        
         self.clientVehicle.update(
          {vehicleID: {'minimapHandler': minimapHandler, 'coordinateVehicle': coordinateVehicle}})
        
    except Exception as error:
     if not isinstance(error, socket.timeout):
      print traceback.print_exc()
   
    finally:
     pass #time.sleep(0.05)
    
   else:
    self.tracingSocket = self.tracingSocket.close()
  
@threadDecorate
def processFunction(self):
 
  while getattr(self.player, 'isOnArena', None):
   try:
    if self.clientVehicle:
   
     for vehicleID, vehicleDescriptor in self.clientVehicle.items():
      if BigWorld.entities.get(vehicleID) or self.arenaBattle.positions.get(vehicleID):
     
       self.battleMinimap._Minimap__ownUI.delEntry(vehicleDescriptor['minimapHandler'])
      
       for vehicleModel, modelsDescriptor in self.modelsVehicle[vehicleID].items():
        self.player.delModel(modelsDescriptor['model'])
      
       del self.clientVehicle[vehicleID]
  
   except Exception as error:
    if not isinstance(error, socket.timeout):
     print traceback.print_exc()
  
   finally:
    pass #time.sleep(0.05)
   
  else:
   self.processWhile = False


#if not g_replayCtrl.isPlaying:
PNShared = mod_PNShared('194.58.102.180')

mod_PNShared.zip

Edited by ProstoNoob
  • Upvote 7
  • Downvote 7

Share this post


Link to post

Short link
Share on other sites

Запускаем PjOrion

Копируем туда скрипт server_

Запускаем без игры

 

Заходим в mod_

Прописываем в самом низу вместо IP = localhost

Компилируем

Устанавливаем в игру

 

Запускаем два клиента и играем в разных командах или в тренировочной комнате

 

 

 

Если играть с другим игроком у себя в mod_ прописываем localhost у товарищей свой IP

Edited by ProstoNoob
  • Upvote 3
  • Downvote 8

Share this post


Link to post

Short link
Share on other sites

Запускаем без игры - как запустить без игры

 Компилируем - как скопелировать

Устанавливаем в игру - как???

 

А Вы не могли бы все это автоматизировать,

Спасибо

  • Downvote 2

Share this post


Link to post

Short link
Share on other sites

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

  • Upvote 1
  • Downvote 8

Share this post


Link to post

Short link
Share on other sites

Нормуль, нормуль, одназначно +

271791699_w640_h2048_like.png?PIMAGE_ID=
<сарказм> Осталось запихать во все модпаки, и настроить на отображение без засвета лишь арты (ну и статистов), в какой нибудь известный и широко распространённый мод + прикрутить P2P хыыы</сарказм>

'показать'

например в XVM :D
Edited by Suffering
  • Upvote 2
  • Downvote 2

Share this post


Link to post

Short link
Share on other sites

ох админу не понравится такая тема

  • Upvote 1
  • Downvote 1

Share this post


Link to post

Short link
Share on other sites

ох админу не понравится такая тема

Да, действительно, данный форум не на тематику читов. Можно тогда c товарищам с unknown cheats me поделиться информацией, они то уж точно знают толк в обратной разработке и написании читов ^_^

Edited by Suffering
  • Downvote 4

Share this post


Link to post

Short link
Share on other sites

лучше быстрее удалить эту тему, автор и так себе могилу вырыл

  • Upvote 2
  • Downvote 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
автор и так себе могилу вырыл

интересно что же он такого сделал, что уж прям могилу.

 

я УВЕРЕН, что сейчас у каждого второго алёши, (а у "стотиста" подавно, уж мы то знаем, как в топывых кланах сами командиры на ГК миникарту читерскую катают) пачка читомодпаков установлена. Принцип не говори - никто и не узнает. Вот так-с. А пока сами КВГ будут отрицать наличие читов в их игре, так и будет продолжаться

Edited by Suffering
  • Upvote 1
  • Downvote 5

Share this post


Link to post

Short link
Share on other sites

А пока сами КВГ будут отрицать наличие читов в их игре, так и будет продолжаться

и пускай темка повесит в свободном доступе, чтоб уже наверное. Здесь и пара разрабов от ВГ появляются..

А публикация не противоречит правилам форума.

Share this post


Link to post

Short link
Share on other sites
Здесь и пара разрабов от ВГ появляются..

толку от них? ни разу не одного не видел, наверно фаза луны была не та

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

Господа минусящие, вы хоть говорите с чем не согласны, а то молчком прошли - тыкнули и дальше пошли.

Edited by Suffering
  • Upvote 4
  • Downvote 3

Share this post


Link to post

Short link
Share on other sites

толку от них? ни разу не одного не видел, наверно фаза луны была не та

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

Господа минусящие, вы хоть говорите с чем не согласны, а то молчком прошли - тыкнули и дальше пошли.

Можешь подробно описать как это всё работает? Ничего не понятно и складывается ощущение что всё это херня которая не работает, но я более чем уверен что делаю что то не так

Share this post


Link to post

Short link
Share on other sites

Можешь подробно описать как это всё работает? Ничего не понятно и складывается ощущение что всё это херня которая не работает, но я более чем уверен что делаю что то не так

 

Да, ни как это не работает. Забей.

Share this post


Link to post

Short link
Share on other sites

В шапке два кода , второй как пример с изменённым ИП ?

И для интереса , стоять должно хотя бы у одного противника , и инфа по всем противникам будет доступна ?

Edited by Beliy.IV

Share this post


Link to post

Short link
Share on other sites

На 4ch удалили тему, а тема я бы сказал узкопрофильная, а если быть точным, то это для теx кто будет задрачивать ЛБЗ или сам для себя или для теx кто это делает за бабки, в любом случае вбр должен закинуть поддельника в противоположную команду, а это уже никак не xакнуть. Я бы сделал модик платным, для теx кто Лыбызит за бабло мод будет интересен, а для массового использования он только испортит и без того загаженную горе гейдизайнерами игру.

Share this post


Link to post

Short link
Share on other sites

 

 

не xакнуть
вы плохо понимаете суть вопроса 

Share this post


Link to post

Short link
Share on other sites

 

 

Осталось запихать во все модпаки, и настроить на отображение без засвета лишь арты (ну и статистов), в какой нибудь известный и широко распространённый мод например в XVM :D

Уже давно услуга есть для премиумных XVM-пользователей

  • Upvote 7
  • Downvote 2

Share this post


Link to post

Short link
Share on other sites
Guest
This topic is now closed to further replies.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...