Autor Tema: Los strings también son mala gente  (Leído 893 veces)

Arcontus

  • Sr. Member
  • ****
  • Mensajes: 278
  • Karma: 9
Los strings también son mala gente
« en: Mayo 27, 2018, 01:22:56 pm »
Hola chicos,
tengo un problema muy extraño con mi proyecto. Debido a su funcionamiento en determinados momentos un enemigo puede recibir múltiples impactos y por cada uno muestro un registro flotante de este en pantalla. De esta manera hay momentos donde pueden juntarse muchos textos en pantalla. El caso es que todo parece ir bien, pero al llevar unos 20 minutos de ejecución me da crashes aleatorios y no siempre.

Sospecho que el problema pueda originarse con la gestión de strings y me he hecho un programilla para hacer un uso intensivo de strings y pese a que no he conseguido que el programa reviente, si que aparecen resultados inesperados.

Este es el código:
Código: [Seleccionar]
import "mod_key"
import "mod_video"
import "mod_text"
import "mod_map"
import "mod_string"
import "mod_rand"
import "mod_say"


PROCESS creaTexto(int miX, int miY, string cadena)
PRIVATE
    int txtid;
    int temporizador;
    string miCadena;
END
BEGIN
    txtid = -1;
    x = miX;
    y = miY;
    miCadena = cadena;
    temporizador = 360;
    txtid = write_string(0, x, y, 0, &miCadena);

    while(temporizador > 0)
        temporizador--;
        move_text(txtid, x, y);
        FRAME;
    END
OnExit:
    if (txtid >= 0) delete_text(txtid); END
    //say(cadena);
END

PROCESS main()
PRIVATE
    int indice, contador, contador2, txtid;
    string miCadena, micadena2;

END
BEGIN
    set_fps(200,0);
    set_mode(800,600,32, mode_window);
    x = 30;
    y = 550;
    txtid = write_string(0, 30,550, 0, &micadena2);
    while(!(key(_ESC)))
            contador2++;
            for (indice = 0; indice < 100; indice++)
                contador++;
                miCadena = "Hola caracola: " + contador;
                miCadena2 = "Total: " + contador;
                creaTexto(rand(10,200), rand(10,500), miCadena);
            END
            if (contador2%800 == 0)
                if (txtid >= 0)
                    delete_text(txtid);
                    txtid = write_string(0, 30,550, 0, &micadena2);

                END
            END
            if (key(_q))
                if (txtid >= 0) delete_text(txtid); txtid = -1; END
            END
            if (txtid < 0)
                txtid = write_string(0, 30,550, 0, &micadena2);
            else
                move_text(txtid, x, y);
            END
        FRAME;
    END
END

El programa trata de pintar "hola caracola" en procesos independientes y aqui es donde esta el fallo, hay una segunda cadena "micadena2" dentro del main que debería tener el valor "Total: N" donde N es el numero de strings pintadas. Lo que me sucede es que al pasar unos pocos segundos miCadena2, ¡vale lo mismo que miCadena! ¿¡WTF!?
Ni dandole a la Q para que repinte el string se arregla el problema, por lo que parece que el problema esté en la cadena y no en el write.

¿Alguna alma caritativa puede probar el código con su versión de Bennu y comentar el resultado?

Y una última cosa es que tras unos segundos, si no repinto la string miCadena2 esta se borra por "arte de magia". Para hacer la prueba comentad la linea 67 "move_text(txtid, x, y);" ¿Esto es normal y deseable?

« última modificación: Mayo 28, 2018, 09:37:36 am por Arcontus »

Futu-block

  • Hero Member
  • *****
  • Mensajes: 2762
  • Karma: 34
  • Superviviente marciano
    • futublock
Re:Los strings también son mala gente
« Respuesta #1 en: Mayo 27, 2018, 03:12:36 pm »
Si, se borra automaticamente cuando le dá la gana...



SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #2 en: Mayo 28, 2018, 04:01:48 am »
gracias, lo vere
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #3 en: Mayo 28, 2018, 04:19:00 am »
aca esta el problema

Código: [Seleccionar]
                if (txtid >= 0) delete_text(txtid); END

debe ser

Código: [Seleccionar]
                if (txtid >= 0) delete_text(txtid); txtid = -1; END

el tema es que borras txtid pero nunca reseteas el id, entonces el texto desaparece, y el sistema intenta mover el texto a x,y, al no haber nada, no hace nada, el txtid que se intenta usar no existe... pero llega un momento en que el sistema reusa ese id para otro write_string y de ahi hace el move de un nuevo texto creado por creaTexto, al lugar de donde estaba "Total ..."

« última modificación: Mayo 28, 2018, 04:23:23 am por SplinterGU »
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

  • Sr. Member
  • ****
  • Mensajes: 278
  • Karma: 9
Re:Los strings también son mala gente
« Respuesta #4 en: Mayo 28, 2018, 09:02:52 am »
Hola SplinterGU,
si, he visto el fallo, bien visto. De todas maneras sigue teniendo un comportamiento extraño, el valor de miCadena2 no es el que le correspondería. Actualizo el código de arriba.
« última modificación: Mayo 28, 2018, 09:37:11 am por Arcontus »

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #5 en: Mayo 29, 2018, 02:52:13 am »
no se que valor incorrecto te da, yo llegue a ver Total: 33000, y lo corte porque me canse...

da mas informacion

en un nuevo post, no edites, porque no se que es nuevo y que es viejo, no tengo tanta memoria...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #6 en: Mayo 29, 2018, 02:55:06 am »
micadena2 tiene el valor correcto, usar write_text + move no es lo adecuado para probar esto...

usa say, pero solo de micadena2... vas a ver que siempre tiene el mismo valor...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

  • Sr. Member
  • ****
  • Mensajes: 278
  • Karma: 9
Re:Los strings también son mala gente
« Respuesta #7 en: Mayo 29, 2018, 09:23:00 am »
no se que valor incorrecto te da, yo llegue a ver Total: 33000, y lo corte porque me canse...

da mas informacion

en un nuevo post, no edites, porque no se que es nuevo y que es viejo, no tengo tanta memoria...
Hola SplinterGU,
tienes razón de que quizás no expliqué bien la casuistica. El caso es que el contenido de miCadena2 cambia (en mi caso al sobrepasar los 33000) pero no a Total: N sino a Hola Caracola: N. Y esto no me deja nada tranquilo hasta no saber exactamente porque.
Adjunto dos imagenes para que se vea el resultado que a mi me devuelve. AM.png es el resultado esperado, pero en AM 001.png se ve como ha cambiado el téxto de miCadena2 de manera "inexplicable".

Arcontus

  • Sr. Member
  • ****
  • Mensajes: 278
  • Karma: 9
Re:Los strings también son mala gente
« Respuesta #8 en: Mayo 29, 2018, 09:38:00 am »
Modifico el código para dejarlo más simplificado donde se observa el mismo problema que comentaba:
Código: [Seleccionar]
import "mod_key"
import "mod_video"
import "mod_text"
import "mod_map"
import "mod_string"
import "mod_rand"
import "mod_say"


PROCESS creaTexto(int miX, int miY, string cadena)
PRIVATE
    int txtid;
    int temporizador;
    string miCadena;
END
BEGIN
    txtid = -1;
    x = miX;
    y = miY;
    miCadena = cadena;
    temporizador = 360;
    txtid = write_string(0, x, y, 0, &miCadena);

    while(temporizador > 0)
        temporizador--;
        move_text(txtid, x, y);
        FRAME;
    END
OnExit:
    if (txtid >= 0) delete_text(txtid); END
    //say(cadena);
END

PROCESS main()
PRIVATE
    int indice, contador, contador2, txtid;
    string miCadena, micadena2;

END
BEGIN
    set_fps(200,0);
    set_mode(800,600,32, mode_window);
    x = 30;
    y = 550;
    txtid = write_string(0, 30,550, 0, &micadena2);
    while(!(key(_ESC)))
            contador2++;
            for (indice = 0; indice < 100; indice++)
                contador++;
                miCadena = "Hola caracola: " + contador;
                miCadena2 = "Total: " + contador;
                creaTexto(rand(10,200), rand(10,500), miCadena);
            END
            move_text(txtid, x, y);
            say (miCadena2);
        FRAME;
    END
END
En mi caso al pasar de las 33000 lineas (aprox) el valor mostrado de miCadena2 por el write cambia inexplicablemente y quiero descartar que esto pueda provocar un crash. Obviamente esto es una prueba que trata de alcanzar el límite de strings lo más rápidamente posible para ver su comportamiento, y me da la impresión de que algo malo está sucediendo.
Con Say se muestra el valor correcto de miCadena2 en todo momento, por lo que parece que el problema puede estar en la función write al alcanzar dicho limite de strings. Si se comenta la linea move_text(txtid, x, y); al alcanzar las 33000 el texto simplemente desaparece y no vuelve a aparecer.

Como reflexión, no solo en mi proyecto sino cualquier proyecto con un alto número de strings (ej: juegos de rol conversacionales) puede alcanzar este límite y tener como mínimo un funcionamiento no deseado.
Mi comentario anterior tiene unas capturas del error.
« última modificación: Mayo 29, 2018, 09:39:34 am por Arcontus »

FreeYourMind

  • Hero Member
  • *****
  • Mensajes: 5629
  • Karma: 127
    • GECA soft
Re:Los strings también son mala gente
« Respuesta #9 en: Mayo 29, 2018, 10:00:35 am »
independientemente del resto tantos strings en un juego de rol no serian problema, porque en ningun momento se enseñan tantos textos en pantalla. y si el juego llega a esa cifra, tampoco tienes que guardar todo el texto en el mismo array, puedes tener varios arrays con texto, de hecho es lo mas recomendable, uno para cada mundo o fase por ejemplo

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #10 en: Mayo 29, 2018, 01:22:06 pm »
el problema es que estas moviendo un texto que muestra micadena a la posicion de micadena2...

si say da correcto, no hay problema con las strings... simplemente estas poniendo en posicion de micadena2 un texto de micadena...

"0" (cero) tampoco es un valor correcto para id de texto... quizas tengas algo ahi, ya que tu codigo considera 0 como valido...

"0" (cero) se retorna cuando hay demasiados textos en pantalla, cuando se llega a 512.

un delete_text(0) elimina todos los textos...

un solo delete_text(0) eliminaria los textos, y sin saberlo podrias estar moviendo un nuevo texto de micadena al lugar de micadena2, ya que el id de micadena2 (que fue borrado por delete_text) ahora apunta a un write de micadena.

corregi el codigo, limpia adecuadamente los ids cada vez que borras un texto y no consideres 0 como valido, 0 es error
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Arcontus

  • Sr. Member
  • ****
  • Mensajes: 278
  • Karma: 9
Re:Los strings también son mala gente
« Respuesta #11 en: Mayo 29, 2018, 11:27:11 pm »
independientemente del resto tantos strings en un juego de rol no serian problema, porque en ningun momento se enseñan tantos textos en pantalla.
Eso es lo que yo me pensaba, pero no parece comportarse así, a ver como me explico para que se entienda bien:
Yo pensaba que con tal de no llegar al límite de strings en pantalla para que no se produzciera un colapso y se borraran (como mínimo) no pasaría nada, pero no es lo que me está sucediendo en mi proyecto.
Por lo que me ha parecido observar el problema es que al imprimir strings estos llegan a un número límite. En mi proyecto los enemigos van recibiendo impactos y voy mostrando sus valores por pantalla en un registro. Después de unos 20 minutos de juego, lo mismo solo hay 10 strings en ese momento en pantalla pero al entrar la 11ª string en pantalla, ciertas strings se borran o cambian de valor y poco después todo hace un crash.


Entonces, lo que trataba de hacer con ese programa de ejemplo que he subido es acelerar "el crash" y aun que no he conseguido que crashee el programa es super obvio que algo le pasa al write de miCadena2 justo después de que se provoque el colapso y borrado de strings.

Respecto a lo que comentas de reusar el mismo array, en este caso cada proceso tiene su propia string, donde le pasan por referencia un valor pero para asegurar el tiro lo guardo en una string propia del proceso e independiente al resto de procesos, en su seccion private... Imagina que en vez de enviar a ese proceso "hola caracola" le envio frases con sentido y una posición X e Y.


el problema es que estas moviendo un texto que muestra micadena a la posicion de micadena2...
Los límites de pintado del proceso "creaTexto()" son entre 10 y 500 en el eje Y, y main pinta en 550. Así que eso no debería suceder nunca, xDD (sino vaya porquería de prueba que os estaría enviando)


"0" (cero) tampoco es un valor correcto para id de texto... quizas tengas algo ahi, ya que tu codigo considera 0 como valido...

"0" (cero) se retorna cuando hay demasiados textos en pantalla, cuando se llega a 512.
Returns INT : TextID
-1 - Error.
>=0 - The TextID of the text.
Eso es lo que pone en la wiki. De hecho tenía todo mi código con un >0 y lo cambié a >=0 para ajustarme a la wiki. E incluso te abrí una sugerencia para no aceptar el código 0 como valido ¿recuerdas? Dijiste que te lo pensarías ;)

SplinterGU, has dicho una cosa que me hace que pensar si te pudiera dar alguna pista: dices que el límite está en 512, pero el problema aparece siempre a los 33.000 (aprox) y no a los 512. Diría que siempre es el mismo número. ¿Splinter, te dice algo el número 33.000 o ¡32.768!? Tiene una pinta muy sospechosa...


Conclusión, estoy de acuerdo con splinterGU de que no es la string, pero algo le pasa al write y puede ser seria la cosa.


SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #12 en: Mayo 30, 2018, 01:16:54 am »
mira que yo soy testarudo a veces... pero me ganas... :D

esto esta mal

Código: [Seleccionar]
OnExit:
    if (txtid >= 0) delete_text(txtid); END
    //say(cadena);
END

debe ser

Código: [Seleccionar]
OnExit:
    if (txtid > 0) delete_text(txtid); END
    //say(cadena);
END

y ademas necesitas esto, reemplazar esto

Código: [Seleccionar]
    txtid = write_string(0, x, y, 0, &miCadena);

por esto

Código: [Seleccionar]
    txtid = write_string(0, x, y, 0, &miCadena);
    if ( !txtid )
        say("no mas textos en pantalla!");
        return;
    end

para que entiendas que pasa

Código: [Seleccionar]
import "mod_key"
import "mod_video"
import "mod_text"
import "mod_map"
import "mod_string"
import "mod_rand"
import "mod_say"
import "mod_proc"

PROCESS creaTexto(int miX, int miY, string cadena)
PRIVATE
    int txtid;
    int temporizador;
    string miCadena;
END
BEGIN
    txtid = -1;
    x = miX;
    y = miY;
    miCadena = cadena;
    temporizador = 360;
    txtid = write_string(0, x, y, 0, &miCadena);
    if ( !txtid )
        say("no mas textos en pantalla!");
// descomentame        exit();
        return;
    end

    say(txtid);

    while(temporizador > 0)
        temporizador--;
        move_text(txtid, x, y);
        FRAME;
    END
OnExit:
    if (txtid > 0) delete_text(txtid); END
    //say(cadena);
END

PROCESS main()
PRIVATE
    int indice, contador, contador2, txtid;
    string miCadena, micadena2;

END
BEGIN
    set_fps(0,0);
    set_mode(800,600,32, mode_window);
    x = 30;
    y = 550;
    txtid = write_string(0, 30,550, 0, &micadena2);
    while(!(key(_ESC)))
            contador2++;
            for (indice = 0; indice < 100; indice++)
                contador++;
                miCadena = "Hola caracola: " + contador;
                miCadena2 = "Total: " + contador;
                creaTexto(rand(10,200), rand(10,500), miCadena);
            END
            move_text(txtid, x, y);
            say (miCadena2);
        FRAME;
    END
    let_me_alone();
END

asi el codigo es como funciona, hasta 500 mil en segundos

hay una linea que puse que dice // descomentame, descomentala y veras el ultimo id asignado... solo 512 textos, en realidad 511... luego retorna 0, pero si tu pones

Código: [Seleccionar]
    if (txtid >= 0) delete_text(txtid); END

cuando el write_string falla, txtid vale 0, y cuando el temporizador termina, se ejecuta el onexit y borra delete_text(0) *** TODOS LOS TEXTOS EN PANTALLA ***!!!! pero tu main sigue pensando que miCadena2 sigue vivo con el id obtenido cuando creaste su propio write_string... entonces, tu logica vuelve a crear todos los textos de nuevo... y cuando crea un write_string con miCadena con id igual al del main, entonces lo mueve al lugar de miCadena2...

te voy a poner otro codigo mas, para que veas lo que te digo... bug autoexplicado...

Código: [Seleccionar]
import "mod_key"
import "mod_video"
import "mod_text"
import "mod_map"
import "mod_string"
import "mod_rand"
import "mod_say"
import "mod_proc"


global
    int main_txtid;
    int no_mas_textos_flag = 0;
    int voy_a_borrar_todos = 0;
    int bug_flag = 0;
end


PROCESS creaTexto(int miX, int miY, string cadena)
PRIVATE
    int txtid;
    int temporizador;
    string miCadena;
END
BEGIN
    txtid = -1;
    x = miX;
    y = miY;
    miCadena = cadena;
    temporizador = 360;
    txtid = write_string(0, x, y, 0, &miCadena);
    if ( !txtid )
        if ( !no_mas_textos_flag )
            say("no mas textos en pantalla! (texto aparece solo primera vez, luego sucedera el error)");
            no_mas_textos_flag = 1;
        end
    end

    if ( txtid == main_txtid && !bug_flag)
        say( "aca genere un miCadena con id de miCadena2... bye bye... (muestro solo 1 vez)");
        bug_flag = 1;
    end

    while(temporizador > 0)
        temporizador--;
        move_text(txtid, x, y);
        FRAME;
    END
OnExit:
    if (!txtid && !voy_a_borrar_todos) say( "voy a borrar todos los textos, incluyendo main_txtid (solo muestro primera vez)"); voy_a_borrar_todos = 1; end
    if (txtid >= 0) delete_text(txtid); END
    //say(cadena);
END

PROCESS main()
PRIVATE
    int indice, contador, contador2, txtid;
    string miCadena, micadena2;

END
BEGIN
    set_fps(0,0);
    set_mode(800,600,32, mode_window);
    x = 30;
    y = 550;
    main_txtid = write_string(0, 30,550, 0, &micadena2);
    while(!(key(_ESC)))
            contador2++;
            for (indice = 0; indice < 100; indice++)
                contador++;
                miCadena = "Hola caracola: " + contador;
                miCadena2 = "Total: " + contador;
                creaTexto(rand(10,200), rand(10,500), miCadena);
            END
            move_text(main_txtid, x, y);
//            say (miCadena2);
        FRAME;
    END
    let_me_alone();
END
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #13 en: Mayo 30, 2018, 01:22:33 am »
NOTA: 32000 no tiene nada que ver con 32768, simplemente es casualidad que se reuse el mismo id cerca de ese numero... de hecho a mi me falla a los 36500 exactos, creados...

ya esta explicado el problema, debes controlar los ids de textos que creas, si haces un delete_text(0) se borra todo, write* retorna 0 ante error... (la wiki esta mal), luego de borrar todo los ids se reusan, si tu logica no limpia el id, en algun momento va a asignar ese id a otro texto, y tu logica hara cosas pensando que es otro texto que ya no existe...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

  • Hero Member
  • *****
  • Mensajes: 12756
  • Karma: 375
Re:Los strings también son mala gente
« Respuesta #14 en: Mayo 30, 2018, 01:30:35 am »
Eso es lo que pone en la wiki. De hecho tenía todo mi código con un >0 y lo cambié a >=0 para ajustarme a la wiki. E incluso te abrí una sugerencia para no aceptar el código 0 como valido ¿recuerdas? Dijiste que te lo pensarías ;)

y en esa ocasion evidentemente te respondi sin pensar mucho, o te dije que lo veria, ya que nunca puede retornar un id = 0 en un texto valido, ya que delete_text(0) borra todos los textos...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2