GS-Zone

Descompresión de graficos directos en memoria Ir al Indice

Moderadores: Moderadores de Argentum, Especialistas de Argentum, Especialistas de Programación

26

Nota » 01 Sep 2011 19:20

Bueno, me pidieron este aporte, y me gustó la idea asi que lo aporto.

Explicación: A la hora de descomprimir los gráficos para leerlos, teniendo que crear un grafico nuevo y borrarlo cada vez, ahora podemos usarlo de forma que no haya necesidad de que nos lo descomprima en el disco, asi ganamos algo de seguridad ante los recursos.

Nota: Para implementar este codigo es necesario tener implementado antes el codigo de compresión de graficos y lectura.

Nota2: Está hecho para Directx8, pero es facilmente aplicable a Directx7, solo cambia una llamada.

Asi que empezamos, todo en el cliente.

Abrimos el modulo zlib.bas y lo remplazamos entero por este:
  1. Option Explicit
  2. Private Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceExA" (ByVal lpRootPathName As String, FreeBytesToCaller As Currency, BytesTotal As Currency, FreeBytesTotal As Currency) As Long
  3.  
  4. Public Type FILEHEADER
  5.     lngFileSize As Long
  6.     intNumFiles As Integer
  7. End Type
  8.  
  9. Public Type INFOHEADER
  10.     lngFileStart As Long
  11.     lngFileSize As Long
  12.     strFileName As String * 16
  13.     lngFileSizeUncompressed As Long
  14. End Type
  15.  
  16. Public Temp_Windows_Directory As String
  17.  
  18. Public Enum resource_file_type
  19.     graphics
  20.     Interface
  21. End Enum
  22.  
  23. Private Const GRAPHIC_PATH As String = "\BMP\"
  24. Private Const GRAPHIC_PNG_PATH As String = "\PNG\"
  25. Private Const MIDI_PATH As String = "\Midi\"
  26. Private Const MP3_PATH As String = "\Mp3\"
  27. Private Const WAV_PATH As String = "\Wav\"
  28. Private Const MAP_PATH As String = "\Mapas\"
  29. Private Const INTERFACE_PATH As String = "\Interface\"
  30. Private Const SCRIPT_PATH As String = "\Init\"
  31. Private Const PATCH_PATH As String = "\Patches\"
  32. Private Const OUTPUT_PATH As String = "\Output\"
  33.  
  34. Private Declare Function Compress Lib "zlib.dll" Alias "compress" (dest As Any, destLen As Any, src As Any, ByVal srcLen As Long) As Long
  35. Private Declare Function UnCompress Lib "zlib.dll" Alias "uncompress" (dest As Any, destLen As Any, src As Any, ByVal srcLen As Long) As Long
  36. Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
  37.  
  38. Private Const MAX_LENGTH = 512
  39.  
  40. Public Sub Compress_Data(ByRef Data() As Byte)
  41.     Dim Dimensions As Long
  42.     Dim DimBuffer As Long
  43.     Dim BufTemp() As Byte
  44.     Dim BufTemp2() As Byte
  45.     Dim LoopC As Long
  46.    
  47.     Dimensions = UBound(Data)
  48.     DimBuffer = Dimensions * 1.06
  49.    
  50.     ReDim BufTemp(DimBuffer)
  51.     Compress BufTemp(0), DimBuffer, Data(0), Dimensions
  52.     Erase Data
  53.    
  54.     ReDim Preserve BufTemp(DimBuffer - 1)
  55.     Data = BufTemp
  56.     Erase BufTemp
  57.    
  58.     Data(0) = Data(0) Xor 166
  59. End Sub
  60.  
  61. Public Sub Decompress_Data(ByRef Data() As Byte, ByVal OrigSize As Long)
  62.     Dim BufTemp() As Byte
  63.    
  64.     ReDim BufTemp(OrigSize - 1)
  65.     Data(0) = Data(0) Xor 166
  66.     UnCompress BufTemp(0), OrigSize, Data(0), UBound(Data) + 1
  67.    
  68.     ReDim Data(OrigSize - 1)
  69.     Data = BufTemp
  70.     Erase BufTemp
  71. End Sub
  72. Public Function Extract_File(ByVal file_type As resource_file_type, ByVal resource_path As String, ByVal File_Name As String, ByVal OutputFilePath As String) As Boolean
  73.    
  74.     Dim LoopC As Long
  75.     Dim SourceFilePath As String
  76.     Dim SourceData() As Byte
  77.     Dim InfoHead As INFOHEADER
  78.     Dim handle As Integer
  79.    
  80. On Local Error GoTo ErrHandler
  81.    
  82.     Select Case file_type
  83.  
  84.         Case graphics
  85.                 SourceFilePath = resource_path & "\Graficos.pak"
  86.            
  87.         Case Interface
  88.                 SourceFilePath = resource_path & "\Interface.pak"
  89.        
  90.         Case Else
  91.             Exit Function
  92.     End Select
  93.    
  94.     InfoHead = File_Find(SourceFilePath, File_Name)
  95.    
  96.     If InfoHead.strFileName = "" Or InfoHead.lngFileSize = 0 Then Exit Function
  97.  
  98.     handle = FreeFile
  99.     Open SourceFilePath For Binary Access Read Lock Write As handle
  100.    
  101.     If InfoHead.lngFileSizeUncompressed > General_Drive_Get_Free_Bytes(Left$(App.Path, 3)) Then
  102.         Close handle
  103.         MsgBox "There is not enough drive space to extract the compressed file.", , "Error"
  104.         Exit Function
  105.     End If
  106.    
  107.    
  108.     ReDim SourceData(InfoHead.lngFileSize - 1)
  109.    
  110.     Get handle, InfoHead.lngFileStart, SourceData
  111.         Decompress_Data SourceData, InfoHead.lngFileSizeUncompressed
  112.     Close handle
  113.    
  114.     handle = FreeFile
  115.     Open OutputFilePath & InfoHead.strFileName For Binary As handle
  116.         Put handle, 1, SourceData
  117.     Close handle
  118.    
  119.     Erase SourceData
  120.        
  121.     Extract_File = True
  122. Exit Function
  123.  
  124. ErrHandler:
  125.     Close handle
  126.     Erase SourceData
  127. End Function
  128.  
  129. Public Function Extract_File_Memory(ByVal file_type As resource_file_type, ByVal resource_path As String, ByVal File_Name As String, byref SourceData() As Byte) As Boolean
  130.  
  131.     ' Parra was here (;
  132.     Dim LoopC As Long
  133.     Dim SourceFilePath As String
  134.     Dim InfoHead As INFOHEADER
  135.     Dim handle As Integer
  136.    
  137. On Local Error GoTo ErrHandler
  138.    
  139.     Select Case file_type
  140.  
  141.         Case graphics
  142.                 SourceFilePath = resource_path & "\Graficos.pak"
  143.            
  144.         Case Interface
  145.                 SourceFilePath = resource_path & "\Interface.pak"
  146.        
  147.         Case Else
  148.             Exit Function
  149.     End Select
  150.    
  151.     InfoHead = File_Find(SourceFilePath, File_Name)
  152.    
  153.     If InfoHead.strFileName = "" Or InfoHead.lngFileSize = 0 Then Exit Function
  154.  
  155.     handle = FreeFile
  156.     Open SourceFilePath For Binary Access Read Lock Write As handle
  157.    
  158.     If InfoHead.lngFileSizeUncompressed > General_Drive_Get_Free_Bytes(Left$(App.Path, 3)) Then
  159.         Close handle
  160.         MsgBox "There is not enough drive space to extract the compressed file.", , "Error"
  161.         Exit Function
  162.     End If
  163.    
  164.    
  165.     ReDim SourceData(InfoHead.lngFileSize - 1)
  166.    
  167.     Get handle, InfoHead.lngFileStart, SourceData
  168.         Decompress_Data SourceData, InfoHead.lngFileSizeUncompressed
  169.     Close handle
  170.        
  171.     Extract_File_Memory = True
  172. Exit Function
  173.  
  174. ErrHandler:
  175.     Close handle
  176.     Erase SourceData
  177. End Function
  178.  
  179. Public Sub Delete_File(ByVal file_path As String)
  180.     Dim handle As Integer
  181.     Dim Data() As Byte
  182.    
  183.     On Error GoTo Error_Handler
  184.    
  185.     handle = FreeFile
  186.     Open file_path For Binary Access Write Lock Read As handle
  187.    
  188.     ReDim Data(LOF(handle) - 1)
  189.     Put handle, 1, Data
  190.    
  191.     Close handle
  192.    
  193.     Kill file_path
  194.    
  195.     Exit Sub
  196.    
  197. Error_Handler:
  198.     Kill file_path
  199.        
  200. End Sub
  201.  
  202. Public Function File_Find(ByVal resource_file_path As String, ByVal File_Name As String) As INFOHEADER
  203.  
  204. On Error GoTo ErrHandler
  205.  
  206.     Dim Max As Integer
  207.     Dim Min As Integer
  208.     Dim mid As Integer
  209.     Dim file_handler As Integer
  210.    
  211.     Dim file_head As FILEHEADER
  212.     Dim info_head As INFOHEADER
  213.    
  214.     If Len(File_Name) < Len(info_head.strFileName) Then _
  215.         File_Name = File_Name & Space$(Len(info_head.strFileName) - Len(File_Name))
  216.    
  217.     file_handler = FreeFile
  218.     Open resource_file_path For Binary Access Read Lock Write As file_handler
  219.    
  220.     Get file_handler, 1, file_head
  221.    
  222.     Min = 1
  223.     Max = file_head.intNumFiles
  224.    
  225.     Do While Min <= Max
  226.         mid = (Min + Max) / 2
  227.        
  228.         Get file_handler, CLng(Len(file_head) + CLng(Len(info_head)) * CLng((mid - 1)) + 1), info_head
  229.                
  230.         If File_Name < info_head.strFileName Then
  231.             If Max = mid Then
  232.                 Max = Max - 1
  233.             Else
  234.                 Max = mid
  235.             End If
  236.         ElseIf File_Name > info_head.strFileName Then
  237.             If Min = mid Then
  238.                 Min = Min + 1
  239.             Else
  240.                 Min = mid
  241.             End If
  242.         Else
  243.             File_Find = info_head
  244.            
  245.             Close file_handler
  246.             Exit Function
  247.         End If
  248.     Loop
  249.    
  250. ErrHandler:
  251.     Close file_handler
  252.     File_Find.strFileName = ""
  253.     File_Find.lngFileSize = 0
  254. End Function
  255.  
  256. Public Function General_Get_Temp_Dir() As String
  257.    Dim s As String
  258.    Dim c As Long
  259.    s = Space$(MAX_LENGTH)
  260.    c = GetTempPath(MAX_LENGTH, s)
  261.    If c > 0 Then
  262.        If c > Len(s) Then
  263.            s = Space$(c + 1)
  264.            c = GetTempPath(MAX_LENGTH, s)
  265.        End If
  266.    End If
  267.    General_Get_Temp_Dir = IIf(c > 0, Left$(s, c), "")
  268. End Function
  269. Public Sub General_Quick_Sort(ByRef SortArray As Variant, ByVal first As Long, ByVal last As Long)
  270.     Dim Low As Long, High As Long
  271.     Dim temp As Variant
  272.     Dim List_Separator As Variant
  273.    
  274.     Low = first
  275.     High = last
  276.     List_Separator = SortArray((first + last) / 2)
  277.     Do While (Low <= High)
  278.         Do While SortArray(Low) < List_Separator
  279.             Low = Low + 1
  280.         Loop
  281.         Do While SortArray(High) > List_Separator
  282.             High = High - 1
  283.         Loop
  284.         If Low <= High Then
  285.             temp = SortArray(Low)
  286.             SortArray(Low) = SortArray(High)
  287.             SortArray(High) = temp
  288.             Low = Low + 1
  289.             High = High - 1
  290.         End If
  291.     Loop
  292.     If first < High Then General_Quick_Sort SortArray, first, High
  293.     If Low < last Then General_Quick_Sort SortArray, Low, last
  294. End Sub
  295.  
  296. Public Function General_Drive_Get_Free_Bytes(ByVal DriveName As String) As Currency
  297.     Dim RetVal As Long
  298.     Dim FB As Currency
  299.     Dim BT As Currency
  300.     Dim FBT As Currency
  301.    
  302.     RetVal = GetDiskFreeSpace(Left(DriveName, 2), FB, BT, FBT)
  303.    
  304.     General_Drive_Get_Free_Bytes = FB * 10000
  305. End Function
  306.  
  307. Public Function Get_Extract(ByVal file_type As resource_file_type, ByVal File_Name As String) As String
  308.     Extract_File file_type, App.Path & "\Recursos\Graficos", LCase$(File_Name), App.Path & "\Recursos\amdInData\"
  309.     Get_Extract = App.Path & "\Recursos\amdInData\" & LCase$(File_Name)
  310. End Function
  311. Public Function Get_Interface(ByVal file_type As resource_file_type, ByVal File_Name As String) As String
  312.     Extract_File file_type, App.Path & "\Recursos\Interface", LCase$(File_Name), App.Path & "\Recursos\Interface\"
  313.     Get_Interface = App.Path & "\Recursos\Interface\" & LCase$(File_Name)
  314. End Function


Luego, podrán encontrar en este modulo todos los paths del cliente, por ejemplo:
  1.        Case graphics
  2.                 SourceFilePath = resource_path & "\Graficos.pak"
  3.            
  4.         Case Interface
  5.                 SourceFilePath = resource_path & "\Interface.pak"

Remplazan .pak por su extension, o si tienen los paths ordenados de otra forma cambienlos.

Ahora buscan esta parte del codigo:
  1.    Dim InfoHead As INFOHEADER
  2.     Dim file As String
  3.  
  4.             InfoHead = File_Find(App.Path & "\Recursos\Graficos\Graficos.TLAO", CStr(Archivo) & ".png")
  5.            
  6.         If InfoHead.lngFileSize <> 0 Then
  7.             file = zLib.Get_Extract(graphics, CStr(Archivo) & ".png")
  8.            
  9.             Set .texture = mD3D.CreateTextureFromFileEx(device, file, _
  10.                 D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_POINT, _
  11.                 D3DX_FILTER_NONE, &HFF000000, texture_info, ByVal 0)
  12.                                                
  13.         End If


Y lo reemplazan por esta:
  1.    Dim InfoHead As INFOHEADER
  2.     dim Buffer() As Byte
  3.    
  4.     InfoHead = File_Find(App.Path & "\Recursos\Graficos\Graficos.pak", CStr(Archivo) & ".png")
  5.    
  6.     If InfoHead.lngFileSize <> 0 Then
  7.                 ' Parra was here (;
  8.         Extract_File_Memory graphics, App.Path & "\Recursos\Graficos", LCase$(CStr(Archivo) & ".png"), Buffer()
  9.            
  10.         Set .texture = mD3D.CreateTextureFromFileInMemoryEx(device, Buffer(0), UBound(Buffer()) + 1, D3DX_DEFAULT, _
  11.                                                             D3DX_DEFAULT, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, _
  12.                                                             D3DX_FILTER_POINT, D3DX_FILTER_NONE, _
  13.                                                             &HFF000000, texture_info, ByVal 0)
  14.         Erase Buffer
  15.     End If

De nuevo, cambiamos el formato ".png" por el nuestro. Es customizable.

Finalmente, para las interfaces podemos hacer exactamente lo mismo, y nos funcionaria. Aunque habria que ver la manera de cargarlas. Pero si quieren esas pueden dejarlas como estan ahora.

Si no funciona el codigo, avisen, y lo reviso! Suerte, y a disfrutarlo!
Última edición por •Parra el 09 Oct 2011 14:49, editado 1 vez en total

Vicinity of obscenity
525
Legendario Inmortal [2]
Registrado: 5 Años de membresía!
Ubicación: España
Mensajes: 5579
Aportes: 50
Premios: 3
Mister Programador FreeForAll (3)

Nota » 01 Sep 2011 20:22

Gracias Parra en todo. Siempre ayudando a TLAO, :P
Ya lo probamos y te avisamos. :)

Imagen

Imagen

Imagen
Staff Tierras Legendarias AO
594
Oraculo [2]
Registrado: Años de membresía
Ubicación: Cordobá
Mensajes: 1337
Aportes: 12
Premios: 2
Campeón de Truco (1) Embajador (1)

Nota » 01 Sep 2011 21:44

I love You PARRA (L

Se te agradece, yo estaba intentando hacerlo con el CreateTextureFromFileInMemory y no entendia muy bien cual era la data para la funcion.

Muchas gracias.

Edit: Anda perfecto, aclaremos que el codigo de extraccion mediante la Zlib.bas ( para el que no lo tiene ) Va en la funcion CrearGrafico

Imagen
Staff Tierras Legendarias
395
Oraculo [5]
Registrado: Años de membresía
Ubicación: Villa del parque
Mensajes: 1925
Aportes: 9

Nota » 02 Sep 2011 07:25

Mafia escribió:I love You PARRA (L

Se te agradece, yo estaba intentando hacerlo con el CreateTextureFromFileInMemory y no entendia muy bien cual era la data para la funcion.

Muchas gracias.

Edit: Anda perfecto, aclaremos que el codigo de extraccion mediante la Zlib.bas ( para el que no lo tiene ) Va en la funcion CrearGrafico

Fantastico, espero que les sirva de mucho. Si tienen algun problema avisen, y si necesitan algun consejo mas tambien!

Vicinity of obscenity
525
Legendario Inmortal [2]
Registrado: 5 Años de membresía!
Ubicación: España
Mensajes: 5579
Aportes: 50
Premios: 3
Mister Programador FreeForAll (3)

Nota » 02 Sep 2011 09:55

Se crean y se dejan en memoria? Al poco tiempo chau memoria si es asi :P

PointMe. ¿Serás el más votado?

Imagen

Publica tu ao en Ranking AO!
Imagen

© PointMe y Ranking AO by Dex Systems
Dex Systems ส็็็็็็็็็็็็็็็็็็็็็็็็็
398
Destructor de Mentes [11]
Registrado: Años de membresía
Mensajes: 1025
Aportes: 12

Nota » 02 Sep 2011 10:07

Vernet escribió:Se crean y se dejan en memoria? Al poco tiempo chau memoria si es asi :P

Grave error, se nota que ni has leido el codigo.

Una vez lo carga el buffer se libera, dejando la memoria libre, y simplemente cargandolo en DirectX. Luego el sistema de memoria dinámica de AO ya se encarga de hacer todo lo demás.

Fijate en la linea esta:


Edit: Otra cosa Mafia, has chequeado si es más rapido de esta forma? Deberia de funcionar mas rapido, fijate que ahora nos evitamos algo de codigo, y es mas directo..

Vicinity of obscenity
525
Legendario Inmortal [2]
Registrado: 5 Años de membresía!
Ubicación: España
Mensajes: 5579
Aportes: 50
Premios: 3
Mister Programador FreeForAll (3)

Nota » 02 Sep 2011 12:46

•Parra escribió:
Vernet escribió:Se crean y se dejan en memoria? Al poco tiempo chau memoria si es asi :P

Grave error, se nota que ni has leido el codigo.

Una vez lo carga el buffer se libera, dejando la memoria libre, y simplemente cargandolo en DirectX. Luego el sistema de memoria dinámica de AO ya se encarga de hacer todo lo demás.

Fijate en la linea esta:


Edit: Otra cosa Mafia, has chequeado si es más rapido de esta forma? Deberia de funcionar mas rapido, fijate que ahora nos evitamos algo de codigo, y es mas directo..

Entonces no peligra en nada la memoria, o si?

Imagen

Imagen

Imagen
Staff Tierras Legendarias AO
594
Oraculo [2]
Registrado: Años de membresía
Ubicación: Cordobá
Mensajes: 1337
Aportes: 12
Premios: 2
Campeón de Truco (1) Embajador (1)

Nota » 02 Sep 2011 12:59

[JuliaaN] escribió:
•Parra escribió:
Vernet escribió:Se crean y se dejan en memoria? Al poco tiempo chau memoria si es asi :P

Grave error, se nota que ni has leido el codigo.

Una vez lo carga el buffer se libera, dejando la memoria libre, y simplemente cargandolo en DirectX. Luego el sistema de memoria dinámica de AO ya se encarga de hacer todo lo demás.

Fijate en la linea esta:


Edit: Otra cosa Mafia, has chequeado si es más rapido de esta forma? Deberia de funcionar mas rapido, fijate que ahora nos evitamos algo de codigo, y es mas directo..

Entonces no peligra en nada la memoria, o si?


No, la memoria no, no pasa nada, se limpia el buffer cada tanto, yo le pregunté a Parra si pasaba por valor las cosas ya que no leí el código y me dijo que no asi que en este caso no es problema

Ahí te ves.

Imagen

Imagen

Imagen

Imagen
Software Developer
197
Legendario Inmortal [1]
Registrado: 5 Años de membresía!
Ubicación: Caseros
Mensajes: 5071
Aportes: 30

Nota » 02 Sep 2011 13:56

siempre impresionando con cosas nueva parra jaja

gracias ^^



Santty.- escribió:Si, soy hincha de tu padre, el que te gana cada vez que te cruza, el dueño del barrio, el orgullo nacional, rey de copas y el máximo ganador de copa libertadores

PROBLEM?





La gente que cuando camina mueve un poco los labios está practicando respuestas originales para discusiones que ya perdieron hace dos horas.
YPF etatizada: -Hola q carga? -Deme Néstor Súper
686
Dragon Ancestral [4]
Registrado: Años de membresíaAños de membresía
Ubicación: Mendoza
Mensajes: 3545
Aportes: 40

Nota » 02 Sep 2011 17:13

Ya me parecia, lo habia leido muy por arriba y no vi esa linea

saludos
Última edición por Vernet el 02 Sep 2011 17:17, editado 1 vez en total

PointMe. ¿Serás el más votado?

Imagen

Publica tu ao en Ranking AO!
Imagen

© PointMe y Ranking AO by Dex Systems
Dex Systems ส็็็็็็็็็็็็็็็็็็็็็็็็็
398
Destructor de Mentes [11]
Registrado: Años de membresía
Mensajes: 1025
Aportes: 12

Nota » 03 Sep 2011 15:32

Buen aporte Parra, me podrias pasar el aporte posterior a este.

Saludos ^^

Imagen
Imagen
Staff Zeiked-Games
641
Dragon Ancestral [3]
Registrado: Años de membresíaAños de membresía
Ubicación: Castelar
Mensajes: 3414
Aportes: 66
Premios: 3
Usuario omnipresente (1) Embajador (2)

Nota » 03 Sep 2011 18:33

Muy bueno parra. Realmente my buenoo

Imagen
Maestro del Gremio de Ladrones
758
Dragon Ancestral [1]
Registrado: Años de membresía
Ubicación: Polinesia
Mensajes: 2462
Aportes: 9
Premios: 1
Embajador (1)

Nota » 04 Sep 2011 03:04

Buenisimo Parra , siempre aportando a la comunidad!

"No existen comentarios boludos, sino boludos que comentan."


Imagen


Imagen
-Staff Argentum Online-
877
Dragon Ancestral [2]
Registrado: Años de membresía
Ubicación: Buenos Aires
Mensajes: 3087
Aportes: 181
Premios: 3
Mister S.O.S. (2) Aportes (1)

Nota » 04 Sep 2011 17:20

Samke escribió:Buen aporte Parra, me podrias pasar el aporte posterior a este.

Saludos ^^

Te refieres al de compresion? Al anterior? Pues no se donde debe estar, seguro que está aportado.. pero igualmente, puedes extraerlo de ORE, usando su compressor también. Igual creo que solo implementando este quizás ya sea funcional, aunque no estoy seguro.

Vicinity of obscenity
525
Legendario Inmortal [2]
Registrado: 5 Años de membresía!
Ubicación: España
Mensajes: 5579
Aportes: 50
Premios: 3
Mister Programador FreeForAll (3)

Nota » 10 Sep 2011 01:32

Deberia de ir unas mil veces mas rapido en cada operacion. El disco duro trabaja en ms y la ram en ns por lo que si directamente descomprimimos en memoria y planchamos desde ahi, tendria que ser en verdad mucho mas rapido.
Buen aporte Parra!
Aguante River Plate ! ! !
909
Moderador
Registrado: Años de membresíaAños de membresíaAños de membresía
Ubicación: Villa adelina, Vicente Lopez.
Mensajes: 14427
Aportes: 305
Premios: 10
Señor Moderador (3) Señor Reglamento (1) Aportes (2) Embajador (3) Detector de Bugs (1)

Siguiente

Volver a Otras versiones

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados