elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Únete al Grupo Steam elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  [APORTE] Usando consola con Threads (aka: consola estilo quake) :D
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [APORTE] Usando consola con Threads (aka: consola estilo quake) :D  (Leído 2,684 veces)
raul338


Desconectado Desconectado

Mensajes: 2.633


La sonrisa es la mejor forma de afrontar las cosas


Ver Perfil WWW
[APORTE] Usando consola con Threads (aka: consola estilo quake) :D
« en: 6 Marzo 2010, 17:27 »

 :D Hoola!

Venia preparando esto desde hace tiempo, pero siempre aparecian algun problema de "cuentas" y se desfiguraba todo jaja  :laugh:

En fin, Tuve que usar threads para una aplicacion que hice, y decidi hacerlo en consola (uff... para que  :xD)

En fin, el programa hacia lo que queria que haga, peeero...  necesitaba ejecutar "comandos" introducidos por el usuario, y a la vez el programa debia reportar algunos  datos al usuario. Como era de suponerse hacia un ReadLine y en otro thread usaba WriteLine cuando era necesario. Ahi surgio un problema, se cruzaba todo haciendo todo ilegible al volver a leer, les pongo un ejemplo grafico:

Escenario: Un servidor de juegos... Al estilo Half-Life  :xD

Código:
Log:
Nivel 1 iniciado
esperando respuesta....
_

si yo pongo un comando ("agregar bot 1") pero en medio de la escritura entra un jugador .... se reporta como "Nuevo jugador: -xDMan-", se pone justo apenas terminamos de escribir la letra en la que estabamos, se escribe el reporte y despues nosotros seguimos escribiendo. Queda horrible!!!

Empezamos a escribir el comando:
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
agregar b_

Entra el usuario, interrumpiendo nuestro comando
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
agregar bNuevo jugador: -xDMan-_

Si seguimos escribiendo (supongamos que no nos dimos cuenta que salio eso)
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
agregar bNuevo jugador: -xDMan-ot 1_

y el ReadLine devuelve bien: agregar bot 1

pero cuando lees la consola directa, es total mente ilegible, todo mezclado  :¬¬


y aca idee los metodos necesarios para resolverlo  ;)

Son dos funciones que reemplazan a Console.WriteLine y Console.ReadLine

ReadLine: es muy similar al Console.ReadLine, pero tiene un buffer en el que se guarda el string escrito
WriteLine: lo que hace es "borrar" de la consola lo escrito y poner lo que se quiere introducir, y luego abajo poner exactamente lo que habiamos puesto (desde el buffer :P) y todo haciendo parecer que no paso nada.

Usando mis metodos ReadLine y WriteLine, quedaria asi

Empezamos a escribir el comando:
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
agregar b_

Entra el usuario, interrumpiendo nuestro comando
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
Nuevo jugador: -xDMan-
agregar b_

seguimos escribiendo como si nada hubiera pasado
Código:
Log:
Nivel 1 iniciado
esperando respuesta....
Nuevo jugador: -xDMan-
agregar bot 1_

y el ReadLine devuelve bien (como era de esperarse): agregar bot 1


Como les dije, es una consola al estilo quake (porque en quake se vio la primera consola asi, de ahi el nombre)


Sin mas, aca esta el codigo, A mas de uno le puede servir  ;-)
(no se necesita ninguna referencia, nada, esta todo listo para servir  :laugh:)


Código
  1. // Si uno hace un WriteLine mientras se espera un ReadLine pasa esto:
  2. // "probando              // Si antes de que ponga la ultima comilla pongo un Console.WriteLine("Hola") queda asi
  3. // "progandoHola
  4. // "
  5. //
  6. // La siguentes funciones estan hechas para evitar eso
  7. // By Raul338 (proximamente: raul338.com.ar)
  8. static string buffer = "";
  9. /// <summary>Escribe un texto sin "cortar" o interrumpir un Console.ReadLine()</summary>
  10. /// <param name="Text">Texto a escribir</param>
  11. static void WriteLine(string Text)
  12. {
  13.    // Guarda la ubicacion actual (la linea se le suma 1, porque es la que sigue)
  14.    int lastLeftPos = Console.CursorLeft;
  15.    int lastTopPos = Console.CursorTop +1;
  16.  
  17.    // Lineas de lo que se va a escribir y lo escrito a mano
  18.    int lineas = ObtenerLineas(Text);
  19.    int lineasEscritas = ObtenerLineas(buffer);
  20.  
  21.    // Esto equilibra algunas cuentas
  22.    if (lastTopPos != 0)
  23.        if (lineasEscritas < 1)
  24.            lastTopPos -= 1;
  25.  
  26.    // Ponemos el cursor al principio de la linea que empezamos a escribir y borramos lo escrito
  27.    Console.SetCursorPosition(0, lastTopPos - lineasEscritas);
  28.    Console.Write("".PadLeft(buffer.Length)); // Aca vaciamos todo :P
  29.    Console.SetCursorPosition(0, lastTopPos - lineasEscritas);
  30.  
  31.    // Escribimos el texto
  32.    Console.WriteLine(Text);
  33.  
  34.    // Ponemos en el cursor en el nuevo lugar (lugarAnterior + las nuevas lineas)
  35.    Console.SetCursorPosition(0, lastTopPos + lineas - lineasEscritas);
  36.  
  37.    // Ponemos lo que el usuario habia escrito anteriormente
  38.    Console.Write(buffer);
  39. }
  40.  
  41. /// <summary>Obtienes las lineas que ocupa el texto introducido en consola</summary>
  42. /// <param name="input">Texto a contar las lineas</param>
  43. /// <returns>Lineas que ocupa en consola</returns>
  44. /// <!-- By Raul338 -->
  45. static int ObtenerLineas(string input)
  46. {
  47.    int lineas = 0;
  48.    // Separamos el texto en lineas
  49.    System.Text.RegularExpressions.Match matchResult = System.Text.RegularExpressions.Regex.Match(input, @"[^\r\n]*(?:\r\n)?");
  50.    while (matchResult.Success)
  51.    {
  52.        // Por alguna razon se incluyen capturas vacias o_O
  53.        if (matchResult.Value != "")
  54.        {
  55.            // La expreision regular tambien cuenta los cierre de lineas, asi que los separamos
  56.            int enter = matchResult.Value.IndexOf(System.Environment.NewLine);
  57.  
  58.            string final = matchResult.Value;
  59.            if (enter >= 0)
  60.                final = matchResult.Value.Substring(0, enter);
  61.  
  62.            // Hacemos la division, sera una linea, pero en consola no entra como tal y se dividen en lineas
  63.            lineas += Convert.ToInt32(final.Length / Console.WindowWidth) + 1;
  64.        }
  65.        matchResult = matchResult.NextMatch();
  66.    }
  67.    return lineas;
  68. }
  69.  
  70. /// <summary>ReadLine 2.0 para poder Escribir a la vez</summary>
  71. /// <returns>El texto escrito</returns>
  72. static string ReadLine()
  73. {
  74.    string result = "";
  75.    // Lee cada tecla presionada
  76.    ConsoleKeyInfo t = Console.ReadKey(false);
  77.    while (t.Key != ConsoleKey.Enter)
  78.    {
  79.        // En caso de que borre, se quita el ultimo caracter
  80.        if (t.Key == ConsoleKey.Backspace && buffer.Length > 0)
  81.        {
  82.            Console.Write(" ");
  83.            Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
  84.            buffer = buffer.Substring(0, buffer.Length - 1);
  85.        }
  86.        else
  87.        {
  88.            // Es un caracter cualquiera, se agrega al string
  89.            buffer += t.KeyChar.ToString();
  90.        }
  91.        t = Console.ReadKey(false);
  92.    }
  93.    Console.WriteLine();
  94.    // Se vacia el buffer y se devuelve lo escrito
  95.    result = buffer;
  96.    buffer = "";
  97.    return result;
  98. }
  99.  


Y aca un pequeño ejemplo: Un thread con un bucle infinito que muestra numeros sucesivos en la pantalla, y ustedes pueden escribir lo que sea

Código
  1. static void Main(string[] args)
  2. {
  3.    // Empezamos el relleno
  4.    Thread t = new Thread(Rellena);
  5.    t.Start();
  6.  
  7.    string comando;
  8.    do
  9.    {
  10.        // Al mismo tiempo que escribimos se separa lo que se va a mostrar de lo que escribimos
  11.        comando = ReadLine();
  12.        WriteLine(DateTime.Now.ToString("HH:mm:ss") + System.Environment.NewLine +" - " + comando);
  13.    } while (comando != "salir");
  14.  
  15.    t.Abort();
  16. }
  17.  
  18.  
  19. // Iteracion infinita para rellenar la consola
  20. static void Rellena()
  21. {
  22.    int i = 0;
  23.    while (true) {
  24.        WriteLine(i.ToString());
  25.        if (i == int.MaxValue) i = 0;
  26.        i++;
  27.        Thread.Sleep(1000);
  28.    }
  29. }
  30.  


Espero que lo prueben, y les guste  :)

Cualquier critica (constructiva) es recibida   ;)


En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
[Batch] [Aporte] (O eso creo xD) Consola de reciclaje v1.0
Scripting
Eleкtro 0 1,933 Último mensaje 3 Febrero 2012, 07:29
por Eleкtro
[Aporte]Pasar grafos fahrenheit a celsius y viceversa(consola)
Java
Senior++ 2 1,537 Último mensaje 9 Julio 2012, 08:45
por Senior++
[Aporte] Java-Leer cantidades (consola)
Java
Senior++ 2 1,867 Último mensaje 16 Julio 2012, 06:26
por hucruz
[C++] [Aporte] Buscaminas por consola
Programación C/C++
Wofo 5 5,700 Último mensaje 15 Marzo 2013, 11:18
por Wofo
Como finalizar un dns_spoof de ettercap por consola?
Hacking Ético
krowa 0 1,537 Último mensaje 29 Junio 2013, 06:02
por krowa
Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines