Archives pour la catégorie «gcn»

La 12ième édition des Novendiales a commencé !

Bonjour à tous,

Les votes sont clos depuis vendredi soir et c’est le thème de notre nouvel adhérent Kick (une fois encore) qui a été retenu : « Old School ». Vous avez donc jusqu’à dimanche prochain (8 mars 2012) pour rendre votre jeu vidéo (réalisé seul ou en binôme). Pour plus de précisions, je vous invite à lire l’interview sur gamesphere accordée par Tof & moi-même qui résume assez bien les enjeux de ce concours de création de jeu vidéo.

Mise à jour du Bilboplanet

Bonjour,

Certains d’entre vous ont peut-être constaté que leur flux du planet gcn avait été « rechargé » (sous Opera ou newsbeuter par exemple, je vous invite à me dire en commentaire si vous avez eu le même problème avec un autre lecteur RSS). Ceci est dû à la mise à jour du bilboplanet qui supporte maintenant les tags ! Je rappelle que le bilboplanet est un logiciel jeune et que notre planet est toujours en phase de test donc le phénomène risque de se reproduire (pas tout de suite cependant).

Merci de votre compréhension

Comment éviter des erreurs « bêtes » en manipulant la pile lua

Lua est globalement très facile à utiliser. Ceci dit la manipulation de la pile (stack) n’est pas forcément évidente sur de longues manipulations. En effet selon la fonction employée, la fonction va dépiler (pop) un certain nombre d’éléments, voire en pusher un certain nombre. Dès lors comment s’assurer que la pile est équilibrée (balanced), c’est-à-dire que la taille de la pile avant et après appel de la fonction est identique ?

Imaginons par exemple cette fonction (tirée & modifiée  de luabind) :

 int create_cpp_class_metatable(lua_State* L)
 {
//Empile un tableau
lua_newtable(L);

// Empile une chaîne de caractère
 lua_pushstring(L, "__luabind_classrep");
// Empile un booléen
 lua_pushboolean(L, 1);
/* Jusque là c'était simple, maintenant il faut être capable de retenir que cette fonction assigne au tableau à la position en paramètre (soit ici "-3", c'est-à-dire 3 emplacements en dessous du haut de la pile => le tableau créé par lua_newtable(L)), la valeur à l'index -1 pour l'indice à l'index -2. Cet appel équivaut donc à monNouveauTableau["__luabind_classrep"] = 1.
lua_rawset dépile les 2 paramètres du haut de la pile ("__luabind_classrep" et "1") mais ne touche pas au tableau...
*/
 lua_rawset(L, -3);

// du coup ici on quitte la fonction en laissant le tableau sur le haut de la pile. PAS BIEN !!
}

Pour faciliter le débogage de ce type d’erreur, certaines bibliothèques dont luabind propose une classe avec le prototype suivant:

// Copyright (c) 2003 Daniel Wallin and Arvid Norberg

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef LUABIND_DEBUG_HPP_INCLUDED
#define LUABIND_DEBUG_HPP_INCLUDED

#ifndef NDEBUG

#include <luabind/lua_include.hpp>
#include <cassert>

namespace luabind { namespace detail
{

    /** \struct  stack_checker_type
     *  Registers stack size on creation. Destructor checks size is the same than that registered during creation (otherwise asserts).
     */

	class stack_checker_type
	{
	    public:
            stack_checker_type(lua_State* L,const int& diff)
                : m_L(L)
                , m_stack(lua_gettop(m_L) + diff)
            {}

            ~stack_checker_type()
            {
                assert(m_stack == lua_gettop(m_L));
            }
        private:
            lua_State* m_L;
            int m_stack;
	};

}}

    /** \def LUABIND_CHECK_STACK
     *   This macro checks if stack is balanced between its construction and destruction (within its C++ scope).
     * Available only with NDEBUG
     * \param A lua_State
     * creates an object registering current size of stack. When getting out of scope, destruct
     */
    #define LUABIND_CHECK_STACK(L) luabind::detail::stack_checker_type stack_checker_object(L,0)


    /** \def LUABIND_CHECK_STACK_DIFF check that the difference in size between construction and destruction of the structure is equal to diff
    * \param diff Differnece of stack size (either positive or negative)
    **/
    #define LUABIND_CHECK_STACK_DIFF(L,diff) luabind::detail::stack_checker_type stack_checker_object(L, (diff) )
#else
    #define LUABIND_CHECK_STACK(L) do {} while (0)
    #define LUABIND_CHECK_STACK_DIFF(L,diff) do {} while (0)
#endif

#endif // LUABIND_DEBUG_HPP_INCLUDED

Cette classe enregistre la taille de la pile lors de la construction d’une de cette instance. Quand l’instance sort de sa portée (scope), typiquement en fin de fonction, le destructeur est appelé. Le destructeur vérifie alors que la taille est identique à celle enregistrée lors de son instanciation. Si la taille de la pile après diffère de celle à l’instanciation alors un assert est lancé. Si l’on reprend notre exemple précédent, le code devient alors.


        int create_cpp_class_metatable(lua_State* L)
        {

            LUABIND_CHECK_STACK(L);//!< Crée une instance de la classe définie dans le fichier précédent

            lua_newtable(L);

            // mark the table with our (hopefully) unique tag
            // that says that the user data that has this
            // metatable is a class_rep
            lua_pushstring(L, "__luabind_classrep");
            lua_pushboolean(L, 1);
            lua_rawset(L, -3);

        }/* On sort du scope, le destructeur est appelé et détecte que la taille diffère (le tableau est restée sur la pile. La pile n'est pas "balanced", un assert va être lancé */

La version précédente de create_cpp_class_metatable va donc lancer un assert. Voici la version corrigée:


        int create_cpp_class_metatable(lua_State* L)
        {

            LUABIND_CHECK_STACK(L);//!< Crée une instance de la classe définie dans le fichier précédent

            lua_newtable(L);

            lua_pushstring(L, "__luabind_classrep");
            lua_pushboolean(L, 1);
            lua_rawset(L, -3);

            return luaL_ref(L, LUA_REGISTRYINDEX);//!< Dépile ce qu'il y a sur le dessus de la pile. Ici il s'agit du tableau
/* On sort du scope, le destructeur est appelé et détecte que la taille diffère (le tableau est restée sur la pile. La pile n'est pas "balanced", un assert va être lancé */
        }

On peut perfectionner la classe stack_checker_type en ajoutant une fonction membre check() pour vérifier la taille avant l’appel du destructeur, ou bien même passer un delta pour vérifier que la pile à la fin est égale à la taille de la pile lors de l’instanciation + delta (fonctionnalité que j’ai implémentée dans ma version de luabind). Par ailleurs on remarque que ce système de vérification peut-être désactivée selon si NDEBUG est défini ou pas. Les performances de votre application finale ne seront donc pas perturbées par cette astuce !

Passage à PugiXml

Bonjour,

Je viens ici faire un peu de pub pour l’excellente « librairie » C++ PugiXml. J’avais envie de la tester depuis longtemps et cette envie s’est concrétisée alors que je me heurtais aux manques de mon wrapper TinyXml (inhérents à TinyXml). Ne voulant pas réécrire (et surtout maintenir !) toute une librairie,  je l’ai donc testée (avec comme 2nd remplaçant irrXML, la librairie utilisée par irrlicht et qui existe en standalone). PugiXml = TinyXml + « tout » ce qui manque à TinyXml :

  1. La documentation est top !
  2. 1 seul fichier source ! donc encore plus compact que TinyXml
  3. des projets livrés avec l’archive
  4. On peut chainer les appels et tester le résultat final uniquement sans avoir à tester les nodes intermédiaires
    pugi::xml_node bind = config.child(L"player").child(L"bind");
     if(!bind){
     return false;
    }

    (ne plantera pas même s’il n’a pas trouvé « player » !)

  5. Quelques fonctions utiles comme as_bool(), as_int(), as_float()..
  6. Support de XPath
  7. Support de l’unicode
  8. ….

Bref l’essayer c’est l’adopter !