summaryrefslogblamecommitdiff
path: root/src/scripting/luautil.h
blob: 45e075f1dee6813fcf8cf01a8596eadcf3c36568 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
  
                   
                                                            
  
                                         
  
                                                                           



                                                                        
                                                                      




                                                                     
                                                                            

   

                           
 

                             



                    
 





                 
                                       
                                         
 
                         
             
                
                   
                
                   
                   
 
                                                         
 
   

































                                                                               





                     
                                                                          









                                                                             
                                                                       

                                                                           
                                           


                                     




                                                                               






                                                                              

                                                                              
       
                                             
     




                                                     



                                                            
                         

                                            


                                            
 

                                             

















                                                                             
                                      
                                            
                                            

                                                  
                                                                
                                                    
 
                                                               
 

                                                                            
 






                                                                              
                                                                         
                                                         
                                                                          
 
                                                                  
                                                                     
 
 

                                             







                                                      
                                                  



                                           
                            





                                          




                                              
 




                                                 
                                                  



                                   

                         

                                                                  

                               
                               





                                            
                    
                                   
            



                           

                                                                    

                               
                               



                                       
                                   
                                       



                        

                                                                          








                                                    

                           
                               
            



                        

                                                                 

                               
                               





                                           
                    
                                   
            



      
/*
 *  The Mana Server
 *  Copyright (C) 2007-2010  The Mana World Development Team
 *
 *  This file is part of The Mana Server.
 *
 *  The Mana Server is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  The Mana Server is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with The Mana Server.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SCRIPTING_LUAUTIL_H
#define SCRIPTING_LUAUTIL_H

#include "scripting/script.h"

extern "C" {
#include <lualib.h>
#include <lauxlib.h>
}

#include <string>
#include <list>
#include <map>
#include <set>
#include <vector>

#include "game-server/abilitymanager.h"
#include "game-server/attributemanager.h"

class CharacterComponent;
class Entity;
class ItemClass;
class MapComposite;
class MapObject;
class MonsterClass;
class StatusEffect;

void raiseWarning(lua_State *s, const char *format, ...);

/**
 * A generic userdata cache based on a native Lua table with weak values.
 *
 * Caching the created userdata instances has two main advantages:
 *
 * - It limits memory consumption and is a little faster. Creating these values
 *   is relatively slow (compared to light userdata).
 *
 * - It makes sure that two userdata objects that refer to the same C++ object
 *   compare as equal (because they will be the same userdata object).
 */
class UserDataCache
{
public:
    /**
     * Attempts to retrieve a userdata associated with the given object from
     * the cache and pushes it on the stack when available.
     *
     * Returns whether a userdata was pushed.
     */
    static bool retrieve(lua_State *s, void *object);

    /**
     * Inserts the userdata at the top of the stack in the cache using
     * the given object as the key. Leaves the userdata on the stack.
     */
    static void insert(lua_State *s, void *object);

private:
    static char mRegistryKey;
};


/**
 * A helper class for pushing and checking custom Lua userdata types.
 */
template <typename T>
class LuaUserData
{
public:
    /**
     * Creates a metatable to be used for the userdata associated with the
     * type. Then, registers the \a members with a library named \a typeName,
     * and sets the '__index' member of the metatable to this library.
     */
    static void registerType(lua_State *s,
                             const char *typeName,
                             const luaL_Reg *members)
    {
        mTypeName = typeName;

        luaL_newmetatable(s, mTypeName);        // metatable
        lua_pushliteral(s, "__index");          // metatable, "__index"
        lua_createtable(s, 0, 0);               // metatable, "__index", {}
#if LUA_VERSION_NUM < 502
        luaL_register(s, nullptr, members);
#else
        luaL_setfuncs(s, members, 0);
#endif

        // Make the functions table available as a global
        lua_pushvalue(s, -1);                   // metatable, "__index", {}, {}
        lua_setglobal(s, mTypeName);            // metatable, "__index", {}

        lua_rawset(s, -3);                      // metatable
        lua_pop(s, 1);                          // -empty-
    }

    /**
     * Pushes a userdata reference to the given object on the stack. Either by
     * creating one, or reusing an existing one.
     *
     * When a null-pointer is passed for \a object, the value 'nil' is pushed.
     */
    static void push(lua_State *s, T *object)
    {
        if (!object)
        {
            lua_pushnil(s);
        }
        else if (!UserDataCache::retrieve(s, object))
        {
            void *userData = lua_newuserdata(s, sizeof(T*));
            * static_cast<T**>(userData) = object;

#if LUA_VERSION_NUM < 502
            luaL_newmetatable(s, mTypeName);
            lua_setmetatable(s, -2);
#else
            luaL_setmetatable(s, mTypeName);
#endif

            UserDataCache::insert(s, object);
        }
    }

    /**
     * Returns the argument at position \a narg when it is of the right type,
     * and raises a Lua error otherwise.
     */
    static T *check(lua_State *L, int narg)
    {
        void *userData = luaL_checkudata(L, narg, mTypeName);
        return *(static_cast<T**>(userData));
    }

private:
    static const char *mTypeName;
};

template <typename T> const char * LuaUserData<T>::mTypeName;

typedef LuaUserData<Entity> LuaEntity;
typedef LuaUserData<ItemClass> LuaItemClass;
typedef LuaUserData<MapObject> LuaMapObject;
typedef LuaUserData<MonsterClass> LuaMonsterClass;
typedef LuaUserData<StatusEffect> LuaStatusEffect;
typedef LuaUserData<AbilityManager::AbilityInfo> LuaAbilityInfo;
typedef LuaUserData<AttributeInfo> LuaAttributeInfo;

Script *                               getScript(lua_State *s);

ItemClass *                            getItemClass(lua_State *s, int p);
MonsterClass *                         getMonsterClass(lua_State *s, int p);

Entity *                               checkActor(lua_State *s, int p);
Entity *                               checkBeing(lua_State *s, int p);
Entity *                               checkCharacter(lua_State *s, int p);
ItemClass *                            checkItemClass(lua_State *s, int p);
Entity *                               checkMonster(lua_State *s, int p);
MonsterClass *                         checkMonsterClass(lua_State *s, int p);
Entity *                               checkNpc(lua_State *s, int p);
AbilityManager::AbilityInfo *          checkAbility(lua_State *s, int p);
AttributeInfo *      checkAttribute(lua_State *s, int p);
unsigned char                          checkWalkMask(lua_State *s, int p);

MapComposite *  checkCurrentMap(lua_State *s, Script *script = 0);
Script::Thread* checkCurrentThread(lua_State *s, Script *script = 0);


/* Polymorphic wrapper for pushing variables.
   Useful for templates.*/

inline void push(lua_State *s, int val)
{
    lua_pushinteger(s, val);
}

inline void push(lua_State *s, const std::string &val)
{
    lua_pushlstring(s, val.c_str(), val.length());
}

inline void push(lua_State *s, Entity *val)
{
    LuaEntity::push(s, val);
}

inline void push(lua_State *s, double val)
{
    lua_pushnumber(s, val);
}

inline void push(lua_State *s, MapObject *val)
{
    LuaMapObject::push(s, val);
}

inline void push(lua_State *s, MonsterClass *val)
{
    LuaMonsterClass::push(s, val);
}

inline void push(lua_State *s, AttributeInfo *val)
{
    LuaAttributeInfo::push(s, val);
}


/*  Pushes an STL LIST */
template <typename T>
void pushSTLContainer(lua_State *s, const std::list<T> &container)
{
    int len = container.size();
    lua_createtable(s, len, 0);
    int table = lua_gettop(s);
    typename std::list<T>::const_iterator i;
    i = container.begin();

    for (int key = 1; key <= len; key++)
    {
        push(s, *i);
        lua_rawseti(s, table, key);
        ++i;
    }
}

/*  Pushes an STL VECTOR */
template <typename T>
void pushSTLContainer(lua_State *s, const std::vector<T> &container)
{
    int len = container.size();
    lua_createtable(s, len, 0);
    int table = lua_gettop(s);

    for (int key = 0; key < len; key++)
    {
        push(s, container.at(key));
        lua_rawseti(s, table, key + 1);
    }
}

/*  Pushes an STL MAP */
template <typename Tkey, typename Tval>
void pushSTLContainer(lua_State *s, const std::map<Tkey, Tval> &container)
{
    int len = container.size();
    lua_createtable(s, 0, len);
    int table = lua_gettop(s);
    typename std::map<Tkey, Tval>::const_iterator i;
    i = container.begin();

    for (int key = 1; key <= len; key++)
    {
        push(s, i->first);
        push(s, i->second);
        lua_settable(s, table);
        ++i;
    }
}

/*  Pushes an STL SET */
template <typename T>
void pushSTLContainer(lua_State *s, const std::set<T> &container)
{
    int len = container.size();
    lua_createtable(s, len, 0);
    int table = lua_gettop(s);
    typename std::set<T>::const_iterator i;
    i = container.begin();

    for (int key = 1; key <= len; key++)
    {
        push(s, *i);
        lua_rawseti(s, table, key);
        ++i;
    }
}

#endif