/// \file core.cpp
/// Core classes
#include <string.h>
#include <sstream>
#include "core.h"
extern "C" {
#include <lauxlib.h>
}
using namespace std;
#include <iostream>
namespace Board
{
template <class C> static int Trampoline(lua_State* state)
{
if(!lua_isuserdata(state, 1))
{
lua_pushstring(state, "native method called without object");
return lua_error(state);
}
C* obj = *(C**) lua_touserdata(state, 1);
int (C::*fn)(lua_State*) = *(int (C::**)(lua_State*)) lua_touserdata(state, lua_upvalueindex(1));
return (obj->*fn)(state);
}
static int RegisterWeakRef(lua_State* state)
{
lua_getfield(state, LUA_REGISTRYINDEX, "weakrefs");
if(lua_isnil(state, -1))
{
lua_pop(state, 1);
lua_createtable(state, 1, 0);
lua_createtable(state, 0, 1);
lua_pushstring(state, "kv");
lua_setfield(state, -2, "__mode");
lua_setmetatable(state, -2);
lua_pushvalue(state, -1);
lua_setfield(state, LUA_REGISTRYINDEX, "weakrefs");
}
lua_pushvalue(state, -2);
int refnum = luaL_ref(state, -2);
lua_pop(state, 1);
return refnum;
}
static void GetWeakRef(lua_State* state, int ref)
{
lua_getfield(state, LUA_REGISTRYINDEX, "weakrefs");
if(lua_isnil(state, -1))
return;
lua_pushinteger(state, ref);
lua_gettable(state, -2);
lua_remove(state, -2);
}
static void UnregisterWeakRef(lua_State* state, int ref)
{
lua_getfield(state, LUA_REGISTRYINDEX, "weakrefs");
if(lua_isnil(state, -1))
return;
luaL_unref(state, -1, ref);
}
void RegisterAll(lua_State* state)
{
Card::Register(state);
Pawn::Register(state);
Board::Register(state);
}
void Card::Register(lua_State* state)
{
int (Card::*func)(lua_State* state);
void* data;
lua_createtable(state, 0, 1);
lua_pushcfunction(state, &Card::New);
lua_setfield(state, -2, "new");
lua_setglobal(state, "Card");
}
int Card::New(lua_State* state)
{
int (Card::*func)(lua_State* state);
void* data;
if(lua_gettop(state) != 4)
{
lua_pushstring(state, "wrong number of arguments");
return lua_error(state);
}
// Get parameters
string name = lua_tostring(state, 1);
int graphic = lua_tointeger(state, 2);
int level = lua_tointeger(state, 3);
// Create userdata
Card** c = (Card**) lua_newuserdata(state, sizeof(Card*));
*c = new Card(name, graphic, level);
// Set metatable
lua_createtable(state, 0, 2);
// __gc
func = &Card::Destroy;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Card>, 1);
lua_setfield(state, -2, "__gc");
// __index
lua_getglobal(state, "Card");
lua_setfield(state, -2, "__index");
// Apply metatable
lua_setmetatable(state, -2);
// Self reference
lua_pushvalue(state, -1);
(*c)->self = RegisterWeakRef(state);
return 1;
}
Card::Card(const string& name, int graphic, int level): name(name), graphic(graphic), level(level)
{
}
Card::~Card()
{
}
int Card::Destroy(lua_State* state)
{
UnregisterWeakRef(state, self);
delete this;
return 0;
}
void Pawn::Register(lua_State* state)
{
int (Pawn::*func)(lua_State* state);
void* data;
lua_createtable(state, 0, 1);
lua_pushcfunction(state, &Pawn::New);
lua_setfield(state, -2, "new");
func = &Pawn::SetHand;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Pawn>, 1);
lua_setfield(state, -2, "SetHand");
func = &Pawn::GetDataTable;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Pawn>, 1);
lua_setfield(state, -2, "GetDataTable");
lua_setglobal(state, "Pawn");
}
int Pawn::New(lua_State* state)
{
int (Pawn::*func)(lua_State* state);
void* data;
// Create userdata
Pawn** p = (Pawn**) lua_newuserdata(state, sizeof(Pawn*));
*p = new Pawn();
// Set metatable
lua_createtable(state, 0, 2);
// __gc
func = &Pawn::Destroy;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Pawn>, 1);
lua_setfield(state, -2, "__gc");
// __index
if(lua_getmetatable(state, 1) == 0)
lua_pushvalue(state, 1);
lua_setfield(state, -2, "__index");
// Apply metatable
lua_setmetatable(state, -2);
// Data member table
lua_pushvalue(state, -1);
lua_createtable(state, 0, 1);
lua_createtable(state, 2, 0);
lua_setfield(state, -2, "hand");
lua_createtable(state, 2, 0);
lua_setfield(state, -2, "data");
lua_settable(state, LUA_REGISTRYINDEX);
// Self reference
lua_pushvalue(state, -1);
(*p)->self = RegisterWeakRef(state);
return 1;
}
Pawn::Pawn()
{
}
int Pawn::SetHand(lua_State* state)
{
luaL_argcheck(state, lua_isuserdata(state, 1), 1, "SetHand");
luaL_argcheck(state, lua_istable(state, 2), 2, "SetHand");
lua_pushvalue(state, 1);
lua_gettable(state, LUA_REGISTRYINDEX);
lua_pushvalue(state, 2);
lua_setfield(state, -2, "hand");
lua_pop(state, 1);
hand.clear();
int i = 1;
while(true)
{
lua_pushinteger(state, i);
lua_gettable(state, 2);
if(!lua_isuserdata(state, -1))
break;
Card* c = *(Card**) lua_touserdata(state, -1);
hand.push_back(c);
i++;
}
return 0;
}
int Pawn::GetDataTable(lua_State* state)
{
luaL_argcheck(state, lua_isuserdata(state, 1), 1, "GetDataTable");
lua_gettable(state, LUA_REGISTRYINDEX);
lua_getfield(state, 1, "data");
return 1;
}
int Pawn::Destroy(lua_State* state)
{
UnregisterWeakRef(state, self);
delete this;
return 0;
}
void Board::Register(lua_State* state)
{
int (Board::*func)(lua_State* state);
void* data;
lua_createtable(state, 0, 1);
func = &Board::SetPlayers;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Board>, 1);
lua_setfield(state, -2, "SetPlayers");
func = &Board::RegisterCard;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Board>, 1);
lua_setfield(state, -2, "RegisterCard");
func = &Board::GetPlayers;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Board>, 1);
lua_setfield(state, -2, "GetPlayers");
func = &Board::GetRandomCard;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Board>, 1);
lua_setfield(state, -2, "GetRandomCard");
lua_setglobal(state, "Board");
}
Board* Board::CreateInstance(lua_State* state)
{
int (Board::*func)(lua_State* state);
void* data;
// Create userdata
Board** b = (Board**) lua_newuserdata(state, sizeof(Board*));
*b = new Board();
// Data member table
lua_pushvalue(state, -1);
lua_createtable(state, 0, 1);
// Create player list
lua_createtable(state, 2, 0);
lua_setfield(state, -2, "objects");
lua_settable(state, LUA_REGISTRYINDEX);
// Set metatable
lua_createtable(state, 0, 2);
// __gc
func = &Board::Destroy;
data = lua_newuserdata(state, sizeof(func));
memcpy(data, &func, sizeof(func));
lua_pushcclosure(state, Trampoline<Board>, 1);
lua_setfield(state, -2, "__gc");
// __index
lua_getglobal(state, "Board");
lua_setfield(state, -2, "__index");
// Apply metatable
lua_setmetatable(state, -2);
// Self reference
lua_pushvalue(state, -1);
(*b)->self = RegisterWeakRef(state);
// Register global
lua_setglobal(state, "board");
return *b;
}
Board::~Board()
{
}
void Board::Write(const string& message)
{
log.push_back(message);
if(log.size() > 16)
log.pop_front();
}
int Board::SetPlayers(lua_State* state)
{
luaL_argcheck(state, lua_isuserdata(state, 1), 1, "SetPlayers");
luaL_argcheck(state, lua_istable(state, 2), 2, "SetPlayers");
objects.clear();
lua_pushvalue(state, 1);
lua_gettable(state, LUA_REGISTRYINDEX);
lua_getfield(state, -1, "objects");
lua_pushinteger(state, 1);
lua_pushinteger(state, 1);
lua_gettable(state, 2);
if(!lua_isuserdata(state, -1))
{
lua_pushstring(state, "Passed non-userdata as player");
return lua_error(state);
}
objects.push_back(*(Pawn**) lua_touserdata(state, -1));
lua_settable(state, -3);
lua_pushinteger(state, 2);
lua_pushinteger(state, 2);
lua_gettable(state, 2);
if(!lua_isuserdata(state, -1))
{
lua_pushstring(state, "Passed non-userdata as player");
return lua_error(state);
}
objects.push_back(*(Pawn**) lua_touserdata(state, -1));
lua_settable(state, -3);
return 0;
}
int Board::RegisterCard(lua_State* state)
{
if(lua_gettop(state) != 2)
{
lua_pushstring(state, "wrong number of arguments to native function");
return lua_error(state);
}
Card* c = *(Card**) lua_touserdata(state, 2);
lua_pop(state, 1);
cards.push_back(c);
return 0;
}
int Board::GetPlayers(lua_State* state)
{
if(lua_gettop(state) != 1)
{
lua_pushstring(state, "wrong number of arguments to native function");
return lua_error(state);
}
if(objects.size() < 2)
return 0;
GetWeakRef(state, objects[0]->self);
GetWeakRef(state, objects[1]->self);
return 2;
}
int Board::GetRandomCard(lua_State* state)
{
if(lua_gettop(state) != 2)
{
lua_pushstring(state, "wrong number of arguments to native function");
return lua_error(state);
}
if(cards.size() == 0)
{
lua_pushnil(state);
return 1;
}
int level = lua_tointeger(state, 2);
int firstCard = rand() % cards.size();
for(int i = firstCard; i < cards.size(); i++)
{
if(cards[i]->level == level)
{
GetWeakRef(state, cards[i]->self);
return 1;
}
}
for(int i = 0; i < firstCard; i++)
{
if(cards[i]->level == level)
{
GetWeakRef(state, cards[i]->self);
return 1;
}
}
lua_pushnil(state);
return 1;
}
int Board::Destroy(lua_State* state)
{
UnregisterWeakRef(state, self);
delete this;
return 0;
}
}
// The end