new script engine, and things maybe be bugged for a while

This commit is contained in:
Eduardo Bart
2011-07-26 20:13:27 -03:00
parent ab7394f357
commit 70f0b0dace
137 changed files with 2905 additions and 2578 deletions

View File

@@ -4,6 +4,7 @@
#include <global.h>
struct ConfigValueProxy {
ConfigValueProxy(const std::string& v) : value(v) { }
operator std::string() const { return convert<std::string>(value); }
operator float() const { return convert<float>(value); }
operator int() const { return convert<int>(value); }
@@ -20,7 +21,7 @@ public:
template<class T>
void set(const std::string& key, const T& value) { m_confsMap[key] = convert<std::string>(value); }
ConfigValueProxy get(const std::string& key) { return ConfigValueProxy{m_confsMap[key]}; }
ConfigValueProxy get(const std::string& key) { return ConfigValueProxy(m_confsMap[key]); }
private:
std::string m_fileName;

View File

@@ -29,12 +29,12 @@ void Dispatcher::poll()
}
}
void Dispatcher::scheduleTask(const boost::function<void()>& callback, int delay)
void Dispatcher::scheduleTask(const std::function<void()>& callback, int delay)
{
m_scheduledTaskList.push(new ScheduledTask(g_engine.getCurrentFrameTicks() + delay, callback));
}
void Dispatcher::addTask(const boost::function<void()>& callback, bool pushFront)
void Dispatcher::addTask(const std::function<void()>& callback, bool pushFront)
{
if(pushFront)
m_taskList.push_front(callback);

View File

@@ -4,15 +4,12 @@
#include <global.h>
#include <queue>
#include <boost/bind.hpp>
#include <boost/function.hpp>
struct ScheduledTask {
ScheduledTask(const boost::function<void()>& _callback) : ticks(0), callback(_callback) { }
ScheduledTask(int _ticks, const boost::function<void()>& _callback) : ticks(_ticks), callback(_callback) { }
ScheduledTask(const std::function<void()>& _callback) : ticks(0), callback(_callback) { }
ScheduledTask(int _ticks, const std::function<void()>& _callback) : ticks(_ticks), callback(_callback) { }
bool operator<(const ScheduledTask& other) const { return ticks > other.ticks; }
int ticks;
boost::function<void()> callback;
std::function<void()> callback;
};
struct lessScheduledTask : public std::binary_function<ScheduledTask*&, ScheduledTask*&, bool> {
@@ -31,13 +28,13 @@ public:
void poll();
/// Add an event
void addTask(const boost::function<void()>& callback, bool pushFront = false);
void addTask(const std::function<void()>& callback, bool pushFront = false);
/// Schedula an event
void scheduleTask(const boost::function<void()>& callback, int delay);
void scheduleTask(const std::function<void()>& callback, int delay);
private:
std::list<boost::function<void()>> m_taskList;
std::list<std::function<void()>> m_taskList;
std::priority_queue<ScheduledTask*, std::vector<ScheduledTask*>, lessScheduledTask> m_scheduledTaskList;
};

View File

@@ -6,7 +6,7 @@
#include <graphics/textures.h>
#include <ui/uicontainer.h>
#include <ui/uiskins.h>
#include <script/scriptcontext.h>
#include <script/luainterface.h>
#include <net/connection.h>
Engine g_engine;
@@ -113,7 +113,7 @@ void Engine::stop()
void Engine::onClose()
{
g_dispatcher.addTask(boost::bind(&ScriptContext::callModuleField, &g_lua, "App", "onClose"));
g_lua.getGlobal("onClose")->call("onClose");
}
void Engine::onResize(const Size& size)

View File

@@ -1,2 +0,0 @@
#include "modules.h"

View File

@@ -1,8 +0,0 @@
#ifndef MODULES_H
#define MODULES_H
class Modules
{
};
#endif // MODULES_H

View File

@@ -0,0 +1,29 @@
#include "packages.h"
#include <core/resources.h>
#include <script/luainterface.h>
Packages g_packages;
void Packages::loadPackages()
{
std::list<std::string> packages = g_resources.listDirectoryFiles("modules");
foreach(const std::string& package, packages) {
std::string dir = make_string("modules/", package);
g_resources.pushCurrentPath(dir);
std::list<std::string> packagesFiles = g_resources.listDirectoryFiles();
foreach(const std::string& packageFile, packagesFiles) {
if(boost::ends_with(packageFile, ".lua")) {
g_lua.runScript(packageFile);
}
}
g_resources.popCurrentPath();
}
}
void Packages::terminate()
{
}

View File

@@ -0,0 +1,15 @@
#ifndef PACKAGES_H
#define PACKAGES_H
#include <global.h>
class Packages
{
public:
void loadPackages();
void terminate();
};
extern Packages g_packages;
#endif // MODULES_H

View File

@@ -2,7 +2,6 @@
#include "resources.h"
#include "platform.h"
#include <boost/algorithm/string.hpp>
#include <physfs.h>
Resources g_resources;
@@ -148,12 +147,15 @@ std::list<std::string> Resources::listDirectoryFiles(const std::string& director
void Resources::pushCurrentPath(const std::string &currentPath)
{
//logTraceDebug(currentPath);
m_currentPaths.push(currentPath);
}
void Resources::popCurrentPath()
{
m_currentPaths.pop();
//if(!m_currentPaths.empty())
// logTraceDebug(m_currentPaths.top());
}
std::string Resources::resolvePath(const std::string& path)

View File

@@ -16,13 +16,17 @@
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <algorithm>
#include <exception>
#include <memory>
#include <type_traits>
#include <functional>
#include <regex>
// smart pointers
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
// string algorithms
#include <boost/algorithm/string.hpp>
// constants
#include <const.h>
@@ -41,5 +45,6 @@
#include <util/foreach.h>
#include <util/makestring.h>
#include <util/logger.h>
#include <util/algorithms.h>
#endif // GLOBAL_H

View File

@@ -44,7 +44,7 @@ AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFra
}
m_currentFrame = -1;
g_dispatcher.scheduleTask(boost::bind(&AnimatedTexture::processAnimation, this), 0);
g_dispatcher.scheduleTask(std::bind(&AnimatedTexture::processAnimation, this), 0);
}
AnimatedTexture::~AnimatedTexture()
@@ -70,7 +70,7 @@ void AnimatedTexture::processAnimation()
if(m_currentFrame >= m_numFrames)
m_currentFrame = 0;
m_textureId = m_framesTextureId[m_currentFrame];
AnimatedTexturePtr me = boost::static_pointer_cast<AnimatedTexture>(shared_from_this());
AnimatedTexturePtr me = std::static_pointer_cast<AnimatedTexture>(shared_from_this());
if(me.use_count() > 1)
g_dispatcher.scheduleTask(boost::bind(&AnimatedTexture::processAnimation, me), m_framesDelay[m_currentFrame]);
g_dispatcher.scheduleTask(std::bind(&AnimatedTexture::processAnimation, me), m_framesDelay[m_currentFrame]);
}

View File

@@ -45,7 +45,7 @@ private:
int m_lastAnimCheckTicks;
};
typedef boost::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef boost::weak_ptr<AnimatedTexture> AnimatedTextureWeakPtr;
typedef std::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef std::weak_ptr<AnimatedTexture> AnimatedTextureWeakPtr;
#endif // ANIMATEDTEXTURE_H

View File

@@ -96,13 +96,13 @@ BorderedImagePtr BorderedImage::loadFromOTMLNode(OTMLNode* node, TexturePtr defa
left = node->readAt("left", left);
right = node->readAt("right", right);
leftBorder = Rect(subRect.left(), subRect.top() + top, left, subRect.height() - top - bottom);
rightBorder = Rect(subRect.right() - right, subRect.top() + top, right, subRect.height() - top - bottom);
rightBorder = Rect(subRect.right() - right + 1, subRect.top() + top, right, subRect.height() - top - bottom);
topBorder = Rect(subRect.left() + left, subRect.top(), subRect.width() - right - left, top);
bottomBorder = Rect(subRect.left() + left, subRect.bottom() - bottom, subRect.width() - right - left, bottom);
bottomBorder = Rect(subRect.left() + left, subRect.bottom() - bottom + 1, subRect.width() - right - left, bottom);
topLeftCorner = Rect(subRect.left(), subRect.top(), left, top);
topRightCorner = Rect(subRect.right() - right, subRect.top(), right, top);
topRightCorner = Rect(subRect.right() - right + 1, subRect.top(), right, top);
bottomLeftCorner = Rect(subRect.left(), subRect.bottom() - bottom, left, bottom);
bottomRightCorner = Rect(subRect.right() - right, subRect.bottom() - bottom, right, bottom);
bottomRightCorner = Rect(subRect.right() - right + 1, subRect.bottom() - bottom + 1, right, bottom);
center = Rect(subRect.left() + left, subRect.top() + top, subRect.width() - right - left, subRect.height() - top - bottom);
leftBorder = node->readAt("left border", leftBorder);
rightBorder = node->readAt("right border", rightBorder);

View File

@@ -31,7 +31,7 @@
#include <otml/otmlnode.h>
class BorderedImage;
typedef boost::shared_ptr<BorderedImage> BorderedImagePtr;
typedef std::shared_ptr<BorderedImage> BorderedImagePtr;
class BorderedImage : public Image
{

View File

@@ -1,27 +1,3 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* 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.
*/
#include <global.h>
#include <core/resources.h>
#include <graphics/font.h>
@@ -54,6 +30,7 @@ void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
// if all pixels were alpha we found the width
if(columnFilledPixels == 0) {
width = x - glyphCoords.left();
width += m_glyphSpacing.width();
if(m_glyphHeight >= 16 && lastColumnFilledPixels >= m_glyphHeight/3)
width += 1;
break;
@@ -84,11 +61,11 @@ bool Font::load(const std::string& file)
// required values
textureName = doc->valueAt("image");
glyphSize = doc->readAt("image glyph size", Size(16, 16));
m_glyphHeight = doc->readAt("glyph height", 11);
m_firstGlyph = doc->readAt("first glyph", 32);
m_topMargin = doc->readAt("top margin", 0);
m_glyphSpacing = doc->readAt("glyph spacing", Size(0,0));
glyphSize = doc->readAt("image-glyph-size", Size(16, 16));
m_glyphHeight = doc->readAt("glyph-height", 11);
m_firstGlyph = doc->readAt("first-glyph", 32);
m_topMargin = doc->readAt("top-margin", 0);
m_glyphSpacing = doc->readAt("glyph-spacing", Size(0,0));
// load texture
m_texture = g_textures.get(textureName);
@@ -101,16 +78,16 @@ bool Font::load(const std::string& file)
calculateGlyphsWidthsAutomatically(glyphSize);
// read custom widths
if(doc->hasChild("glyph widths")) {
if(doc->hasChild("glyph-widths")) {
std::map<int, int> glyphWidths;
doc->readAt("glyph widths", &glyphWidths);
doc->readAt("glyph-widths", &glyphWidths);
foreach(const auto& pair, glyphWidths)
m_glyphsSize[pair.first].setWidth(pair.second);
}
// calculate glyphs texture coords
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
for(int glyph = m_firstGlyph; glyph< 256; ++glyph) {
for(int glyph = m_firstGlyph; glyph < 256; ++glyph) {
m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
m_glyphsSize[glyph].width(),
@@ -248,7 +225,7 @@ const std::vector<Point>& Font::calculateGlyphsPositions(const std::string& text
lineWidths.resize(lines+1);
lineWidths[lines] = 0;
} else if(glyph >= 32) {
lineWidths[lines] += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
lineWidths[lines] += m_glyphsSize[glyph].width();
maxLineWidth = std::max(maxLineWidth, lineWidths[lines]);
}
}
@@ -281,7 +258,7 @@ const std::vector<Point>& Font::calculateGlyphsPositions(const std::string& text
// render only if the glyph is valid
if(glyph >= 32 && glyph != (uchar)'\n') {
virtualPos.x += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
virtualPos.x += m_glyphsSize[glyph].width();
}
}

View File

@@ -75,6 +75,6 @@ private:
Size m_glyphsSize[256];
};
typedef boost::shared_ptr<Font> FontPtr;
typedef std::shared_ptr<Font> FontPtr;
#endif // FONT_H

View File

@@ -1,32 +1,7 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* 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.
*/
#include <global.h>
#include <core/resources.h>
#include <graphics/fonts.h>
#include <boost/algorithm/string.hpp>
Fonts g_fonts;

View File

@@ -44,6 +44,6 @@ protected:
Rect m_textureCoords;
};
typedef boost::shared_ptr<Image> ImagePtr;
typedef std::shared_ptr<Image> ImagePtr;
#endif // IMAGE_H

View File

@@ -27,7 +27,7 @@
#include <global.h>
class Texture : public boost::enable_shared_from_this<Texture>
class Texture : public std::enable_shared_from_this<Texture>
{
public:
/// Create a texture, width and height must be a multiple of 2
@@ -55,7 +55,7 @@ protected:
Size m_glSize;
};
typedef boost::shared_ptr<Texture> TexturePtr;
typedef boost::weak_ptr<Texture> TextureWeakPtr;
typedef std::shared_ptr<Texture> TexturePtr;
typedef std::weak_ptr<Texture> TextureWeakPtr;
#endif // TEXTURE_H

View File

@@ -28,8 +28,6 @@
#include <graphics/textureloader.h>
#include <core/dispatcher.h>
#include <boost/algorithm/string.hpp>
Textures g_textures;
TexturePtr Textures::get(const std::string& textureFile)

View File

@@ -40,61 +40,57 @@ void Connection::poll()
ioService.reset();
}
void Connection::connect(const std::string& host, uint16 port, const boost::function<void()>& connectCallback)
void Connection::connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback)
{
m_connectCallback = connectCallback;
m_connectionState = CONNECTION_STATE_RESOLVING;
boost::asio::ip::tcp::resolver::query query(host, convert<std::string>(port));
m_resolver.async_resolve(query, boost::bind(&Connection::onResolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator));
m_resolver.async_resolve(query, std::bind(&Connection::onResolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
m_timer.expires_from_now(boost::posix_time::seconds(2));
m_timer.async_wait(boost::bind(&Connection::onTimeout, shared_from_this(), boost::asio::placeholders::error));
m_timer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));
}
void Connection::send(OutputMessage *outputMessage)
{
boost::asio::async_write(m_socket,
boost::asio::buffer(outputMessage->getBuffer(), outputMessage->getMessageSize()),
boost::bind(&Connection::onSend, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
std::bind(&Connection::onSend, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
m_timer.expires_from_now(boost::posix_time::seconds(2));
m_timer.async_wait(boost::bind(&Connection::onTimeout, shared_from_this(), boost::asio::placeholders::error));
m_timer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));
}
void Connection::onTimeout(const boost::system::error_code& error)
{
if(error != boost::asio::error::operation_aborted)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
}
void Connection::onResolve(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
trace();
m_timer.cancel();
if(error) {
if(m_errorCallback)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
return;
}
m_socket.async_connect(*endpointIterator, boost::bind(&Connection::onConnect, shared_from_this(), boost::asio::placeholders::error));
m_socket.async_connect(*endpointIterator, std::bind(&Connection::onConnect, shared_from_this(), std::placeholders::_1));
m_timer.expires_from_now(boost::posix_time::seconds(2));
m_timer.async_wait(boost::bind(&Connection::onTimeout, shared_from_this(), boost::asio::placeholders::error));
m_timer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1));
}
void Connection::onConnect(const boost::system::error_code& error)
{
trace();
m_timer.cancel();
if(error) {
if(m_errorCallback)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
return;
}
@@ -103,29 +99,25 @@ void Connection::onConnect(const boost::system::error_code& error)
// Start listening.
boost::asio::async_read(m_socket,
boost::asio::buffer(m_inputMessage.getBuffer(), InputMessage::HEADER_LENGTH),
boost::bind(&Connection::onRecvHeader, shared_from_this(), boost::asio::placeholders::error));
std::bind(&Connection::onRecvHeader, shared_from_this(), std::placeholders::_1));
}
void Connection::onSend(const boost::system::error_code& error, size_t)
{
trace();
m_timer.cancel();
if(error) {
if(m_errorCallback)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
return;
}
}
void Connection::onRecvHeader(const boost::system::error_code& error)
{
trace();
if(error) {
if(m_errorCallback)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
return;
}
@@ -134,16 +126,14 @@ void Connection::onRecvHeader(const boost::system::error_code& error)
boost::asio::async_read(m_socket,
boost::asio::buffer(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, messageSize),
boost::bind(&Connection::onRecvData, shared_from_this(), boost::asio::placeholders::error));
std::bind(&Connection::onRecvData, shared_from_this(), std::placeholders::_1));
}
void Connection::onRecvData(const boost::system::error_code& error)
{
trace();
if(error) {
if(m_errorCallback)
g_dispatcher.addTask(boost::bind(m_errorCallback, error));
g_dispatcher.addTask(std::bind(m_errorCallback, error));
return;
}
@@ -151,7 +141,7 @@ void Connection::onRecvData(const boost::system::error_code& error)
// must be called outside dispatcher cause of inputmessage.
if(m_recvCallback)
m_recvCallback(&m_inputMessage);
//g_dispatcher.addTask(boost::bind(m_recvCallback, &m_inputMessage));
//g_dispatcher.addTask(std::bind(m_recvCallback, &m_inputMessage));
// keep reading
@@ -159,6 +149,6 @@ void Connection::onRecvData(const boost::system::error_code& error)
/*m_inputMessage.reset();
boost::asio::async_read(m_socket,
boost::asio::buffer(m_inputMessage.getBuffer(), InputMessage::HEADER_LENGTH),
boost::bind(&Connection::onRecvHeader, shared_from_this(), boost::asio::placeholders::error));*/
std::bind(&Connection::onRecvHeader, shared_from_this(), std::placeholders::_1));*/
}

View File

@@ -31,19 +31,18 @@
#include <net/outputmessage.h>
#include <boost/asio.hpp>
#include <boost/function.hpp>
typedef boost::function<void(boost::system::error_code&)> ErrorCallback;
typedef boost::function<void(InputMessage*)> RecvCallback;
typedef std::function<void(boost::system::error_code&)> ErrorCallback;
typedef std::function<void(InputMessage*)> RecvCallback;
class Connection : public boost::enable_shared_from_this<Connection>, boost::noncopyable
class Connection : public std::enable_shared_from_this<Connection>, boost::noncopyable
{
public:
Connection();
static void poll();
void connect(const std::string& host, uint16 port, const boost::function<void()>& connectCallback);
void connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback);
void send(OutputMessage *outputMessage);
void setErrorCallback(const ErrorCallback& errorCallback) { m_errorCallback = errorCallback; }
@@ -66,7 +65,7 @@ public:
private:
ErrorCallback m_errorCallback;
RecvCallback m_recvCallback;
boost::function<void()> m_connectCallback;
std::function<void()> m_connectCallback;
ConnectionState_t m_connectionState;
boost::asio::deadline_timer m_timer;
@@ -76,6 +75,6 @@ private:
};
typedef boost::shared_ptr<Connection> ConnectionPtr;
typedef std::shared_ptr<Connection> ConnectionPtr;
#endif

View File

@@ -29,12 +29,12 @@
Protocol::Protocol() :
m_connection(new Connection)
{
m_connection->setErrorCallback(boost::bind(&Protocol::onError, this, _1));
m_connection->setRecvCallback(boost::bind(&Protocol::onRecv, this, _1));
m_connection->setErrorCallback(std::bind(&Protocol::onError, this, std::placeholders::_1));
m_connection->setRecvCallback(std::bind(&Protocol::onRecv, this, std::placeholders::_1));
m_xteaEncryptionEnabled = false;
}
void Protocol::connect(const std::string& host, uint16 port, const boost::function<void()>& callback)
void Protocol::connect(const std::string& host, uint16 port, const std::function<void()>& callback)
{
m_connection->connect(host, port, callback);
}

View File

@@ -28,7 +28,7 @@
#include <net/connection.h>
#include <net/inputmessage.h>
#include <net/outputmessage.h>
#include <script/scriptobject.h>
#include <script/luaobject.h>
#define CIPSOFT_PUBLIC_RSA "1321277432058722840622950990822933849527763264961655079678763618" \
"4334395343554449668205332383339435179772895415509701210392836078" \
@@ -38,18 +38,18 @@
//#define RSA "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"
class Protocol : public ScriptObject
class Protocol : public LuaObject
{
public:
Protocol();
void connect(const std::string& host, uint16 port, const boost::function<void()>& callback);
void connect(const std::string& host, uint16 port, const std::function<void()>& callback);
void send(OutputMessage *outputMessage);
virtual void onRecv(InputMessage *inputMessage);
virtual void onError(const boost::system::error_code& err);
virtual const char *getScriptObjectType() const { return "Protocol"; }
virtual const char* getLuaTypeName() const { return "Protocol"; }
protected:
uint32 m_xteaKey[4];
@@ -63,6 +63,6 @@ private:
ConnectionPtr m_connection;
};
typedef boost::shared_ptr<Protocol> ProtocolPtr;
typedef std::shared_ptr<Protocol> ProtocolPtr;
#endif

View File

@@ -44,6 +44,6 @@ protected:
mpz_t m_p, m_q, m_u, m_d, m_dp, m_dq, m_mod;
};
typedef boost::shared_ptr<Rsa> RsaPtr;
typedef std::shared_ptr<Rsa> RsaPtr;
#endif //RSA_H

View File

@@ -0,0 +1,191 @@
#ifndef LUABINDER_H
#define LUABINDER_H
#include "luavalue.h"
#include "luastate.h"
namespace luabinder
{
// transform const T& -> T
template<typename T>
struct remove_const_ref {
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};
// pack an value into tuple recursively
template<int N>
struct pack_values_into_tuple {
template<typename Tuple>
static void call(Tuple& tuple, LuaState* lua) {
typedef typename std::tuple_element<N-1, Tuple>::type ValueType;
std::get<N-1>(tuple) = safe_luavalue_cast<ValueType>(lua->popValue());
pack_values_into_tuple<N-1>::call(tuple, lua);
}
};
template<>
struct pack_values_into_tuple<0> {
template<typename Tuple>
static void call(Tuple &tuple, LuaState* lua) { }
};
// call function
template<typename Ret, typename F, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaState* lua, Args... args) {
Ret ret = f(args...);
lua->pushValue(safe_to_luavalue(ret));
return 1;
}
// call function with no return
template<typename Ret, typename F, typename... Args>
typename std::enable_if<std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaState* lua, Args... args) {
f(args...);
return 0;
}
// expand function arguments for calling
template<int N, typename Ret>
struct expand_fun_arguments {
template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) {
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...);
}
};
template<typename Ret>
struct expand_fun_arguments<0,Ret> {
template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) {
return call_fun_and_push_result<Ret>(f, lua, args...);
}
};
// bind different types of functions
template<typename Ret, typename F, typename Tuple>
LuaCppFunction bind_fun_specializer(const F& f) {
enum { N = std::tuple_size<Tuple>::value };
return [=](LuaState* lua) {
if(lua->stackSize() != N)
throw LuaBadNumberOfArgumentsException(N, lua->stackSize());
Tuple tuple;
pack_values_into_tuple<N>::call(tuple, lua);
return expand_fun_arguments<N,Ret>::call(tuple, f, lua);
};
}
// bind a std::function
template<typename Ret, typename... Args>
LuaCppFunction bind_fun(const std::function<Ret(Args...)>& f) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
// bind a custumized function
inline
LuaCppFunction bind_fun(const std::function<int(LuaState*)>& f) {
return f;
}
// convert to std::function then bind
template<typename Ret, typename... Args>
LuaCppFunction bind_fun(Ret (*f)(Args...)) {
return bind_fun(std::function<Ret(Args...)>(f));
}
// a tuple_element that works with the next algorithm
template<std::size_t __i, typename _Tp>
struct tuple_element;
template<std::size_t __i, typename _Head, typename... _Tail>
struct tuple_element<__i, std::tuple<_Head, _Tail...> >
: tuple_element<__i - 1, std::tuple<_Tail...> > { };
template<typename _Head, typename... _Tail>
struct tuple_element<0, std::tuple<_Head, _Tail...> > { typedef _Head type; };
template<typename _Head>
struct tuple_element<-1,std::tuple<_Head>> { typedef void type; };
template<std::size_t __i>
struct tuple_element<__i,std::tuple<>> { typedef void type; };
// rebind functions already binded by std::bind that have placeholders
template<typename Enable, int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple;
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<typename std::enable_if<(N > 0 && std::is_placeholder<typename tuple_element<N-1, HoldersTuple>::type>::value > 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> {
typedef typename std::tuple_element<N-1, HoldersTuple>::type holder_type;
typedef typename tuple_element<std::is_placeholder<holder_type>::value-1, ArgsTuple>::type _arg_type;
typedef typename remove_const_ref<_arg_type>::type arg_type;
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, arg_type, Args...>::type type;
};
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<typename std::enable_if<(N > 0 && std::is_placeholder<typename tuple_element<N-1, HoldersTuple>::type>::value == 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> {
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, Args...>::type type;
};
template<typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<void, 0, ArgsTuple, HoldersTuple, Args...> {
typedef typename std::tuple<Args...> type;
};
template<typename Ret, typename... Args, typename... Holders>
LuaCppFunction bind_fun(const std::_Bind<Ret (*(Holders...))(Args...)>& f) {
typedef typename std::tuple<Args...> ArgsTuple;
typedef typename std::tuple<Holders...> HoldersTuple;
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
template<typename Obj, typename Ret, typename... Args, typename... Holders>
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<Ret (Obj::*)(Args...)>(Obj*, Holders...)>& f) {
typedef typename std::tuple<Args...> ArgsTuple;
typedef typename std::tuple<Holders...> HoldersTuple;
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
// custumized functions already binded by std::bind doesn't need to be bind again
template<typename Obj>
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<int (Obj::*)(LuaState*)>(Obj*, std::_Placeholder<1>)>& f) {
return f;
}
inline
LuaCppFunction bind_fun(const std::_Bind<int (*(std::_Placeholder<1>))(LuaState*)>& f) {
return f;
}
// bind member function
template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf),
Tuple>(mf);
}
template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) {
auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf),
Tuple>(mf);
}
// bind custumized member function
template<typename Obj>
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaState*)) {
auto mf = std::mem_fn(f);
return [=](LuaState* lua) {
lua->insert(1);
auto obj = safe_luavalue_cast<Obj*>(lua->popValue());
return mf(obj, lua);
};
}
}
#endif // LUABINDER_H

View File

@@ -0,0 +1,19 @@
#ifndef LUADECLARATIONS_H
#define LUADECLARATIONS_H
#include <global.h>
class LuaInterface;
class LuaState;
class LuaValue;
class LuaObject;
typedef std::function<int(LuaState*)> LuaCppFunction;
typedef std::shared_ptr<LuaCppFunction> LuaCppFunctionPtr;
typedef std::shared_ptr<LuaValue> LuaValuePtr;
typedef std::shared_ptr<LuaObject> LuaObjectPtr;
typedef std::vector<LuaValuePtr> LuaValueList;
#endif // LUADECLARATIONS_H

View File

@@ -0,0 +1,39 @@
#include "luaexception.h"
#include "luainterface.h"
LuaException::LuaException(const std::string& error, int traceLevel)
{
generateLuaErrorMessage(error, traceLevel);
}
void LuaException::generateLuaErrorMessage(const std::string& error, int traceLevel)
{
// clear stack, to prevent further errors
g_lua.clearStack();
// append trace level to error message
if(traceLevel >= 0)
m_what = make_string("LUA ERROR: ", g_lua.getTraceback(error, traceLevel));
else
m_what = make_string("LUA ERROR: ", error);
}
LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got)
{
std::string error = "attempt to call a function with wrong number of arguments";
if(expected >= 0 && got >= 0)
error = make_string(error, " (expected ", expected, ", but got ", got, ")");
generateLuaErrorMessage(error, 1);
}
LuaBadTypeConversinException::LuaBadTypeConversinException(const std::string& typeName)
{
std::string error = make_string("attempt to convert ", typeName, " to a lua value");
generateLuaErrorMessage(error, 0);
}
LuaBadValueCastException::LuaBadValueCastException(const LuaValuePtr& value, const std::string& typeName)
{
std::string error = make_string("attempt to cast a ", value->getTypeName(), " lua value to ", typeName);
generateLuaErrorMessage(error, 0);
}

View File

@@ -0,0 +1,38 @@
#ifndef LUAEXCEPTION_H
#define LUAEXCEPTION_H
#include "luadeclarations.h"
/// LuaException, all lua errors are throwed by it
class LuaException : public std::exception
{
public:
LuaException(const std::string& error, int traceLevel = -1);
virtual ~LuaException() throw() { };
void generateLuaErrorMessage(const std::string& error, int traceLevel);
virtual const char* what() const throw() { return m_what.c_str(); }
protected:
LuaException() { }
std::string m_what;
};
class LuaBadNumberOfArgumentsException : public LuaException {
public:
LuaBadNumberOfArgumentsException(int expected = -1, int got = -1);
};
class LuaBadTypeConversinException : public LuaException {
public:
LuaBadTypeConversinException(const std::string& typeName = "an incompatible lua type");
};
class LuaBadValueCastException : public LuaException {
public:
LuaBadValueCastException(const LuaValuePtr& value, const std::string& typeName = "an incompatible lua type");
};
#endif

View File

@@ -0,0 +1,54 @@
#include "luainterface.h"
#include <core/engine.h>
#include <ui/ui.h>
#include "../../protocollogin.h"
void LuaInterface::registerFunctions()
{
g_lua.bindGlobalFunction("exit", std::bind(&Engine::stop, &g_engine));
g_lua.bindGlobalFunction("loadUI", std::bind(&UILoader::loadFromFile, &g_uiLoader, std::placeholders::_1, std::placeholders::_2));
g_lua.setGlobal("rootUI", safe_to_luavalue(UIContainer::getRoot()));
g_lua.registerClass("UIElement");
g_lua.bindClassStaticFunction("UIElement", "new", &UIElement::create);
g_lua.bindClassMemberField("UIElement", "id", &UIElement::getId, &UIElement::setId);
g_lua.bindClassMemberField("UIElement", "enabled", &UIElement::isEnabled, &UIElement::setEnabled);
g_lua.bindClassMemberField("UIElement", "visible", &UIElement::isVisible, &UIElement::setVisible);
g_lua.bindClassMemberField("UIElement", "focused", &UIElement::isFocused, &UIElement::setFocused);
g_lua.bindClassMemberField("UIElement", "width", &UIElement::getWidth, &UIElement::setWidth);
g_lua.bindClassMemberField("UIElement", "height", &UIElement::getHeight, &UIElement::setHeight);
g_lua.bindClassMemberField("UIElement", "parent", &UIElement::getParent, &UIElement::setParent);
g_lua.bindClassMemberFunction("UIElement", "setLocked", &UIElement::setLocked);
//g_lua.bindClassMemberFunction("UIElement", "setMargin", &UIElement::luaSetMargin);
g_lua.bindClassMemberFunction("UIElement", "destroy", &UIElement::destroyLater);
g_lua.bindClassMemberFunction("UIElement", "centerIn", &UIElement::centerIn);
g_lua.bindClassMemberFunction("UIElement", "addAnchor", &UIElement::addAnchor);
g_lua.registerClass("UIContainer", "UIElement");
g_lua.bindClassStaticFunction("UIContainer", "create", &UIContainer::create);
g_lua.bindClassMemberFunction("UIContainer", "getChild", &UIContainer::getChildById);
//g_lua.bindClassMemberFunction("UIContainer", "children", &UIContainer::getChildren);
g_lua.bindClassMemberFunction("UIContainer", "addChild", &UIContainer::addChild);
g_lua.registerClass("UILabel", "UIElement");
g_lua.bindClassStaticFunction("UILabel", "create", &UILabel::create);
g_lua.bindClassMemberField("UILabel", "text", &UILabel::getText, &UILabel::setText);
g_lua.registerClass("UIButton", "UIElement");
g_lua.bindClassStaticFunction("UIButton", "create", &UIButton::create);
g_lua.bindClassMemberField("UIButton", "text", &UIButton::getText, &UIButton::setText);
g_lua.registerClass("UITextEdit", "UIElement");
g_lua.bindClassStaticFunction("UITextEdit", "create", &UITextEdit::create);
g_lua.bindClassMemberField("UITextEdit", "text", &UITextEdit::getText, &UITextEdit::setText);
g_lua.registerClass("UIWindow", "UIContainer");
g_lua.bindClassStaticFunction("UIWindow", "create", &UIWindow::create);
g_lua.bindClassMemberField("UIWindow", "title", &UIWindow::getTitle, &UIWindow::setTitle);
g_lua.registerClass("Protocol");
g_lua.registerClass("ProtocolLogin", "Protocol");
g_lua.bindClassStaticFunction("ProtocolLogin", "create", &ProtocolLogin::create);
g_lua.bindClassMemberFunction("ProtocolLogin", "login", &ProtocolLogin::login);
g_lua.bindClassMemberFunction("ProtocolLogin", "cancel", &ProtocolLogin::cancel);
}

View File

@@ -0,0 +1,235 @@
#include "luainterface.h"
LuaInterface g_lua;
void LuaInterface::init()
{
// installs a custom loader that will load scripts correctlyfrom lua require keyword
auto loaders = getGlobal("package")->getField("loaders");
loaders->setTable(loaders->getTableSize() + 1, createCppFunction(&LuaInterface::luaScriptLoader));
// register LuaObject, the class that all other classes will derive from
registerClass("LuaObject");
bindClassMemberGetField("LuaObject", "use_count", &LuaObject::getUseCount);
// register other custom classes and functions
registerFunctions();
}
void LuaInterface::terminate()
{
collectGarbage();
}
LuaValuePtr LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
{
LuaValuePtr func;
// get the function contained the buffer
if(boost::starts_with(buffer, "function")) {
runBuffer(make_string("__func = ", buffer), source);
func = getGlobal("__func");
setGlobal("__func", createNil());
// use the buffer as a function
} else
func = loadBuffer(buffer, source);
return func;
}
LuaValuePtr LuaInterface::evaluateExpression(const std::string& expression, const std::string& source)
{
// run the expression
std::string buffer = make_string("__exp = (", expression, ")");
runBuffer(buffer, source);
// get the expression result
LuaValuePtr res = getGlobal("__exp");
setGlobal("__exp", createNil());
return res;
}
LuaValuePtr LuaInterface::createEnvironment()
{
// creates a new environment table and
// redirect the new environment to the current thread global environment (aka _G)
// this allows to access global variables from _G in the new environment
// and prevents new variables on the new environment to be set on the global environment
auto env = createTable();
auto mt = createTable();
mt->setField("__index", getGlobalEnvironment());
env->setMetatable(mt);
return env;
}
void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
{
// create the class table (that it is also the class methods table)
auto klass = createTable(className);
// create the class metatable
auto klass_mt = createTable(className + "_mt");
// create the class fieldmethods table
auto klass_fieldmethods = createTable(className + "_fieldmethods");
// set metatable metamethods
klass_mt->setField("__index", &LuaInterface::luaObjectGetEvent);
klass_mt->setField("__newindex", &LuaInterface::luaObjectSetEvent);
klass_mt->setField("__eq", &LuaInterface::luaObjectEqualEvent);
klass_mt->setField("__gc", &LuaInterface::luaObjectCollectEvent);
klass_mt->setField("methods", klass);
klass_mt->setField("fieldmethods", klass_fieldmethods);
// redirect methods and fieldmethods to the base class ones
if(!className.empty() && className != "LuaObject") {
/* the following code what create classes hierarchy for lua, by reproducing the following:
* DerivedClass = { __index = BaseClass }
* DerivedClass_fieldmethods = { __index = BaseClass_methods }
*/
// redirect the class methods to the base methods
auto redirect = createTable();
auto tmp = getGlobal(baseClass);
redirect->setField("__index", tmp);
klass->setMetatable(redirect);
// redirect the class fieldmethods to the base fieldmethods
redirect = createTable();
tmp = getGlobal(baseClass + "_fieldmethods");
redirect->setField("__index", tmp);
klass_fieldmethods->setMetatable(redirect);
}
}
void LuaInterface::registerClassStaticFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function)
{
registerClassMemberFunction(className, functionName, function);
}
void LuaInterface::registerClassMemberFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function)
{
auto table = getGlobal(className);
table->setField(functionName, function);
}
void LuaInterface::registerClassMemberField(const std::string& className, const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction)
{
auto fieldmethods = getGlobal(className + "_fieldmethods");
auto methods = getGlobal(className);
auto capitalized = field;
capitalized[0] = std::toupper(field[0]);
if(getFunction) {
auto func = createCppFunction(getFunction);
fieldmethods->setField(make_string("get_", field), func);
methods->setField(make_string("get", capitalized), func);
}
if(setFunction) {
auto func = createCppFunction(setFunction);
fieldmethods->setField(make_string("set_", field), func);
methods->setField(make_string("set", capitalized), func);
}
}
void LuaInterface::registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function)
{
setGlobal(functionName, createCppFunction(function));
}
int LuaInterface::luaScriptLoader(LuaState* lua)
{
// load the script as a function
auto fileName = make_string(lua->popValue()->toString(), + ".lua");
auto scriptMain = lua->loadScript(fileName);
lua->pushValue(scriptMain);
return 1;
}
int LuaInterface::luaObjectGetEvent(LuaState* lua)
{
// metamethod that will retrive fields values (that include functions) from the object
auto key = lua->popValue()->toString();
auto objRef = lua->popValue();
auto obj = safe_luavalue_cast<LuaObjectPtr>(objRef);
// if a get method for this key exists, calls it
auto get_method = objRef->getMetatable()->getField("fieldmethods")->getField("get_" + key);
if(!get_method->isNil()) {
LuaValueList rets = get_method->call(make_string(obj->getLuaTypeName(), " obj.", key), objRef);
assert(rets.size() == 1);
lua->pushValues(rets);
return 1;
}
// if the field for this key exists, returns it
auto field = obj->getField(key);
if(!field->isNil()) {
lua->pushValue(field);
return 1;
}
// if a method for this key exists, returns it
auto method = objRef->getMetatable()->getField("methods")->getField(key);
lua->pushValue(method);
return 1;
}
int LuaInterface::luaObjectSetEvent(LuaState* lua)
{
// this metamethod is called when setting a field of the object by using the keyword '='
auto value = lua->popValue();
auto key = lua->popValue()->toString();
auto objRef = lua->popValue();
auto obj = safe_luavalue_cast<LuaObjectPtr>(objRef);
// check if a set method for this field exists and call it
auto set_method = objRef->getMetatable()->getField("fieldmethods")->getField("set_" + key);
if(!set_method->isNil()) {
set_method->call(make_string(obj->getLuaTypeName(), " obj.", key, "="), objRef, value);
return 0;
}
// no set method exists, then sets the object table
obj->setField(key, value);
return 0;
}
int LuaInterface::luaObjectEqualEvent(LuaState* lua)
{
// metamethod that will check equality of objects
auto objRef2 = lua->popValue();
auto objRef1 = lua->popValue();
bool ret = false;
// check if obj1 == obj2
if(objRef1->isUserdata() && objRef2->isUserdata()) {
LuaObjectPtr* objPtr1 = static_cast<LuaObjectPtr*>(objRef1->toUserdata());
LuaObjectPtr* objPtr2 = static_cast<LuaObjectPtr*>(objRef2->toUserdata());
assert(objPtr1 && objPtr2);
if(*objPtr1 == *objPtr2)
ret = true;
}
lua->pushBoolean(ret);
return 1;
}
int LuaInterface::luaObjectCollectEvent(LuaState* lua)
{
/* this metamethod is called every two lua garbage collections
* for any LuaObject that have no references left in lua environment
* anymore, thus this creates the possibility of holding an object
* existence by lua
*/
// get object pointer
auto objRef = lua->popValue();
auto objPtr = static_cast<LuaObjectPtr*>(objRef->toUserdata());
assert(objPtr);
// reset pointer to decrease object use count
objPtr->reset();
return 0;
}

View File

@@ -0,0 +1,73 @@
#ifndef LUAINTERFACE_H
#define LUAINTERFACE_H
#include "luabinder.h"
#include "luaobject.h"
class LuaInterface : public LuaState
{
public:
void init();
void terminate();
/// Load a function from buffef into a LuaValue
LuaValuePtr loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
/// Evaluate a lua expression to a LuaValue
LuaValuePtr evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
LuaValuePtr createEnvironment();
/// Register core script functions
void registerFunctions();
// methods for registring classes and functions
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
void registerClassStaticFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function);
void registerClassMemberFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function);
void registerClassMemberField(const std::string& className, const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction);
void registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function);
// methods for binding functions
template<typename F>
void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) {
registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
}
template<class C, typename F>
void bindClassMemberFunction(const std::string& className, const std::string& functionName, F C::*function) {
registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun(function));
}
template<class C, typename F1, typename F2>
void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction));
}
template<class C, typename F>
void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F C::*getFunction) {
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction());
}
template<class C, typename F>
void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F C::*setFunction) {
registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction));
}
template<typename F>
void bindGlobalFunction(const std::string& functionName, const F& function) {
registerGlobalFunction(functionName, luabinder::bind_fun(function));
}
private:
// installed lua callbacks by this interface
static int luaScriptLoader(LuaState* lua);
static int luaObjectGetEvent(LuaState* lua);
static int luaObjectSetEvent(LuaState* lua);
static int luaObjectEqualEvent(LuaState* lua);
static int luaObjectCollectEvent(LuaState* lua);
};
extern LuaInterface g_lua;
#endif // LUAINTERFACE_H

View File

@@ -0,0 +1,24 @@
#include "luaobject.h"
#include "luainterface.h"
LuaObject::LuaObject()
{
// creates own table
m_luaTable = g_lua.createTable();
}
LuaObject::~LuaObject()
{
}
LuaValuePtr LuaObject::toLuaValue()
{
// fills a new userdata with a new LuaObject pointer
new(g_lua.newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(shared_from_this());
// set the metatable for the userdata
g_lua.setMetatable(make_string(getLuaTypeName(), "_mt"));
return g_lua.popValue();
}

View File

@@ -0,0 +1,50 @@
#ifndef LUAOBJECT_H
#define LUAOBJECT_H
#include "luavalue.h"
/// LuaObject, all bound classes must be derived from it
class LuaObject : public std::enable_shared_from_this<LuaObject>
{
public:
LuaObject();
virtual ~LuaObject();
/// Call a field of this lua object
template<typename... T>
LuaValueList callField(const std::string& field, const T&... args) {
// note that we must retrive the field from or lua value (to use the __index metamethod)
// so we cannot use our getField here
auto fieldFunc = toLuaValue()->getField(field);
auto funcName = make_string(getLuaTypeName(), ":", field);
return fieldFunc->call(funcName, shared_from_this(), args...);
}
/// Set a field of this lua object
template<typename T>
void setField(const std::string& key, const T& value) {
m_luaTable->setField(key, value);
}
/// Get a field of this lua object
LuaValuePtr getField(const std::string& key) {
return m_luaTable->getField(key);
}
/// Returns current use count by the shared_ptr
int getUseCount() { return shared_from_this().use_count() - 1; }
/// Class name used in lua, must be overridden by derived classes
virtual const char* getLuaTypeName() const = 0;
/** Convert to a lua value for pushing this object into lua stack.
* Each call to this will create a new pointer, thus increasing the use count.*/
LuaValuePtr toLuaValue();
LuaObjectPtr asLuaObject() { return shared_from_this(); }
private:
LuaValuePtr m_luaTable;
};
#endif // LUAOBJECT_H

View File

@@ -0,0 +1,604 @@
#include "luastate.h"
#include "luavalue.h"
#include <lua.hpp>
#include <core/resources.h>
/// Retrive LuaState from L
LuaState* retriveLuaState(lua_State* L)
{
lua_getfield(L, LUA_REGISTRYINDEX, "LuaStateInstance");
auto lua = static_cast<LuaState*>(const_cast<void*>(lua_topointer(L, -1)));
lua_pop(L, 1);
return lua;
}
/// Handle errors by protected lua calls (pcall)
int luaErrorHandler(lua_State* L)
{
// pops the error message
auto lua = retriveLuaState(L);
auto error = lua->popString();
// prevents repeated tracebacks
if(error.find("stack traceback:") != std::string::npos)
error = lua->getTraceback(error, 1);
// pushes the new error message with traceback information
lua->pushString(error);
return 1;
}
/// Handle bound cpp functions callbacks
int luaCppFunctionCallback(lua_State* L)
{
auto lua = retriveLuaState(L);
auto funcPtr = static_cast<LuaCppFunctionPtr*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(funcPtr);
try {
return (*(funcPtr->get()))(lua);
} catch(LuaException &e) {
logError(e.what());
return 0;
}
}
/// Free cpp function pointer when it expires
int luaCppFunctionCallbackPointerExpire(lua_State* L)
{
auto funcPtr = static_cast<LuaCppFunctionPtr*>(lua_touserdata(L, -1));
assert(funcPtr);
funcPtr->reset();
return 0;
}
LuaState::LuaState() : m_collecting(false)
{
// create lua state
L = luaL_newstate();
if(!L)
throw LuaException("failed to create lua state");
// load lua standard libraries
luaL_openlibs(L);
// store this into lua
pushLightUserdata(this);
lua_setfield(L, LUA_REGISTRYINDEX, "LuaStateInstance");
}
LuaState::~LuaState()
{
// close lua state
m_collecting = true;
lua_close(L);
}
void LuaState::collectGarbage()
{
// prevents recursive collects
if(!m_collecting) {
m_collecting = true;
// we must collect two times for __gc metamethod be called on uservalues
for(int i=0;i<2;++i)
lua_gc(L, LUA_GCCOLLECT, 0);
m_collecting = false;
}
}
LuaValuePtr LuaState::loadBuffer(const std::string& buffer, const std::string& source)
{
// load buffer from lua, the "@" means that the source is a file path, thus lua will
// print file paths in tracebacks
int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), ("@" + source).c_str());
if(ret != 0)
throw LuaException(popString(), 0);
return popValue();
}
LuaValuePtr LuaState::loadScript(const std::string &fileName)
{
std::stringstream fin;
if(!g_resources.loadFile(fileName, fin))
throw LuaException(make_string("failed to open lua script ", g_resources.resolvePath(fileName)), 0);
return loadBuffer(fin.str(), g_resources.resolvePath(fileName));
}
void LuaState::runBuffer(const std::string& buffer, const std::string& source)
{
auto main = loadBuffer(buffer, source);
main->call(source);
}
void LuaState::runScript(const std::string& fileName)
{
auto main = loadScript(fileName);
main->call(fileName);
}
int LuaState::safeCall(const std::string& functionName, int numArgs)
{
assert(hasIndex(-numArgs-1));
int previousStackSize = stackSize();
// push error function
int errorFuncIndex = previousStackSize - numArgs;
lua_pushcfunction(L, luaErrorHandler);
insert(errorFuncIndex);
m_callStack.push_front(functionName);
// call the func
int ret = lua_pcall(L, numArgs, LUA_MULTRET, errorFuncIndex);
m_callStack.pop_front();
// pop error func
remove(errorFuncIndex);
if(ret != 0)
throw LuaException(popString(), 0);
// return the number of results
return (stackSize() + numArgs + 1) - previousStackSize;
}
LuaValuePtr LuaState::popValue()
{
assert(hasIndex(-1));
LuaValuePtr value;
int refId = ref();
if(refId < 0) {
// refs < 0 are considered as nil values
value = LuaValuePtr(new LuaValue());
} else {
pushRef(refId);
value = LuaValuePtr(new LuaValue(refId));
pop();
}
return value;
}
LuaValueList LuaState::popValues()
{
int numValues = stackSize();
LuaValueList values(numValues);
for(int i=numValues-1;i>=0;--i)
values[i] = popValue();
return values;
}
void LuaState::pushCppFunction(const LuaCppFunction& func)
{
// create a pointer to func (this pointer will hold the function existence)
new(newUserdata(sizeof(LuaCppFunctionPtr))) LuaCppFunctionPtr(new LuaCppFunction(func));
// set the userdata __gc metamethod
newTable();
lua_pushcfunction(L, luaCppFunctionCallbackPointerExpire);
setField("__gc");
setMetatable();
// pushes the func
lua_pushcclosure(L, luaCppFunctionCallback, 1);
}
void LuaState::pushValue(const LuaValuePtr& value)
{
if(value->isNil())
pushNil();
else
pushRef(value->ref);
}
void LuaState::pushValues(const LuaValueList& values)
{
foreach(const LuaValuePtr& value, values)
pushValue(value);
}
std::string LuaState::getTraceback(const std::string& errorMessage, int depth)
{
// get traceback from debug.traceback
getGlobalField("debug");
getField("traceback");
remove(-2);
pushString(errorMessage);
pushInteger(depth);
call(2,1);
std::string luaTraceback = popString();
boost::replace_first(luaTraceback, "stack traceback:", "lua stack traceback:");
std::stringstream ss;
ss << luaTraceback;
// add application call traceback
if(m_callStack.size() > 0) {
ss << "\napplication call stack traceback:";
foreach(const std::string& func, m_callStack)
ss << "\n\t" << func;
}
return ss.str();
}
std::string LuaState::getCurrentSource()
{
std::string path;
int level = 0;
// get the current running script path
LuaValuePtr func;
do {
func = getStackFunction(level);
if(func->isLuaFunction()) {
path = getFunctionSource(func);
break;
}
level++;
} while(!func->isNil());
return path;
}
std::string LuaState::getFunctionSource(LuaValuePtr func)
{
std::string path;
pushValue(func);
lua_Debug ar;
lua_getinfo(L, ">Sn", &ar);
if(ar.source) {
path = ar.source;
path = path.substr(1, std::string::npos);
}
return path;
}
LuaValuePtr LuaState::getGlobalEnvironment()
{
lua_pushthread(L);
getEnv();
remove(-2);
return popValue();
}
void LuaState::setGlobalEnvironment(const LuaValuePtr& env)
{
lua_pushthread(L);
pushValue(env);
setEnv();
pop();
}
LuaValuePtr LuaState::getStackFunction(int level)
{
// get current stack func
lua_Debug ar;
if(lua_getstack(L, level, &ar) == 1) {
lua_getinfo(L, "f", &ar);
return popValue();
}
return createNil();
}
std::string LuaState::typeName(int index)
{
assert(hasIndex(index));
int type = lua_type(L, index);
std::string name = lua_typename(L, type);
return name;
}
int LuaState::ref()
{
return luaL_ref(L, LUA_REGISTRYINDEX);
}
void LuaState::unref(int ref)
{
if(ref > 0)
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
void LuaState::call(int numArgs, int numRets)
{
assert(hasIndex(-numArgs - 1));
lua_call(L, numArgs, numRets);
}
void LuaState::insert(int index)
{
assert(hasIndex(index));
lua_insert(L, index);
}
void LuaState::remove(int index)
{
assert(hasIndex(index));
lua_remove(L, index);
}
bool LuaState::next(int index)
{
assert(hasIndex(index));
return lua_next(L, index);
}
void LuaState::copy(int index)
{
assert(hasIndex(index));
lua_pushvalue(L, index);
}
void LuaState::setMetatable(int index)
{
assert(hasIndex(index));
lua_setmetatable(L, index);
}
void LuaState::setMetatable(const std::string& name)
{
assert(hasIndex(-1));
getGlobalField(name);
setMetatable();
}
void LuaState::getMetatable(int index)
{
assert(hasIndex(index));
lua_getmetatable(L, index);
}
void LuaState::getField(const std::string& key, int index)
{
assert(hasIndex(index));
lua_getfield(L, index, key.c_str());
}
void LuaState::setField(const std::string& key, int index)
{
assert(hasIndex(index));
lua_setfield(L, index, key.c_str());
}
void LuaState::getEnv(int index)
{
assert(hasIndex(index));
lua_getfenv(L, index);
}
void LuaState::setEnv(int index)
{
assert(hasIndex(index));
assert(lua_setfenv(L, index) == 1);
}
void LuaState::getTable(int index)
{
assert(hasIndex(index));
lua_gettable(L, index);
}
void LuaState::setTable(int index)
{
assert(hasIndex(index));
lua_settable(L, index);
}
void LuaState::getGlobalField(const std::string& key)
{
lua_getglobal(L, key.c_str());
}
void LuaState::setGlobalField(const std::string& key)
{
assert(hasIndex(-1));
lua_setglobal(L, key.c_str());
}
void LuaState::rawGet(int index)
{
assert(hasIndex(index));
lua_rawget(L, index);
}
void LuaState::rawGeti(int n, int index)
{
assert(hasIndex(index));
lua_rawgeti(L, index, n);
}
void LuaState::rawSet(int index)
{
assert(hasIndex(index));
lua_rawset(L, index);
}
void LuaState::rawSeti(int n, int index)
{
assert(hasIndex(index));
lua_rawseti(L, index, n);
}
void LuaState::newTable()
{
lua_newtable(L);
}
void* LuaState::newUserdata(int size)
{
return lua_newuserdata(L, size);
}
void LuaState::pop(int n)
{
assert(hasIndex(-n));
lua_pop(L, n);
}
int LuaState::popInteger()
{
assert(hasIndex(-1));
int v = toInteger(-1);
pop();
return v;
}
double LuaState::popNumber()
{
assert(hasIndex(-1));
double v = toNumber(-1);
pop();
return v;
}
bool LuaState::popBoolean()
{
assert(hasIndex(-1));
bool v = toBoolean(-1);
pop();
return v;
}
std::string LuaState::popString()
{
assert(hasIndex(-1));
std::string v = toString(-1);
pop();
return v;
}
void* LuaState::popUserdata()
{
assert(hasIndex(-1));
void* v = toUserdata(-1);
pop();
return v;
}
void LuaState::pushNil()
{
lua_pushnil(L);
}
void LuaState::pushInteger(int v)
{
lua_pushinteger(L, v);
}
void LuaState::pushNumber(double v)
{
lua_pushnumber(L, v);
}
void LuaState::pushBoolean(bool v)
{
lua_pushboolean(L, v);
}
void LuaState::pushString(const std::string& v)
{
lua_pushstring(L, v.c_str());
}
void LuaState::pushRef(int ref)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
}
void LuaState::pushLightUserdata(void* p)
{
lua_pushlightuserdata(L, p);
}
bool LuaState::isNil(int index)
{
assert(hasIndex(index));
return lua_isnil(L, index);
}
bool LuaState::isBoolean(int index)
{
assert(hasIndex(index));
return lua_isboolean(L, index);
}
bool LuaState::isNumber(int index)
{
assert(hasIndex(index));
return lua_isnumber(L, index);
}
bool LuaState::isString(int index)
{
assert(hasIndex(index));
return lua_isstring(L, index);
}
bool LuaState::isTable(int index)
{
assert(hasIndex(index));
return lua_istable(L, index);
}
bool LuaState::isFunction(int index)
{
assert(hasIndex(index));
return lua_isfunction(L, index);
}
bool LuaState::isCFunction(int index)
{
assert(hasIndex(index));
return lua_iscfunction(L, index);
}
bool LuaState::isUserdata(int index)
{
assert(hasIndex(index));
return lua_isuserdata(L, index);
}
bool LuaState::toBoolean(int index)
{
assert(hasIndex(index));
return (bool)lua_toboolean(L, index);
}
int LuaState::toInteger(int index)
{
assert(hasIndex(index));
return lua_tointeger(L, index);
}
double LuaState::toNumber(int index)
{
assert(hasIndex(index));
return lua_tonumber(L, index);
}
std::string LuaState::toString(int index)
{
assert(hasIndex(index));
return std::string(isString() ? lua_tostring(L, index) : "");
}
void* LuaState::toUserdata(int index)
{
assert(hasIndex(index));
return lua_touserdata(L, index);
}
int LuaState::stackSize()
{
return lua_gettop(L);
}

View File

@@ -0,0 +1,126 @@
#ifndef LUASTATE_H
#define LUASTATE_H
#include "luadeclarations.h"
struct lua_State;
class LuaState
{
public:
LuaState();
virtual ~LuaState();
// high level functions
void collectGarbage();
LuaValuePtr loadBuffer(const std::string& buffer, const std::string& source);
LuaValuePtr loadScript(const std::string& fileName);
void runBuffer(const std::string& buffer, const std::string& source);
void runScript(const std::string& fileName);
LuaValuePtr getGlobal(const std::string& name) { getGlobalField(name); return popValue(); }
void setGlobal(const std::string& name, const LuaValuePtr& value) { pushValue(value); setGlobalField(name); }
LuaValuePtr createTable() { newTable(); return popValue(); }
LuaValuePtr createTable(const std::string& name) { newTable(); copy(); setGlobalField(name); return popValue(); }
LuaValuePtr createCppFunction(const LuaCppFunction& v) { pushCppFunction(v); return popValue(); }
LuaValuePtr createNil() { pushNil(); return popValue(); }
LuaValuePtr createNumber(double v) { pushNumber(v); return popValue(); }
LuaValuePtr createInteger(int v) { pushInteger(v); return popValue(); }
LuaValuePtr createString(const std::string& v) { pushString(v); return popValue(); }
LuaValuePtr createBoolean(bool v) { pushBoolean(v); return popValue(); }
std::string getTraceback(const std::string& errorMessage = "", int depth = 0);
std::string getCurrentSource();
std::string getFunctionSource(LuaValuePtr func);
LuaValuePtr getStackFunction(int level);
LuaValuePtr getGlobalEnvironment();
void setGlobalEnvironment(const LuaValuePtr& env);
// low level lua functions
std::string typeName(int index = -1);
int ref();
void unref(int ref);
void call(int numArgs = 0, int numRets = 0);
int safeCall(const std::string& functionName, int numArgs = 0);
void insert(int index);
void remove(int index);
bool next(int index = -2);
void copy(int index = -1);
void setMetatable(int index = -2);
void setMetatable(const std::string& name);
void getMetatable(int index = -1);
void getField(const std::string& key, int index = -1);
void setField(const std::string& key, int index = -2);
void getTable(int index = -2);
void setTable(int index = -3);
void getEnv(int index = -1);
void setEnv(int index = -2);
void getGlobalField(const std::string& key);
void setGlobalField(const std::string& key);
void rawGet(int index = -1);
void rawGeti(int n, int index = -1);
void rawSet(int index = -3);
void rawSeti(int n, int index = -2);
void newTable();
void* newUserdata(int size);
void pop(int n = 1);
int popInteger();
double popNumber();
bool popBoolean();
std::string popString();
void* popUserdata();
LuaValuePtr popValue();
LuaValueList popValues();
void pushNil();
void pushInteger(int v);
void pushNumber(double v);
void pushBoolean(bool v);
void pushString(const std::string& v);
void pushRef(int ref);
void pushLightUserdata(void* p);
void pushCppFunction(const LuaCppFunction& func);
void pushValue(const LuaValuePtr& value);
void pushValues(const LuaValueList& values);
bool isNil(int index = -1);
bool isBoolean(int index = -1);
bool isNumber(int index = -1);
bool isString(int index = -1);
bool isTable(int index = -1);
bool isFunction(int index = -1);
bool isCFunction(int index = -1);
bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
bool isUserdata(int index = -1);
bool toBoolean(int index = -1);
int toInteger(int index = -1);
double toNumber(int index = -1);
std::string toString(int index = -1);
void* toUserdata(int index = -1);
int stackSize();
void clearStack() { pop(stackSize()); }
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index)); }
private:
lua_State* L;
bool m_collecting;
std::deque<std::string> m_callStack;
};
#endif // LUASTATE_H

View File

@@ -0,0 +1,234 @@
#include "luavalue.h"
#include "luainterface.h"
#include "luaobject.h"
#include <core/resources.h>
LuaValue::LuaValue(int ref) : ref(ref)
{
}
LuaValue::~LuaValue()
{
// releases the reference of this value from lua
g_lua.unref(ref);
}
LuaValueList LuaValue::call(const std::string& funcName, const LuaValueList& args)
{
LuaValueList rets;
// if is a function, calls it
if(isFunction()) {
g_resources.pushCurrentPath(getPathDirectory(g_lua.getFunctionSource(shared_from_this())));
try {
push();
g_lua.pushValues(args);
int numRets = g_lua.safeCall(funcName, args.size());
for(int i=0;i<numRets; ++i)
rets.push_back(g_lua.popValue());
} catch(LuaException &e) {
logError(e.what());
}
g_resources.popCurrentPath();
}
// also calls a table of functions
else if(isTable()) {
LuaValueList functions = getTableValues();
foreach(const LuaValuePtr& function, functions) {
if(function->isFunction())
function->call(funcName, args);
}
};
return rets;
}
int LuaValue::getTableSize()
{
int size = 0;
push();
assert(g_lua.isTable());
g_lua.pushNil();
while(g_lua.next()) {
g_lua.pop();
size++;
}
g_lua.pop();
return size;
}
LuaValueList LuaValue::getTableValues()
{
LuaValueList ret;
push();
assert(g_lua.isTable());
g_lua.pushNil();
while(g_lua.next())
ret.push_back(g_lua.popValue());
return ret;
}
LuaValuePtr LuaValue::getField(const std::string& key)
{
push();
assert(g_lua.isTable() || g_lua.isUserdata());
g_lua.getField(key);
g_lua.remove(-2);
return g_lua.popValue();
}
void LuaValue::setField(const std::string& key, const LuaValuePtr& value)
{
push();
assert(g_lua.isTable() || g_lua.isUserdata());
g_lua.pushValue(value);
g_lua.setField(key);
g_lua.pop();
}
LuaValuePtr LuaValue::getMetatable()
{
push();
assert(g_lua.isUserdata() || g_lua.isTable());
g_lua.getMetatable();
g_lua.remove(-2);
return g_lua.popValue();
}
void LuaValue::setMetatable(const LuaValuePtr& mt)
{
push();
assert(g_lua.isUserdata() || g_lua.isTable());
g_lua.pushValue(mt);
g_lua.setMetatable();
g_lua.pop();
}
void LuaValue::setTable(int n, const LuaValuePtr& value)
{
push();
assert(g_lua.isTable());
g_lua.pushInteger(n);
g_lua.pushValue(value);
g_lua.setTable();
g_lua.pop();
}
void LuaValue::setEnvironment(LuaValuePtr env)
{
push();
g_lua.pushValue(env);
g_lua.setEnv();
g_lua.pop();
}
std::string LuaValue::getTypeName()
{
push();
std::string typeName = g_lua.typeName();
g_lua.pop();
return typeName;
}
bool LuaValue::isBoolean()
{
push();
bool ret = g_lua.isBoolean();
g_lua.pop();
return ret;
}
bool LuaValue::isString()
{
push();
bool ret = g_lua.isString();
g_lua.pop();
return ret;
}
bool LuaValue::isNumber()
{
push();
bool ret = g_lua.isNumber();
g_lua.pop();
return ret;
}
bool LuaValue::isTable()
{
push();
bool ret = g_lua.isTable();
g_lua.pop();
return ret;
}
bool LuaValue::isFunction()
{
push();
bool ret = g_lua.isFunction();
g_lua.pop();
return ret;
}
bool LuaValue::isCFunction()
{
push();
bool ret = g_lua.isCFunction();
g_lua.pop();
return ret;
}
bool LuaValue::isLuaFunction()
{
push();
bool ret = g_lua.isLuaFunction();
g_lua.pop();
return ret;
}
bool LuaValue::isUserdata()
{
push();
bool ret = g_lua.isUserdata();
g_lua.pop();
return ret;
}
bool LuaValue::toBoolean()
{
push();
return g_lua.popBoolean();
}
int LuaValue::toInteger()
{
push();
return g_lua.popInteger();
}
double LuaValue::toNumber()
{
push();
return g_lua.popNumber();
}
std::string LuaValue::toString()
{
push();
return g_lua.popString();
}
void* LuaValue::toUserdata()
{
push();
return g_lua.popUserdata();
}
void LuaValue::push()
{
g_lua.pushValue(shared_from_this());
}

View File

@@ -0,0 +1,78 @@
#ifndef LUAVALUE_H
#define LUAVALUE_H
#include "luavaluecasts.h"
/// Utility used to fill a LuaValueList by args...
inline void fillLuaValueList(LuaValueList& argsList) { }
template<class T, class... Args>
void fillLuaValueList(LuaValueList& argsList, const T& first, const Args&... rest) {
argsList.push_back(safe_to_luavalue(first));
fillLuaValueList(argsList, rest...);
}
/// LuaValue, all values from and to lua can be represented by this type
class LuaValue : public std::enable_shared_from_this<LuaValue>
{
public:
LuaValue(int ref = -1);
virtual ~LuaValue();
/** If this value is a function or a list of functions, calls it.
* Otherwise, if is not a nil value, throws an LuaException */
LuaValueList call(const std::string& funcName, const LuaValueList& args = LuaValueList());
template<class... T>
LuaValueList call(const std::string& funcName, const T&... args) {
LuaValueList argsList;
push();
fillLuaValueList(argsList, args...);
return call(funcName, argsList);
}
int getTableSize();
LuaValueList getTableValues();
LuaValuePtr getField(const std::string& key);
void setField(const std::string& key, const LuaValuePtr& value);
template<typename T>
void setField(const std::string& key, const T& value) {
setField(key, safe_to_luavalue<T>(value));
}
LuaValuePtr getMetatable();
void setMetatable(const LuaValuePtr& mt);
void setTable(int n, const LuaValuePtr& value);
void setEnvironment(LuaValuePtr env);
std::string getTypeName();
// check types
bool isNil() { return ref < 0; }
bool isBoolean();
bool isString();
bool isNumber();
bool isTable();
bool isFunction();
bool isCFunction();
bool isLuaFunction();
bool isUserdata();
// convert types
bool toBoolean();
int toInteger();
double toNumber();
std::string toString();
void* toUserdata();
private:
/// Pushes this value into lua stack
void push();
int ref;
friend class LuaState;
};
#endif // LUAVALUE_H

View File

@@ -0,0 +1,76 @@
#include "luavaluecasts.h"
#include "luainterface.h"
bool to_luavalue(const LuaValuePtr& v, LuaValuePtr& o) {
o = v;
return true;
}
bool to_luavalue(bool v, LuaValuePtr& o) {
o = g_lua.createBoolean(v);
return true;
}
bool to_luavalue(int v, LuaValuePtr& o) {
o = g_lua.createInteger(v);
return true;
}
bool to_luavalue(double v, LuaValuePtr& o) {
o = g_lua.createNumber(v);
return true;
}
bool to_luavalue(const std::string& v, LuaValuePtr& o) {
o = g_lua.createString(v);
return true;
}
bool to_luavalue(const char* v, LuaValuePtr& o) {
o = g_lua.createString(v);
return true;
}
bool to_luavalue(int (*v)(LuaState*), LuaValuePtr& o) {
o = g_lua.createCppFunction(v);
return true;
}
bool to_luavalue(const LuaCppFunction& v, LuaValuePtr& o) {
o = g_lua.createCppFunction(v);
return true;
}
bool luavalue_cast(const LuaValuePtr& v, bool& o) {
o = v->toBoolean();
return true;
}
bool luavalue_cast(const LuaValuePtr& v, int& o) {
o = v->toInteger();
return true;
}
bool luavalue_cast(const LuaValuePtr& v, double& o) {
o = v->toNumber();
return true;
}
bool luavalue_cast(const LuaValuePtr& v, std::string& o) {
o = v->toString();
return true;
}
bool luavalue_cast(const LuaValuePtr& v, LuaObjectPtr& o) {
if(v->isUserdata()) {
LuaObjectPtr* objRef = static_cast<LuaObjectPtr*>(v->toUserdata());
if(objRef && *objRef) {
o = *objRef;
return true;
}
} else if(v->isNil()) {
o = LuaObjectPtr();
return true;
}
return false;
}

View File

@@ -0,0 +1,80 @@
#ifndef LUAVALUECASTS_H
#define LUAVALUECASTS_H
#include "luadeclarations.h"
#include "luaexception.h"
// convert from common types
bool to_luavalue(const LuaValuePtr& v, LuaValuePtr& o);
bool to_luavalue(bool v, LuaValuePtr& o);
bool to_luavalue(int v, LuaValuePtr& o);
bool to_luavalue(double v, LuaValuePtr& o);
bool to_luavalue(const std::string& v, LuaValuePtr& o);
bool to_luavalue(const char* v, LuaValuePtr& o);
bool to_luavalue(int (*v)(LuaState*), LuaValuePtr& o);
bool to_luavalue(const LuaCppFunction& v, LuaValuePtr& o);
// convert from LuaObject
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, bool>::type
to_luavalue(const T& v, LuaValuePtr& o) {
if(v) {
o = v->toLuaValue();
return true;
}
return false;
}
/// Safe convert, if any errors occurs throws an LuaException
template<class T>
LuaValuePtr safe_to_luavalue(const T& v) {
LuaValuePtr o;
if(!to_luavalue(v, o))
throw LuaBadTypeConversinException();
return o;
}
// common types casting
bool luavalue_cast(const LuaValuePtr& v, bool& o);
bool luavalue_cast(const LuaValuePtr& v, int& o);
bool luavalue_cast(const LuaValuePtr& v, double& o);
bool luavalue_cast(const LuaValuePtr& v, std::string& o);
bool luavalue_cast(const LuaValuePtr& v, LuaObjectPtr& o);
// convert enums
template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(const LuaValuePtr& v, T& o) {
return luavalue_cast(v, (int&)o);
}
// cast pointer
template<class T>
bool luavalue_cast(const LuaValuePtr& v, T*& o) {
LuaObjectPtr obj;
if(!luavalue_cast(v, obj))
return false;
o = std::dynamic_pointer_cast<T>(obj).get();
return !!o;
}
// cast shared pointers
template<class T>
bool luavalue_cast(const LuaValuePtr& v, std::shared_ptr<T>& o) {
LuaObjectPtr obj;
if(!luavalue_cast(v, obj))
return false;
o = std::dynamic_pointer_cast<T>(obj);
return !!o;
}
/// Safe casting, if any errors occurs throws an LuaException
template<class T>
T safe_luavalue_cast(const LuaValuePtr& v) {
T o;
if(!luavalue_cast(v, o))
throw LuaBadValueCastException(v);
return o;
}
#endif // LUAVALUECASTS_H

View File

@@ -1,748 +0,0 @@
#include <global.h>
#include <script/scriptcontext.h>
#include <script/scriptfunctions.h>
#include <core/resources.h>
#include <lua.hpp>
#include <boost/algorithm/string.hpp>
ScriptContext g_lua;
void ScriptContext::init()
{
L = luaL_newstate();
if(!L)
logFatal("FATAL ERROR: could not create lua context");
// load lua standard libraries
luaL_openlibs(L);
// setup custom package loader
setupPackageLoader();
registerScriptFunctions();
}
void ScriptContext::terminate()
{
collectGarbage();
lua_close(L);
L = NULL;
}
void ScriptContext::loadAllModules()
{
std::list<std::string> modules = g_resources.listDirectoryFiles("modules");
foreach(const std::string& module, modules) {
std::list<std::string> moduleFiles = g_resources.listDirectoryFiles("modules/" + module);
foreach(const std::string& moduleFile, moduleFiles) {
if(boost::ends_with(moduleFile, ".lua"))
loadFile(std::string("modules/") + module + "/" + moduleFile);
}
}
}
bool ScriptContext::loadFile(const std::string& fileName)
{
std::stringstream fin;
if(g_resources.loadFile(fileName, fin))
return loadBuffer(fin.str(), fileName);
else
logError("ERROR: script file '", fileName, "' doesn't exist");
return false;
}
bool ScriptContext::loadBuffer(const std::string& text, const std::string& what)
{
if(loadBufferAsFunction(text, what) && callFunction())
return true;
return false;
}
bool ScriptContext::loadBufferAsFunction(const std::string& text, const std::string& what)
{
int ret = luaL_loadbuffer(L, text.c_str(), text.length(), ("@" + what).c_str());
if(ret != 0){
reportError(popString());
return false;
}
if(!isFunction()) {
pop();
return false;
}
return true;
}
void ScriptContext::reportError(const std::string& errorDesc, const char *funcName)
{
std::stringstream ss;
ss << "LUA Script ERROR: ";
if(funcName)
ss << " in " << funcName << "(): ";
ss << errorDesc;
logError(ss.str());
}
void ScriptContext::reportErrorWithTraceback(const std::string& errorDesc, const char* funcName)
{
pushString(errorDesc);
luaErrorHandler(L);
reportError(popString(), funcName);
}
void ScriptContext::collectGarbage()
{
for(int i=0;i<2;i++)
lua_gc(L, LUA_GCCOLLECT, 0);
}
int ScriptContext::getStackSize()
{
return lua_gettop(L);
}
void ScriptContext::insert(int index)
{
if(index != -1)
lua_insert(L, index);
}
void ScriptContext::swap(int index)
{
insert(index);
pushValue(index+1);
remove(index);
}
void ScriptContext::remove(int index)
{
lua_remove(L, index);
}
bool ScriptContext::next(int index)
{
return lua_next(L, index);
}
void ScriptContext::releaseRef(int ref)
{
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
void ScriptContext::newTable()
{
lua_newtable(L);
}
void ScriptContext::setTable(int index)
{
lua_settable(L, index);
}
void *ScriptContext::newUserdata(int size)
{
return lua_newuserdata(L, size);
}
void ScriptContext::newMetatable(const std::string& name)
{
luaL_newmetatable(L, name.c_str());
}
void ScriptContext::setMetatable(const std::string& name, int index)
{
luaL_getmetatable(L, name.c_str());
if(isNil())
reportError(make_string("could not retrive metatable", name));
else
lua_setmetatable(L, index < 0 ? index-1 : index);
}
void ScriptContext::rawGet(const std::string& key)
{
pushString(key);
lua_rawget(L, -2);
}
void ScriptContext::rawSet(const std::string& key)
{
pushString(key);
insert(-2);
lua_rawset(L, -3);
}
void ScriptContext::getField(const std::string& key)
{
lua_getfield(L, -1, key.c_str());
}
void ScriptContext::setField(const std::string& key)
{
lua_setfield(L, -2, key.c_str());
}
void ScriptContext::getScriptObjectField(const ScriptObjectPtr& scriptobject, const std::string& field)
{
if(scriptobject) {
pushRef(scriptobject->getScriptTable());
getField(field);
remove(-2);
} else
pushNil();
}
void ScriptContext::setScriptObjectField(const ScriptObjectPtr& scriptobject, const std::string& field)
{
if(scriptobject) {
pushRef(scriptobject->getScriptTable());
insert(-2);
setField(field);
}
pop();
}
void ScriptContext::rawGetGlobalTableField(const std::string& globalTable, const std::string& key)
{
getGlobal(globalTable);
rawGet(key);
remove(-2);
}
void ScriptContext::rawSetGlobalTableField(const std::string& globalTable, const std::string& key)
{
getGlobal(globalTable);
insert(-2);
rawSet(key);
pop();
}
void ScriptContext::getGlobal(const std::string& key)
{
lua_getfield(L, LUA_GLOBALSINDEX, key.c_str());
}
void ScriptContext::setGlobal(const std::string& key)
{
lua_setfield(L, LUA_GLOBALSINDEX, key.c_str());
}
bool ScriptContext::isNil(int index)
{
return lua_isnil(L, index);
}
bool ScriptContext::isBoolean(int index)
{
return lua_isboolean(L, index);
}
bool ScriptContext::isNumber(int index)
{
return lua_isnumber(L, index);
}
bool ScriptContext::isString(int index)
{
return lua_isstring(L, index);
}
bool ScriptContext::isTable(int index)
{
return lua_istable(L, index);
}
bool ScriptContext::isUserdata(int index)
{
return lua_isuserdata(L, index);
}
bool ScriptContext::isFunction(int index)
{
return lua_isfunction(L, index);
}
bool ScriptContext::isCFunction(int index)
{
return lua_iscfunction(L, index);
}
bool ScriptContext::isLuaFunction(int index)
{
return isFunction(index) && !isCFunction(index);
}
void ScriptContext::pop(int n)
{
lua_pop(L, n);
}
bool ScriptContext::popBoolean()
{
bool b = (lua_toboolean(L, -1) != 0);
pop();
return b;
}
int ScriptContext::popInteger()
{
double d = lua_tonumber(L, -1);
pop();
return (int)d;
}
std::string ScriptContext::popString()
{
std::string str;
if(lua_isstring(L, -1))
str = lua_tostring(L, -1);
pop();
return str;
}
ScriptObjectPtr ScriptContext::popClassInstance()
{
ScriptObjectPtr object;
if(isUserdata()) { // instances are store as userdata
object = *((ScriptObjectPtr *)lua_touserdata(L, -1));
if(!object)
reportErrorWithTraceback("attempt to retrive class instance from a object that is already expired");
} else if(!isNil()) // we accept nil values
reportErrorWithTraceback("couldn't retrive class instance, the value is not a scriptobject type");
pop();
return object;
}
int ScriptContext::popRef()
{
return luaL_ref(L, LUA_REGISTRYINDEX);
}
void ScriptContext::pushNil()
{
lua_pushnil(L);
}
void ScriptContext::pushBoolean(bool b)
{
lua_pushboolean(L, b);
}
void ScriptContext::pushInteger(int32_t i)
{
lua_pushnumber(L, i);
}
void ScriptContext::pushString(const std::string& str)
{
lua_pushstring(L, str.c_str());
}
void ScriptContext::pushClassInstance(const ScriptObjectPtr& object)
{
if(object) {
new(newUserdata(sizeof(ScriptObjectPtr))) ScriptObjectPtr(object);
setMetatable(std::string(object->getScriptObjectType()) + "_mt");
} else
pushNil();
}
void ScriptContext::pushValue(int index)
{
lua_pushvalue(L, index);
}
void ScriptContext::pushRef(int ref)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
}
std::string ScriptContext::getFunctionSourcePath(bool functionIsOnStack, int level)
{
std::string path;
lua_Debug ar;
memset(&ar, 0, sizeof(ar));
if(functionIsOnStack)
lua_getinfo(L, ">Sn", &ar);
else {
if(lua_getstack(L, level-1, &ar) == 1)
lua_getinfo(L, "Sn", &ar);
}
// c function, we must get information of a level above
if(strcmp("C", ar.what) == 0) {
memset(&ar, 0, sizeof(ar));
if(lua_getstack(L, level, &ar) == 1) {
lua_getinfo(L, "f", &ar);
return getFunctionSourcePath(true, level+1);
}
} else {
if(ar.source) {
std::string source = ar.source;
std::size_t pos = source.find_last_of('/');
if(source[0] == '@' && pos != std::string::npos)
path = source.substr(1, pos - 1);
} else {
logError("no source");
}
}
return path;
}
bool ScriptContext::callFunction(int numArgs, int numRets)
{
pushValue(-numArgs - 1);
g_resources.pushCurrentPath(getFunctionSourcePath(true));
int size = getStackSize();
int errorIndex = -numArgs - 2;
lua_pushcfunction(L, &ScriptContext::luaErrorHandler);
insert(errorIndex);
int ret = lua_pcall(L, numArgs, numRets, errorIndex);
if(ret != 0) {
reportError(popString());
pop(); // pop error func
return false;
}
remove(-numRets - 1); // pop error func
if(getStackSize() != size - numArgs - 1 + numRets) {
reportError("stack size changed!");
return false;
}
g_resources.popCurrentPath();
return true;
}
void ScriptContext::callModuleField(const std::string& module, const std::string& field)
{
g_lua.rawGetGlobalTableField(module, field);
g_lua.callFunction();
}
void ScriptContext::setupPackageLoader()
{
lua_getfield(L, LUA_GLOBALSINDEX, "package"); // package
lua_getfield(L, -1, "loaders"); // package.loaders, package
lua_remove(L, -2); // package.loaders
lua_pushnil(L); // nil, package.loaders
int numLoaders = 0;
while(lua_next(L, -2) != 0) {
// value, key, package.loaders
lua_pop(L, 1); // key, package.loaders
numLoaders++;
}
lua_pushinteger(L, numLoaders + 1); // at, package.loaders
lua_pushcfunction(L, &ScriptContext::luaPackageLoader); // luaPackageLoader, at, package.loaders
lua_rawset(L, -3); // package.loaders
lua_pop(L, 1); // (empty)
}
void ScriptContext::registerClass(const std::string& klass, const std::string& baseClass)
{
// mt = {}
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, (klass + "_mt").c_str());
// set __index metamethod
lua_pushcfunction(L, &ScriptContext::luaIndexMetaMethod);
lua_setfield(L, -2, "__index");
// set __newindex metamethod
lua_pushcfunction(L, &ScriptContext::luaNewIndexMetaMethod);
lua_setfield(L, -2, "__newindex");
// set __eq metamethod
lua_pushcfunction(L, &ScriptContext::luaEqualMetaMethod);
lua_setfield(L, -2, "__eq");
// set __gc metamethod, which collects userdata
lua_pushcfunction(L, &ScriptContext::luaGarbageCollectMetaMethod);
lua_setfield(L, -2, "__gc");
// klass = { }
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, klass.c_str());
// mt.methods = klass
lua_setfield(L, -2, "methods");
// klass_fieldmethods = { }
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
// mt.fieldmethods = klass_fieldmethods
lua_setfield(L, -2, "fieldmethods");
if(baseClass.length()) {
// get klass
lua_getfield(L, LUA_GLOBALSINDEX, klass.c_str());
// redirect = { __index = baseClass }
lua_newtable(L);
lua_getfield(L, LUA_GLOBALSINDEX, baseClass.c_str());
lua_setfield(L, -2, "__index");
// setmetatable(klass, redirect)
lua_setmetatable(L, -2);
lua_pop(L, 1);
// get klass_fieldmethods
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
// redirect = { __index = baseClass_fieldmethods }
lua_newtable(L);
lua_getfield(L, LUA_GLOBALSINDEX, (baseClass + "_fieldmethods").c_str());
lua_setfield(L, -2, "__index");
// setmetatable(klass_fieldmethods, redirect)
lua_setmetatable(L, -2);
}
lua_pop(L, 1);
m_currentClass = klass;
}
void ScriptContext::registerMemberField(const std::string& field, ScriptContext::LuaCFunction getFunction, ScriptContext::LuaCFunction setFunction)
{
if(getFunction) {
int functionId = m_functions.size();
m_functions.push_back(getFunction);
// push the class table
lua_getfield(L, LUA_GLOBALSINDEX, (m_currentClass + "_fieldmethods").c_str());
// push the function id
lua_pushnumber(L, functionId);
// store id in the closure
lua_pushcclosure(L, &ScriptContext::luaFunctionCallback, 1);
// store the function at the class field functionName
lua_setfield(L, -2, ("get_" + field).c_str());
// pop the table
lua_pop(L, 1);
}
if(setFunction) {
int functionId = m_functions.size();
m_functions.push_back(setFunction);
// push the class table
lua_getfield(L, LUA_GLOBALSINDEX, (m_currentClass + "_fieldmethods").c_str());
// push the function id
lua_pushnumber(L, functionId);
// store id in the closure
lua_pushcclosure(L, &ScriptContext::luaFunctionCallback, 1);
// store the function at the class field functionName
lua_setfield(L, -2, ("set_" + field).c_str());
// pop the table
lua_pop(L, 1);
}
}
void ScriptContext::registerMemberFunction(const std::string& functionName, LuaCFunction function)
{
int functionId = m_functions.size();
m_functions.push_back(function);
// push the class table
lua_getfield(L, LUA_GLOBALSINDEX, m_currentClass.c_str());
// push the function id
lua_pushnumber(L, functionId);
// store id in the closure
lua_pushcclosure(L, &ScriptContext::luaFunctionCallback, 1);
// store the function at the class field functionName
lua_setfield(L, -2, functionName.c_str());
// pop the table
lua_pop(L, 1);
}
void ScriptContext::registerGlobalFunction(const std::string& functionName, LuaCFunction function)
{
int functionId = m_functions.size();
m_functions.push_back(function);
// push the function id
lua_pushnumber(L, functionId);
// store id in the closure
lua_pushcclosure(L, &ScriptContext::luaFunctionCallback, 1);
// store the function in the global lua table
lua_setfield(L, LUA_GLOBALSINDEX, functionName.c_str());
}
void ScriptContext::registerModule(const std::string& module)
{
registerClass(module);
lua_getfield(L, LUA_GLOBALSINDEX, module.c_str());
lua_getfield(L, LUA_REGISTRYINDEX, (module + "_mt").c_str());
lua_setmetatable(L, -2);
lua_pop(L, -1);
}
int ScriptContext::luaPackageLoader(lua_State* L)
{
std::string fileName = lua_tostring(L, -1);
fileName += ".lua";
if(g_resources.fileExists(fileName)) {
std::stringstream fin;
if(g_resources.loadFile(fileName, fin))
luaL_loadbuffer(L, fin.str().c_str(), fin.str().length(), ("@" + g_resources.resolvePath(fileName)).c_str());
} else {
lua_pushfstring(L, "\n\tcould not load lua script " LUA_QS, fileName.c_str());
}
return 1;
}
int ScriptContext::luaIndexMetaMethod(lua_State* L)
{
// stack: key, obj
std::string key = lua_tostring(L, -1); // key, obj
lua_pop(L, 1); // obj
lua_getmetatable(L, -1); // mt, obj
lua_getfield(L, -1, "fieldmethods"); // fieldmethods, mt, obj
lua_getfield(L, -1, ("get_" + key).c_str()); // get_method, fieldmethods, mt, obj
lua_remove(L, -2); // get_method, mt, obj
if(!lua_isnil(L, -1)) {
lua_remove(L, -2); // get_method, obj
lua_insert(L, -2); // obj, get_method
if(!g_lua.callFunction(1, 1))
lua_pushnil(L);
return 1;
} else {
lua_pop(L, 1); // mt, obj
lua_getfield(L, -1, "methods"); // methods, mt, obj
lua_getfield(L, -1, key.c_str()); // method, methods, mt, obj
lua_remove(L, -2); // method, mt, obj
if(!lua_isnil(L, -1)) {
lua_insert(L, -3); // mt, obj, method
lua_pop(L, 2); // method
return 1;
}
lua_pop(L, 1); // mt, obj
}
lua_pop(L, 1); // obj
// stack: obj
if(g_lua.isTable()) {
g_lua.rawGet(key);
g_lua.remove(-2);
} else if(g_lua.isUserdata()) {
g_lua.getScriptObjectField(g_lua.popClassInstance(), key);
} else {
g_lua.pop();
g_lua.pushNil();
g_lua.reportErrorWithTraceback("unknown type in newindex metamethod");
}
return 1;
}
int ScriptContext::luaNewIndexMetaMethod(lua_State* L)
{
// stack: value, key, obj
lua_insert(L, -2); // key, value, obj
std::string key = lua_tostring(L, -1);
lua_pop(L, 1); // value, obj
lua_getmetatable(L, -2); // mt, value, obj
lua_getfield(L, -1, "fieldmethods"); // fieldmethods, mt, value, obj
lua_getfield(L, -1, ("set_" + key).c_str()); // set_method, fieldmethods, mt, value, obj
lua_remove(L, -2); // set_method, mt, value, obj
if(!lua_isnil(L, -1)) {
lua_remove(L, -2); // set_method, value, obj
lua_insert(L, -3); // value, obj, set_method
g_lua.callFunction(2);
return 1;
}
lua_pop(L, 2); // mt, value, obj
// stack: value, obj
g_lua.insert(-2);
if(g_lua.isTable()) {
g_lua.insert(-2);
g_lua.rawSet(key);
g_lua.pop();
} else if(g_lua.isUserdata()) {
g_lua.setScriptObjectField(g_lua.popClassInstance(), key);
} else {
g_lua.pop(2);
g_lua.reportErrorWithTraceback("unknown type in index metamethod");
}
return 1;
}
int ScriptContext::luaEqualMetaMethod(lua_State* L)
{
if(!lua_isuserdata(L, -1) || !lua_isuserdata(L, -2)) {
lua_pop(L, 2);
lua_pushboolean(L, 0);
} else {
ScriptObjectPtr *objectRef1 = (ScriptObjectPtr *)lua_touserdata(L, -1);
ScriptObjectPtr *objectRef2 = (ScriptObjectPtr *)lua_touserdata(L, -2);
lua_pop(L, 2);
if(objectRef1 == objectRef2)
lua_pushboolean(L, 1);
else
lua_pushboolean(L, 0);
}
return 1;
}
int ScriptContext::luaGarbageCollectMetaMethod(lua_State* L)
{
if(lua_isuserdata(L, -1)) {
ScriptObjectPtr *objectRef = (ScriptObjectPtr *)lua_touserdata(L, -1);
objectRef->reset();
}
lua_pop(L, 1);
return 1;
}
int ScriptContext::luaFunctionCallback(lua_State* L)
{
// look for function id
int id = lua_tonumber(L, lua_upvalueindex(1));
g_resources.pushCurrentPath(g_lua.getFunctionSourcePath(false));
// call the function
int ret = (*(g_lua.m_functions[id]))();
g_resources.popCurrentPath();
return ret;
}
int ScriptContext::luaErrorHandler(lua_State *L)
{
// push debug
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if(!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
// push debug.traceback
lua_getfield(L, -1, "traceback");
if(!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
// remove debug
lua_remove(L, -2);
// push additional error message
lua_pushvalue(L, -2);
// push level
lua_pushinteger(L, 2);
// call debug.traceback
lua_call(L, 2, 1);
// remove additional error message
lua_remove(L, -2);
// return, the complete error message is on the stack
return 1;
}

View File

@@ -1,115 +0,0 @@
#ifndef SCRIPTCONTEXT_H
#define SCRIPTCONTEXT_H
#include <global.h>
#include "scriptobject.h"
#define reportFuncError(a) reportError(a, __FUNCTION__)
#define reportFuncErrorWithTraceback(a) reportErrorWithTraceback(a, __FUNCTION__)
struct lua_State;
class ScriptContext
{
public:
ScriptContext() : L(NULL) { }
void init();
void terminate();
void loadAllModules();
bool loadFile(const std::string& fileName);
bool loadBuffer(const std::string& text, const std::string& what = "luaBuffer");
bool loadBufferAsFunction(const std::string& text, const std::string& what = "luaBuffer");
void reportError(const std::string& errorDesc, const char *funcName = NULL);
void reportErrorWithTraceback(const std::string& errorDesc, const char *funcName = NULL);
void collectGarbage();
int getStackSize();
void insert(int index);
void swap(int index);
void remove(int index);
bool next(int index = -2);
void releaseRef(int ref);
void newTable();
void setTable(int index = -3);
void *newUserdata(int size);
void newMetatable(const std::string& name);
void setMetatable(const std::string& name, int index = -1);
void rawGet(const std::string& key);
void rawSet(const std::string& key);
void getField(const std::string& key);
void setField(const std::string& key);
void getScriptObjectField(const ScriptObjectPtr& scriptobject, const std::string& field);
void setScriptObjectField(const ScriptObjectPtr& scriptobject, const std::string& field);
void rawGetGlobalTableField(const std::string& globalTable, const std::string& key);
void rawSetGlobalTableField(const std::string& globalTable, const std::string& key);
void getGlobal(const std::string& key);
void setGlobal(const std::string& key);
bool isNil(int index = -1);
bool isBoolean(int index = -1);
bool isNumber(int index = -1);
bool isString(int index = -1);
bool isTable(int index = -1);
bool isUserdata(int index = -1);
bool isFunction(int index = -1);
bool isCFunction(int index = -1);
bool isLuaFunction(int index = -1);
void pop(int n = 1);
bool popBoolean();
int popInteger();
std::string popString();
ScriptObjectPtr popClassInstance();
int popRef();
void pushNil();
void pushBoolean(bool b);
void pushInteger(int i);
void pushString(const std::string& str);
void pushClassInstance(const ScriptObjectPtr& object);
void pushValue(int index = -1);
void pushRef(int ref);
std::string getFunctionSourcePath(bool functionIsOnStack, int level = 1);
bool callFunction(int numArgs = 0, int numRets = 0);
void callModuleField(const std::string& module, const std::string& field);
typedef int (*LuaCFunction)();
void setupPackageLoader();
void registerClass(const std::string& klass, const std::string& baseClass = "");
void registerMemberField(const std::string& field, LuaCFunction getFunction, LuaCFunction setFunction = NULL);
void registerMemberFunction(const std::string& functionName, LuaCFunction function);
void registerGlobalFunction(const std::string& functionName, LuaCFunction function);
void registerModule(const std::string& module);
static int luaPackageLoader(lua_State* L);
static int luaIndexMetaMethod(lua_State* L);
static int luaNewIndexMetaMethod(lua_State* L);
static int luaEqualMetaMethod(lua_State* L);
static int luaGarbageCollectMetaMethod(lua_State* L);
static int luaFunctionCallback(lua_State* L);
static int luaErrorHandler(lua_State *L);
private:
std::vector<LuaCFunction> m_functions;
std::string m_currentClass;
lua_State *L;
};
extern ScriptContext g_lua;
#endif // SCRIPTCONTEXT_H

View File

@@ -1,561 +0,0 @@
#include <global.h>
#include <script/scriptfunctions.h>
#include <script/scriptcontext.h>
#include <core/engine.h>
#include <core/resources.h>
#include <ui/ui.h>
#include <core/dispatcher.h>
#include "../../protocollogin.h"
#include <boost/algorithm/string.hpp>
////////////////////////////////////////////////////////////////////////////////
// App
int lua_App_exit() {
g_engine.stop();
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// UI
int lua_UI_load() {
UIContainerPtr parent;
if(g_lua.getStackSize() > 1)
parent = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
else
parent = UIContainer::getRoot();
std::string uiFile = g_lua.popString();
if(!boost::ends_with(uiFile, ".otml"))
uiFile.append(".otml");
UIElementPtr element;
if(parent) {
element = g_uiLoader.loadFromFile(uiFile.c_str(), parent);
if(!element) {
g_lua.reportFuncErrorWithTraceback("failed to load UI");
}
} else
g_lua.reportFuncErrorWithTraceback("invalid parent container");
g_lua.pushClassInstance(element);
return 1;
}
int lua_UI_getRootContainer() {
UIContainerPtr rootContainer = UIContainer::getRoot();
g_lua.pushClassInstance(rootContainer);
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// UIElement
UIElementPtr lua_createUIElement(UI::ElementType elementType)
{
std::string id;
UIContainerPtr parent;
if(g_lua.getStackSize() > 1)
parent = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
if(g_lua.getStackSize() > 0) {
if(g_lua.isString())
id = g_lua.popString();
else
parent = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
}
UIElementPtr element;
switch(elementType) {
case UI::Element:
element = UIElementPtr(new UIElement);
break;
case UI::Container:
element = UIElementPtr(new UIContainer);
break;
case UI::Label:
element = UIElementPtr(new UILabel);
break;
case UI::Button:
element = UIElementPtr(new UIButton);
break;
case UI::TextEdit:
element = UIElementPtr(new UITextEdit);
break;
case UI::Window:
element = UIElementPtr(new UIWindow);
break;
default:
break;
}
if(element) {
if(!id.empty())
element->setId(id);
if(parent)
parent->addChild(element);
element->applyDefaultSkin();
}
return element;
}
int lua_UIElement_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::Element));
return 1;
}
int lua_UIElement_getId() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushString(element->getId());
else
g_lua.pushNil();
return 1;
}
int lua_UIElement_setId() {
std::string id = g_lua.popString();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setId(id);
return 0;
}
int lua_UIElement_isEnabled() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isEnabled());
else
g_lua.pushNil();
return 1;
}
int lua_UIElement_setEnabled() {
bool enabled = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setEnabled(enabled);
return 0;
}
int lua_UIElement_isVisible() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isVisible());
else
g_lua.pushNil();
return 1;
}
int lua_UIElement_setVisible() {
bool visible = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setVisible(visible);
return 0;
}
int lua_UIElement_isFocused() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isFocused());
else
g_lua.pushNil();
return 1;
}
int lua_UIElement_setFocused() {
bool focused = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setFocused(focused);
return 0;
}
int lua_UIElement_getWidth() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushInteger(element->getWidth());
else
g_lua.pushInteger(0);
return 1;
}
int lua_UIElement_setWidth() {
int width = g_lua.popInteger();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setWidth(width);
return 0;
}
int lua_UIElement_getHeight() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushInteger(element->getHeight());
else
g_lua.pushInteger(0);
return 1;
}
int lua_UIElement_setHeight() {
int height = g_lua.popInteger();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setHeight(height);
return 0;
}
int lua_UIElement_getParent() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushClassInstance(element->getParent());
else
g_lua.pushNil();
return 1;
}
int lua_UIElement_setParent() {
UIContainerPtr parent = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setParent(parent);
return 0;
}
int lua_UIElement_setLocked() {
bool locked = true;
if(g_lua.getStackSize() > 1)
locked = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
if(UIContainerPtr container = element->getParent()) {
if(locked)
container->lockElement(element);
else
container->unlockElement(element);
} else
g_lua.reportFuncErrorWithTraceback("locking failed, element has no parent");
}
return 0;
}
int lua_UIElement_setMargin() {
int top = 0, right = 0, bottom = 0, left = 0;
if(g_lua.getStackSize() == 5) {
left = g_lua.popInteger();
bottom = g_lua.popInteger();
right = g_lua.popInteger();
top = g_lua.popInteger();
} else if(g_lua.getStackSize() == 3) {
left = right = g_lua.popInteger();
top = bottom = g_lua.popInteger();
} else if(g_lua.getStackSize() == 2) {
top = right = bottom = left = g_lua.popInteger();
} else {
g_lua.reportFuncErrorWithTraceback("invalid number of arguments");
}
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setMargin(top, right, bottom, left);
return 0;
}
int lua_UIElement_destroy() {
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->destroyLater();
g_dispatcher.addTask(boost::bind(&ScriptContext::collectGarbage, &g_lua));
return 0;
}
int lua_UIElement_centerIn() {
std::string targetId;
if(g_lua.isString())
targetId = g_lua.popString();
else if(UIElementPtr target = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
targetId = target->getId();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->centerIn(targetId);
return 0;
}
int lua_UIElement_addAnchor() {
AnchorPoint targetEdge = (AnchorPoint)g_lua.popInteger();
std::string targetId;
if(g_lua.isString())
targetId = g_lua.popString();
else if(UIElementPtr target = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
targetId = target->getId();
AnchorPoint anchoredEdge = (AnchorPoint)g_lua.popInteger();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->addAnchor(anchoredEdge, AnchorLine(targetId, targetEdge));
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// UIContainer
int lua_UIContainer_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::Container));
return 1;
}
int lua_UIContainer_child() {
std::string id = g_lua.popString();
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
g_lua.pushClassInstance(container->getChildById(id));
else
g_lua.pushNil();
return 1;
}
int lua_UIContainer_getChildren() {
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance())) {
g_lua.newTable();
foreach(const UIElementPtr& child, container->getChildren()) {
g_lua.pushClassInstance(child);
if(child->getId().length())
g_lua.setField(child->getId());
}
} else
g_lua.pushNil();
return 1;
}
int lua_UIContainer_addChild() {
UIElementPtr child = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance());
UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
if(container && child)
container->addChild(child);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// UILabel
int lua_UILabel_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::Label));
return 1;
}
int lua_UILabel_setText() {
std::string text = g_lua.popString();
if(UILabelPtr label = boost::dynamic_pointer_cast<UILabel>(g_lua.popClassInstance()))
label->setText(text);
return 0;
}
int lua_UILabel_getText() {
if(UILabelPtr label = boost::dynamic_pointer_cast<UILabel>(g_lua.popClassInstance()))
g_lua.pushString(label->getText());
else
g_lua.pushNil();
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// UIButton
int lua_UIButton_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::Button));
return 1;
}
int lua_UIButton_setText() {
std::string text = g_lua.popString();
if(UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(g_lua.popClassInstance()))
button->setText(text);
return 0;
}
int lua_UIButton_getText() {
if(UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(g_lua.popClassInstance()))
g_lua.pushString(button->getText());
else
g_lua.pushNil();
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// UITextEdit
int lua_UITextEdit_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::TextEdit));
return 1;
}
int lua_UITextEdit_setText() {
std::string text = g_lua.popString();
if(UITextEditPtr textEdit = boost::dynamic_pointer_cast<UITextEdit>(g_lua.popClassInstance()))
textEdit->setText(text);
return 0;
}
int lua_UITextEdit_getText() {
if(UITextEditPtr textEdit = boost::dynamic_pointer_cast<UITextEdit>(g_lua.popClassInstance()))
g_lua.pushString(textEdit->getText());
else
g_lua.pushNil();
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// UIWindow
int lua_UIWindow_new() {
g_lua.pushClassInstance(lua_createUIElement(UI::Window));
return 1;
}
int lua_UIWindow_setTitle() {
std::string title = g_lua.popString();
if(UIWindowPtr window = boost::dynamic_pointer_cast<UIWindow>(g_lua.popClassInstance()))
window->setTitle(title);
return 0;
}
int lua_UIWindow_getTitle() {
if(UIWindowPtr window = boost::dynamic_pointer_cast<UIWindow>(g_lua.popClassInstance()))
g_lua.pushString(window->getTitle());
else
g_lua.pushNil();
return 1;
}
void registerScriptFunctions()
{
////////////////////////////////////////////////////////////////////////////////
// App
g_lua.registerModule("App");
// App.exit()
g_lua.registerMemberFunction("exit", &lua_App_exit);
////////////////////////////////////////////////////////////////////////////////
// UI
g_lua.registerClass("UI");
// UI.load(file, [parent])
g_lua.registerMemberFunction("load", &lua_UI_load);
// UI.getRootContainer()
g_lua.registerMemberFunction("getRootContainer", &lua_UI_getRootContainer);
////////////////////////////////////////////////////////////////////////////////
// UIElement
g_lua.registerClass("UIElement");
// (UIElement) UIElement.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIElement_new);
// (string) UIElement.id
g_lua.registerMemberField("id", &lua_UIElement_getId, &lua_UIElement_setId);
// (boolean) UIElement.enabled
g_lua.registerMemberField("enabled", &lua_UIElement_isEnabled, &lua_UIElement_setEnabled);
// (boolean UIElement.visible
g_lua.registerMemberField("visible", &lua_UIElement_isVisible, &lua_UIElement_setVisible);
// (boolean UIElement.focused
g_lua.registerMemberField("focused", &lua_UIElement_isFocused, &lua_UIElement_setFocused);
// (integer) UIElement.width
g_lua.registerMemberField("width", &lua_UIElement_getWidth, &lua_UIElement_setWidth);
// (integer) UIElement.height
g_lua.registerMemberField("height", &lua_UIElement_getHeight, &lua_UIElement_setHeight);
// (UIContainer UIElement.parent
g_lua.registerMemberField("parent", &lua_UIElement_getParent, &lua_UIElement_setParent);
// element:setLocked(boolean locked)
g_lua.registerMemberFunction("setLocked", &lua_UIElement_setLocked);
// element:setMargin(int all)
// element:setMargin(int vertical, int horizontal)
// element:setMargin(int top, right, bottom, left)
g_lua.registerMemberFunction("setMargin", &lua_UIElement_setMargin);
// element:destroy()
g_lua.registerMemberFunction("destroy", &lua_UIElement_destroy);
// element:centerIn(UIContainer target)
g_lua.registerMemberFunction("centerIn", &lua_UIElement_centerIn);
// element:addAnchor(AnchorPoint anchoredEdge, UIElement target, AnchorPoint targetEdge)
// element:addAnchor(AnchorPoint anchoredEdge, string targetId, AnchorPoint targetEdge)
g_lua.registerMemberFunction("addAnchor", &lua_UIElement_addAnchor);
////////////////////////////////////////////////////////////////////////////////
// UIContainer
g_lua.registerClass("UIContainer", "UIElement");
// UIContainer.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIContainer_new);
// container:child(string id)
g_lua.registerMemberFunction("child", &lua_UIContainer_child);
// (table) container:children()
g_lua.registerMemberFunction("children", &lua_UIContainer_getChildren);
// container:addChild(UIElement child)
g_lua.registerMemberFunction("addChild", &lua_UIContainer_addChild);
////////////////////////////////////////////////////////////////////////////////
// UILabel
g_lua.registerClass("UILabel", "UIElement");
// UILabel.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UILabel_new);
// label.text
g_lua.registerMemberField("text", &lua_UILabel_getText, &lua_UILabel_setText);
////////////////////////////////////////////////////////////////////////////////
// UIButton
g_lua.registerClass("UIButton", "UIElement");
// UIButton.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIButton_new);
// button.text
g_lua.registerMemberField("text", &lua_UIButton_getText, &lua_UIButton_setText);
////////////////////////////////////////////////////////////////////////////////
// UITextEdit
g_lua.registerClass("UITextEdit", "UIElement");
// UITextEdit.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UITextEdit_new);
// textEdit.text
g_lua.registerMemberField("text", &lua_UITextEdit_getText, &lua_UITextEdit_setText);
////////////////////////////////////////////////////////////////////////////////
// UIWindow
g_lua.registerClass("UIWindow", "UIContainer");
// UIWindow.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIWindow_new);
// window.title
g_lua.registerMemberField("title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle);
////////////////////////////////////////////////////////////////////////////////
// Protocol
g_lua.registerClass("ProtocolLogin");
g_lua.registerMemberFunction("new", []{
g_lua.pushClassInstance(ScriptObjectPtr(new ProtocolLogin));
return 1;
});
g_lua.registerMemberFunction("login", []{
std::string accountPassword = g_lua.popString();
std::string accountName = g_lua.popString();
if(ProtocolLoginPtr protocolLogin = boost::dynamic_pointer_cast<ProtocolLogin>(g_lua.popClassInstance()))
protocolLogin->login(accountName, accountPassword);
return 0;
});
g_lua.registerMemberFunction("cancel", []{
//TODO: this func
return 0;
});
}

View File

@@ -1,10 +0,0 @@
#ifndef SCRIPTFUNCTIONS_H
#define SCRIPTFUNCTIONS_H
#include <global.h>
#include "scriptobject.h"
void registerScriptFunctions();
#endif // SCRIPTFUNCTIONS_H

View File

@@ -1,54 +0,0 @@
#include "scriptobject.h"
#include "scriptcontext.h"
#include <core/dispatcher.h>
void ScriptObject::releaseScriptObject()
{
if(m_scriptTableRef != -1) {
g_lua.releaseRef(m_scriptTableRef);
m_scriptTableRef = -1;
}
}
int ScriptObject::getScriptTable()
{
if(m_scriptTableRef == -1) {
g_lua.newTable();
m_scriptTableRef = g_lua.popRef();
}
return m_scriptTableRef;
}
void ScriptObject::callScriptTableField(const std::string& field, int numArgs)
{
// set self
g_lua.pushClassInstance(shared_from_this());
g_lua.setGlobal("self");
// push field
g_lua.getScriptObjectField(shared_from_this(), field);
// call it if its a function
if(g_lua.isFunction()) {
g_lua.insert(-numArgs-1);
g_lua.callFunction(numArgs);
// if its an array call each element
} else if(g_lua.isTable()) {
//TODO: call here with arguments
g_lua.pushNil();
while(g_lua.next()) {
// call it if its a function
if(g_lua.isFunction())
g_lua.callFunction();
g_lua.pop();
}
} else if(!g_lua.isNil()) {
g_lua.reportError(make_string("field '", field, "' for '", getScriptObjectType(), "' is not a valid function or array of functions"));
}
// release self
g_lua.pushNil();
g_lua.setGlobal("self");
}

View File

@@ -1,26 +0,0 @@
#ifndef SCRIPTOBJECT_H
#define SCRIPTOBJECT_H
#include <global.h>
class ScriptObject : public boost::enable_shared_from_this<ScriptObject>
{
public:
ScriptObject() : m_scriptTableRef(-1) { }
virtual ~ScriptObject() { releaseScriptObject(); }
void releaseScriptObject();
//TODO: global destroy
virtual const char *getScriptObjectType() const { return NULL; }
int getScriptTable();
void callScriptTableField(const std::string& field, int numArgs = 0);
private:
int m_scriptTableRef;
};
typedef boost::shared_ptr<ScriptObject> ScriptObjectPtr;
#endif // SCRIPTOBJECT_H

View File

@@ -0,0 +1,285 @@
#include <global.h>
#include <script/luafunctions.h>
#include <script/luacontext.h>
#include <core/engine.h>
#include <core/resources.h>
#include <ui/ui.h>
#include <core/dispatcher.h>
#include "../../protocollogin.h"
#include <boost/algorithm/string.hpp>
int lua_App_exit() {
g_engine.stop();
return 0;
}
int lua_App_loadUI() {
UIContainerPtr parent;
if(g_lua.stackSize() > 1)
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
else
parent = UIContainer::getRoot();
std::string uiFile = g_lua.popString();
if(!boost::ends_with(uiFile, ".otml"))
uiFile.append(".otml");
UIElementPtr element;
if(parent) {
element = g_uiLoader.loadFromFile(uiFile.c_str(), parent);
if(!element) {
g_lua.reportFuncErrorWithTraceback("failed to load UI");
}
} else
g_lua.reportFuncErrorWithTraceback("invalid parent container");
g_lua.pushLuaObjectInstance(element);
return 1;
}
int lua_App_getRootContainer() {
UIContainerPtr rootContainer = UIContainer::getRoot();
g_lua.pushLuaObjectInstance(rootContainer);
return 1;
}
UIElementPtr lua_createUIElement(UI::ElementType elementType)
{
std::string id;
UIContainerPtr parent;
if(g_lua.stackSize() > 1)
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
if(g_lua.stackSize() > 0) {
if(g_lua.isString())
id = g_lua.popString();
else
parent = std::dynamic_pointer_cast<UIContainer>(g_lua.popLuaObjectInstance());
}
UIElementPtr element;
switch(elementType) {
case UI::Element:
element = UIElementPtr(new UIElement);
break;
case UI::Container:
element = UIElementPtr(new UIContainer);
break;
case UI::Label:
element = UIElementPtr(new UILabel);
break;
case UI::Button:
element = UIElementPtr(new UIButton);
break;
case UI::TextEdit:
element = UIElementPtr(new UITextEdit);
break;
case UI::Window:
element = UIElementPtr(new UIWindow);
break;
default:
break;
}
if(element) {
if(!id.empty())
element->setId(id);
if(parent)
parent->addChild(element);
element->applyDefaultSkin();
}
return element;
}
int lua_UIElement_setLocked() {
bool locked = true;
if(g_lua.stackSize() > 1)
locked = g_lua.popBoolean();
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance())) {
if(UIContainerPtr container = element->getParent()) {
if(locked)
container->lockElement(element);
else
container->unlockElement(element);
} else
g_lua.reportFuncErrorWithTraceback("locking failed, element has no parent");
}
return 0;
}
int lua_UIElement_setMargin() {
int top = 0, right = 0, bottom = 0, left = 0;
if(g_lua.stackSize() == 5) {
left = g_lua.popInteger();
bottom = g_lua.popInteger();
right = g_lua.popInteger();
top = g_lua.popInteger();
} else if(g_lua.stackSize() == 3) {
left = right = g_lua.popInteger();
top = bottom = g_lua.popInteger();
} else if(g_lua.stackSize() == 2) {
top = right = bottom = left = g_lua.popInteger();
} else {
g_lua.reportFuncErrorWithTraceback("invalid number of arguments");
}
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
element->setMargin(top, right, bottom, left);
return 0;
}
int lua_UIElement_centerIn() {
std::string targetId;
if(g_lua.isString())
targetId = g_lua.popString();
else if(UIElementPtr target = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
targetId = target->getId();
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
element->centerIn(targetId);
return 0;
}
int lua_UIElement_addAnchor() {
AnchorPoint targetEdge = (AnchorPoint)g_lua.popInteger();
std::string targetId;
if(g_lua.isString())
targetId = g_lua.popString();
else if(UIElementPtr target = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
targetId = target->getId();
AnchorPoint anchoredEdge = (AnchorPoint)g_lua.popInteger();
if(UIElementPtr element = std::dynamic_pointer_cast<UIElement>(g_lua.popLuaObjectInstance()))
element->addAnchor(anchoredEdge, AnchorLine(targetId, targetEdge));
return 0;
}
void registerScriptFunctions()
{
////////////////////////////////////////////////////////////////////////////////
// App
g_lua.registerModule("App");
// App.exit()
g_lua.registerMemberFunction("exit", &lua_App_exit);
// App.loadUI(file, [parent])
g_lua.registerMemberFunction("loadUI", &lua_App_loadUI);
// App.getRootContainer()
g_lua.registerMemberFunction("getRootContainer", &lua_App_getRootContainer);
////////////////////////////////////////////////////////////////////////////////
// UIElement
g_lua.registerClass("UIElement");
// (UIElement) UIElement.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIElement_new);
// (string) UIElement.id
g_lua.registerMemberField("id", &lua_UIElement_getId, &lua_UIElement_setId);
// (boolean) UIElement.enabled
g_lua.registerMemberField("enabled", &lua_UIElement_isEnabled, &lua_UIElement_setEnabled);
// (boolean UIElement.visible
g_lua.registerMemberField("visible", &lua_UIElement_isVisible, &lua_UIElement_setVisible);
// (boolean UIElement.focused
g_lua.registerMemberField("focused", &lua_UIElement_isFocused, &lua_UIElement_setFocused);
// (integer) UIElement.width
g_lua.registerMemberField("width", &lua_UIElement_getWidth, &lua_UIElement_setWidth);
// (integer) UIElement.height
g_lua.registerMemberField("height", &lua_UIElement_getHeight, &lua_UIElement_setHeight);
// (UIContainer UIElement.parent
g_lua.registerMemberField("parent", &lua_UIElement_getParent, &lua_UIElement_setParent);
// element:setLocked(boolean locked)
g_lua.registerMemberFunction("setLocked", &lua_UIElement_setLocked);
// element:setMargin(int all)
// element:setMargin(int vertical, int horizontal)
// element:setMargin(int top, right, bottom, left)
g_lua.registerMemberFunction("setMargin", &lua_UIElement_setMargin);
// element:destroy()
g_lua.registerMemberFunction("destroy", &lua_UIElement_destroy);
// element:centerIn(UIContainer target)
g_lua.registerMemberFunction("centerIn", &lua_UIElement_centerIn);
// element:addAnchor(AnchorPoint anchoredEdge, UIElement target, AnchorPoint targetEdge)
// element:addAnchor(AnchorPoint anchoredEdge, string targetId, AnchorPoint targetEdge)
g_lua.registerMemberFunction("addAnchor", &lua_UIElement_addAnchor);
////////////////////////////////////////////////////////////////////////////////
// UIContainer
g_lua.registerClass("UIContainer", "UIElement");
// UIContainer.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIContainer_new);
// container:child(string id)
g_lua.registerMemberFunction("child", &lua_UIContainer_child);
// (table) container:children()
g_lua.registerMemberFunction("children", &lua_UIContainer_getChildren);
// container:addChild(UIElement child)
g_lua.registerMemberFunction("addChild", &lua_UIContainer_addChild);
////////////////////////////////////////////////////////////////////////////////
// UILabel
g_lua.registerClass("UILabel", "UIElement");
// UILabel.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UILabel_new);
// label.text
g_lua.registerMemberField("text", &lua_UILabel_getText, &lua_UILabel_setText);
////////////////////////////////////////////////////////////////////////////////
// UIButton
g_lua.registerClass("UIButton", "UIElement");
// UIButton.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIButton_new);
// button.text
g_lua.registerMemberField("text", &lua_UIButton_getText, &lua_UIButton_setText);
////////////////////////////////////////////////////////////////////////////////
// UITextEdit
g_lua.registerClass("UITextEdit", "UIElement");
// UITextEdit.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UITextEdit_new);
// textEdit.text
g_lua.registerMemberField("text", &lua_UITextEdit_getText, &lua_UITextEdit_setText);
////////////////////////////////////////////////////////////////////////////////
// UIWindow
g_lua.registerClass("UIWindow", "UIContainer");
// UIWindow.new([UIContainer parent], [string id])
g_lua.registerMemberFunction("new", &lua_UIWindow_new);
// window.title
g_lua.registerMemberField("title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle);
////////////////////////////////////////////////////////////////////////////////
// Protocol
g_lua.registerClass("ProtocolLogin");
g_lua.registerMemberFunction("new", []{
g_lua.pushLuaObjectInstance(LuaObjectPtr(new ProtocolLogin));
return 1;
});
g_lua.registerMemberFunction("login", []{
std::string accountPassword = g_lua.popString();
std::string accountName = g_lua.popString();
if(ProtocolLoginPtr protocolLogin = std::dynamic_pointer_cast<ProtocolLogin>(g_lua.popLuaObjectInstance()))
protocolLogin->login(accountName, accountPassword);
return 0;
});
g_lua.registerMemberFunction("cancel", []{
//TODO: this func
return 0;
});
}

View File

@@ -5,8 +5,8 @@
#include <ui/uilayout.h>
class UIElement;
typedef boost::shared_ptr<UIElement> UIElementPtr;
typedef boost::weak_ptr<UIElement> UIElementWeakPtr;
typedef std::shared_ptr<UIElement> UIElementPtr;
typedef std::weak_ptr<UIElement> UIElementWeakPtr;
enum AnchorPoint {
AnchorNone = 0,
@@ -61,6 +61,6 @@ private:
std::vector<Anchor> m_anchors;
};
typedef boost::shared_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
typedef std::shared_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
#endif // UIANCHORLAYOUT_H

View File

@@ -10,7 +10,10 @@ void UIButton::onInputEvent(const InputEvent& event)
} else if(event.type == EV_MOUSE_LUP && m_state == ButtonDown) {
m_state = ButtonUp;
if(getRect().contains(event.mousePos)) {
g_dispatcher.addTask(boost::bind(&ScriptObject::callScriptTableField, shared_from_this(), "onClick", 0));
LuaObjectPtr me = asLuaObject();
g_dispatcher.addTask([me] {
me->callField("onClick");
});
}
} else if(event.type == EV_MOUSE_MOVE && m_state != ButtonDown) {
if(isMouseOver())

View File

@@ -6,7 +6,7 @@
#include <graphics/borderedimage.h>
class UIButton;
typedef boost::shared_ptr<UIButton> UIButtonPtr;
typedef std::shared_ptr<UIButton> UIButtonPtr;
class UIButton : public UIElement
{
@@ -22,6 +22,8 @@ public:
UIElement(UI::Button),
m_state(ButtonUp) { }
static UIButtonPtr create() { return UIButtonPtr(new UIButton); }
void onInputEvent(const InputEvent& event);
void setText(const std::string& text) { m_text = text; }
@@ -29,7 +31,7 @@ public:
ButtonState getState() { return m_state; }
virtual const char *getScriptObjectType() const { return "UIButton"; }
virtual const char *getLuaTypeName() const { return "UIButton"; }
private:
std::string m_text;

View File

@@ -11,7 +11,7 @@ struct UIButtonStateSkin {
Point textTranslate;
Color textColor;
};
typedef boost::shared_ptr<UIButtonStateSkin> UIButtonStateSkinPtr;
typedef std::shared_ptr<UIButtonStateSkin> UIButtonStateSkinPtr;
class UIButtonSkin : public UIElementSkin
{

View File

@@ -9,7 +9,7 @@ class UICheckBox : public UIElement
public:
UICheckBox(UI::ElementType type = UI::Element);
virtual const char *getScriptObjectType() const { return "UICheckBox"; }
virtual const char *getLuaTypeName() const { return "UICheckBox"; }
};
#endif // UICHECKBOX_H

View File

@@ -67,18 +67,48 @@ UIElementPtr UIContainer::getChildById(const std::string& id)
{
if(getId() == id || id == "self")
return asUIElement();
if(id == "parent")
else if(id == "parent")
return getParent();
if(id == "root")
else if(id == "root")
return getRoot();
foreach(const UIElementPtr& child, m_children) {
if(child->getId() == id)
return child;
else if(id == "prev") {
if(UIContainerPtr parent = getParent())
return parent->getChildBefore(asUIElement());
} else if(id == "next") {
if(UIContainerPtr parent = getParent())
return parent->getChildAfter(asUIElement());
} else {
foreach(const UIElementPtr& child, m_children) {
if(child->getId() == id)
return child;
}
}
return UIElementPtr();
}
UIElementPtr UIContainer::getChildBefore(const UIElementPtr& reference)
{
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
const UIElementPtr& element = (*it);
if(element == reference) {
if(++it != m_children.rend())
return (*it);
break;
}
}
return UIElementPtr();
}
UIElementPtr UIContainer::getChildAfter(const UIElementPtr& reference)
{
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
const UIElementPtr& element = (*it);
if(element == reference) {
if(++it != m_children.end())
return (*it);
break;
}
}
return UIElementPtr();
}
@@ -86,26 +116,30 @@ UIElementPtr UIContainer::recursiveGetChildById(const std::string& id)
{
if(getId() == id || id == "self")
return asUIElement();
if(id == "parent")
else if(id == "parent")
return getParent();
if(id == "root")
else if(id == "root")
return getRoot();
foreach(const UIElementPtr& element, m_children) {
if(element->getId() == id)
return element;
else {
UIContainerPtr container = element->asUIContainer();
if(container) {
UIElementPtr element2 = container->recursiveGetChildById(id);
if(element2)
return element2;
else if(id == "prev") {
if(UIContainerPtr parent = getParent())
return parent->getChildBefore(asUIElement());
} else if(id == "next") {
if(UIContainerPtr parent = getParent())
return parent->getChildAfter(asUIElement());
} else {
foreach(const UIElementPtr& element, m_children) {
if(element->getId() == id)
return element;
else {
UIContainerPtr container = element->asUIContainer();
if(container) {
UIElementPtr element2 = container->recursiveGetChildById(id);
if(element2)
return element2;
}
}
}
}
return UIElementPtr();
}
@@ -239,7 +273,7 @@ void UIContainer::setFocusedElement(const UIElementPtr& focusedElement)
// when containers are focused they go to the top
if(focusedElement && focusedElement->asUIContainer()) {
g_dispatcher.addTask(boost::bind(&UIContainer::pushChildToTop, asUIContainer(), m_focusedElement));
g_dispatcher.addTask(std::bind(&UIContainer::pushChildToTop, asUIContainer(), m_focusedElement));
}
}

View File

@@ -11,6 +11,7 @@ public:
UIElement(type) { }
virtual ~UIContainer() { }
static UIContainerPtr create() { return UIContainerPtr(new UIContainer); }
virtual void destroy();
virtual void onLoad();
virtual void render();
@@ -28,6 +29,8 @@ public:
UIElementPtr recursiveGetChildById(const std::string& id);
/// Find an element by position
UIElementPtr getChildByPos(const Point& pos);
UIElementPtr getChildBefore(const UIElementPtr& reference);
UIElementPtr getChildAfter(const UIElementPtr& reference);
/// Find an element in this container and in its children by position
UIElementPtr recursiveGetChildByPos(const Point& pos);
/// Get children
@@ -37,6 +40,7 @@ public:
/// Return number of children
int getChildCount() const { return m_children.size(); }
/// Disable all children except the specified element
bool lockElement(const UIElementPtr& element);
/// Renable all children
@@ -50,9 +54,9 @@ public:
UIElementPtr getFocusedElement() const { return m_focusedElement; }
virtual UI::ElementType getElementType() const { return UI::Container; }
UIContainerPtr asUIContainer() { return boost::static_pointer_cast<UIContainer>(shared_from_this()); }
UIContainerPtr asUIContainer() { return std::static_pointer_cast<UIContainer>(shared_from_this()); }
virtual const char *getScriptObjectType() const { return "UIContainer"; }
virtual const char *getLuaTypeName() const { return "UIContainer"; }
/// Get root container (the container that contains everything)
static UIContainerPtr& getRoot();

View File

@@ -6,13 +6,15 @@
#include <ui/uielementskin.h>
#include <ui/uicontainer.h>
#include <ui/uianchorlayout.h>
#include <script/luainterface.h>
UIElement::UIElement(UI::ElementType type) :
ScriptObject(),
LuaObject(),
m_type(type),
m_visible(true),
m_enabled(true),
m_mouseOver(false),
m_destroyed(false),
m_marginLeft(0),
m_marginRight(0),
m_marginTop(0),
@@ -31,30 +33,33 @@ UIElement::~UIElement()
void UIElement::destroyLater()
{
//logTraceDebug(getId());
g_dispatcher.addTask(boost::bind(&UIElement::destroy, asUIElement()));
if(!m_destroyed)
g_dispatcher.addTask(std::bind(&UIElement::destroy, asUIElement()));
}
void UIElement::destroy()
{
//logTraceDebug(getId());
if(!m_destroyed) {
UIElementPtr me = asUIElement();
UIElementPtr me = asUIElement();
callScriptTableField("onDestroy");
// remove from parent
if(getParent())
getParent()->removeChild(me);
// remove from parent
if(getParent())
getParent()->removeChild(me);
g_dispatcher.addTask(std::bind(&UIElement::destroyCheck, me));
// free script stuff
releaseScriptObject();
g_dispatcher.addTask(boost::bind(&UIElement::destroyCheck, me));
m_destroyed = true;
}
}
void UIElement::destroyCheck()
{
//logTraceDebug(getId());
for(int i=0;i<2;++i)
g_lua.collectGarbage();
UIElementPtr me = asUIElement();
// check for leaks, the number of references must be always 2 here
if(me.use_count() != 2 && me != UIContainer::getRoot()) {
@@ -99,7 +104,10 @@ void UIElement::setSkin(const UIElementSkinPtr& skin)
void UIElement::onLoad()
{
g_dispatcher.addTask(boost::bind(&ScriptObject::callScriptTableField, shared_from_this(), "onLoad", 0));
UIElementPtr me = asUIElement();
g_dispatcher.addTask([me] {
me->callField("onLoad");
});
}
void UIElement::render()
@@ -111,24 +119,29 @@ void UIElement::render()
UIElementPtr UIElement::backwardsGetElementById(const std::string& id)
{
if(getId() == id || id == "self")
return asUIElement();
if(id == "parent")
return getParent();
if(id == "root")
return UIContainer::getRoot();
UIElementPtr element;
if(asUIContainer()) {
element = asUIContainer()->recursiveGetChildById(id);
if(element)
return element;
}
if(getId() == id || id == "self")
element = asUIElement();
else if(id == "parent")
element = getParent();
else if(id == "root")
element = UIContainer::getRoot();
else if(id == "prev") {
if(UIContainerPtr parent = getParent())
element = parent->getChildBefore(asUIElement());
} else if(id == "next") {
if(UIContainerPtr parent = getParent())
element = parent->getChildAfter(asUIElement());
} else {
if(asUIContainer()) {
element = asUIContainer()->recursiveGetChildById(id);
if(element)
return element;
}
if(getParent())
element = getParent()->backwardsGetElementById(id);
if(getParent())
element = getParent()->backwardsGetElementById(id);
}
return element;
}
@@ -153,6 +166,17 @@ void UIElement::moveTo(Point pos)
setRect(newRect);
}
void UIElement::setLocked(bool locked)
{
UIContainerPtr parent = getParent();
if(parent) {
if(locked)
parent->lockElement(asUIElement());
else
parent->unlockElement(asUIElement());
}
}
void UIElement::setParent(UIContainerPtr parent)
{
UIElementPtr me = asUIElement();
@@ -197,17 +221,13 @@ UILayoutPtr UIElement::getLayout() const
void UIElement::centerIn(const std::string& targetId)
{
addAnchor(AnchorHorizontalCenter, AnchorLine(targetId, AnchorHorizontalCenter));
addAnchor(AnchorVerticalCenter, AnchorLine(targetId, AnchorVerticalCenter));
addAnchor(AnchorHorizontalCenter, targetId, AnchorHorizontalCenter);
addAnchor(AnchorVerticalCenter, targetId, AnchorVerticalCenter);
}
void UIElement::addAnchor(AnchorPoint anchoredEdge, AnchorLine anchorEdge)
void UIElement::addAnchor(AnchorPoint edge, const std::string& targetId, AnchorPoint targetEdge)
{
UIElementPtr target = backwardsGetElementById(anchorEdge.getElementId());
if(!target)
logWarning("warning: element id '", anchorEdge.getElementId(), "' doesn't exist while anchoring element '", getId(), "'");
UIAnchorLayoutPtr layout = boost::dynamic_pointer_cast<UIAnchorLayout>(getLayout());
UIAnchorLayoutPtr layout = std::dynamic_pointer_cast<UIAnchorLayout>(getLayout());
if(layout)
layout->addAnchor(asUIElement(), anchoredEdge, anchorEdge);
layout->addAnchor(asUIElement(), edge, AnchorLine(targetId, targetEdge));
}

View File

@@ -3,7 +3,7 @@
#include <global.h>
#include <core/input.h>
#include <script/scriptobject.h>
#include <script/luaobject.h>
#include <ui/uianchorlayout.h>
namespace UI {
@@ -21,22 +21,23 @@ namespace UI {
}
class UIElementSkin;
typedef boost::shared_ptr<UIElementSkin> UIElementSkinPtr;
typedef std::shared_ptr<UIElementSkin> UIElementSkinPtr;
class UIContainer;
typedef boost::shared_ptr<UIContainer> UIContainerPtr;
typedef boost::weak_ptr<UIContainer> UIContainerWeakPtr;
typedef std::shared_ptr<UIContainer> UIContainerPtr;
typedef std::weak_ptr<UIContainer> UIContainerWeakPtr;
class UIElement;
typedef boost::shared_ptr<UIElement> UIElementPtr;
typedef boost::weak_ptr<UIElement> UIElementWeakPtr;
typedef std::shared_ptr<UIElement> UIElementPtr;
typedef std::weak_ptr<UIElement> UIElementWeakPtr;
class UIElement : public ScriptObject
class UIElement : public LuaObject
{
public:
UIElement(UI::ElementType type = UI::Element);
virtual ~UIElement();
static UIElementPtr create() { return UIElementPtr(new UIElement); }
void destroyLater();
virtual void destroy();
virtual void destroyCheck();
@@ -54,6 +55,8 @@ public:
void moveTo(Point pos);
void setLocked(bool locked);
void setLayout(const UILayoutPtr& layout) { m_layout = layout; }
UILayoutPtr getLayout() const;
@@ -82,9 +85,9 @@ public:
virtual bool isFocusable() const { return false; }
UI::ElementType getElementType() const { return m_type; }
UIElementPtr asUIElement() { return boost::static_pointer_cast<UIElement>(shared_from_this()); }
UIElementPtr asUIElement() { return std::static_pointer_cast<UIElement>(shared_from_this()); }
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
virtual const char *getScriptObjectType() const { return "UIElement"; }
virtual const char *getLuaTypeName() const { return "UIElement"; }
void setSize(const Size& size);
void setSize(int width, int height) { setSize(Size(width, height)); }
@@ -115,7 +118,7 @@ public:
int getMarginBottom() const { return m_marginBottom; }
void centerIn(const std::string& targetId);
void addAnchor(AnchorPoint anchoredEdge, AnchorLine anchorEdge);
void addAnchor(AnchorPoint edge, const std::string& targetId, AnchorPoint targetEdge);
private:
UI::ElementType m_type;
@@ -126,6 +129,7 @@ private:
bool m_visible;
bool m_enabled;
bool m_mouseOver;
bool m_destroyed;
Rect m_rect;
int m_marginLeft;

View File

@@ -43,6 +43,6 @@ private:
Color m_fontColor;
};
typedef boost::shared_ptr<UIElementSkin> UIElementSkinPtr;
typedef std::shared_ptr<UIElementSkin> UIElementSkinPtr;
#endif // UIELEMENTSKIN_H

View File

@@ -5,6 +5,9 @@
#include <ui/uielement.h>
#include <graphics/font.h>
class UILabel;
typedef std::shared_ptr<UILabel> UILabelPtr;
class UILabel : public UIElement
{
public:
@@ -12,19 +15,21 @@ public:
UIElement(UI::Label),
m_align(AlignLeftCenter) { }
static UILabelPtr create() { return UILabelPtr(new UILabel); }
void setText(const std::string& text);
std::string getText() const { return m_text; }
void setAlign(AlignmentFlag align) { m_align = align; }
AlignmentFlag getAlign() const { return m_align; }
virtual const char *getScriptObjectType() const { return "UILabel"; }
virtual const char *getLuaTypeName() const { return "UILabel"; }
private:
std::string m_text;
AlignmentFlag m_align;
};
typedef boost::shared_ptr<UILabel> UILabelPtr;
typedef std::shared_ptr<UILabel> UILabelPtr;
#endif // UILABEL_H

View File

@@ -4,12 +4,12 @@
#include <global.h>
class UIElement;
typedef boost::shared_ptr<UIElement> UIElementPtr;
typedef std::shared_ptr<UIElement> UIElementPtr;
class UILayout;
typedef boost::shared_ptr<UILayout> UILayoutPtr;
typedef std::shared_ptr<UILayout> UILayoutPtr;
class UILayout : public boost::enable_shared_from_this<UILayout>
class UILayout : public std::enable_shared_from_this<UILayout>
{
public:
UILayout() { }

View File

@@ -2,8 +2,7 @@
#include <core/resources.h>
#include <ui/ui.h>
#include <ui/uiloader.h>
#include <script/scriptcontext.h>
#include <script/scriptfunctions.h>
#include <script/luainterface.h>
#include <otml/otml.h>
#include <ui/uianchorlayout.h>
#include <util/translator.h>
@@ -46,16 +45,19 @@ UIElementPtr UILoader::createElementFromId(const std::string& id)
return element;
}
UIElementPtr UILoader::loadFromFile(std::string filePath, const UIContainerPtr& parent)
UIElementPtr UILoader::loadFromFile(std::string fileName, const UIContainerPtr& parent)
{
UIElementPtr element;
if(!boost::ends_with(".otml", fileName))
fileName += ".otml";
std::stringstream fin;
if(!g_resources.loadFile(filePath, fin))
if(!g_resources.loadFile(fileName, fin))
return element;
try {
OTMLParser parser(fin, filePath);
OTMLParser parser(fin, fileName);
OTMLNode* doc = parser.getDocument();
// get element id
@@ -82,7 +84,7 @@ UIElementPtr UILoader::loadFromFile(std::string filePath, const UIContainerPtr&
// report onLoad events
element->onLoad();
} catch(OTMLException e) {
logError("ERROR: Failed to load ui ",filePath,": ", e.what());
logError("ERROR: Failed to load ui ", g_resources.resolvePath(fileName) ,": ", e.what());
}
return element;
@@ -139,9 +141,13 @@ void UILoader::loadElement(const UIElementPtr& element, OTMLNode* node)
} else // apply default skin
element->applyDefaultSkin();
// load elements common proprieties
if(node->hasChild("size"))
element->setSize(node->readAt<Size>("size"));
// load size
Size size = element->getSize();
size = node->readAt("size", size);
size.setWidth(node->readAt("width", size.width()));
size.setHeight(node->readAt("height", size.height()));
if(size.isValid())
element->setSize(size);
// load margins
element->setMarginLeft(node->readAtPath("margin/left", 0));
@@ -159,18 +165,20 @@ void UILoader::loadElement(const UIElementPtr& element, OTMLNode* node)
// load basic element events
loadElementScriptFunction(element, node->at("onLoad"));
loadElementScriptFunction(element, node->at("onDestroy"));
// load specific element type
switch(element->getElementType()) {
case UI::Button:
loadButton(boost::static_pointer_cast<UIButton>(element), node);
loadButton(std::static_pointer_cast<UIButton>(element), node);
break;
case UI::Window:
loadWindow(boost::static_pointer_cast<UIWindow>(element), node);
loadWindow(std::static_pointer_cast<UIWindow>(element), node);
break;
case UI::Label:
loadLabel(boost::static_pointer_cast<UILabel>(element), node);
loadLabel(std::static_pointer_cast<UILabel>(element), node);
break;
case UI::TextEdit:
loadTextEdit(std::static_pointer_cast<UITextEdit>(element), node);
break;
default:
break;
@@ -188,7 +196,7 @@ void UILoader::loadElementAnchor(const UIElementPtr& anchoredElement, AnchorPoin
return;
}
UIAnchorLayoutPtr layout = boost::dynamic_pointer_cast<UIAnchorLayout>(anchoredElement->getLayout());
UIAnchorLayoutPtr layout = std::dynamic_pointer_cast<UIAnchorLayout>(anchoredElement->getLayout());
if(!layout) {
logError(node->generateErrorMessage("could not add anchor, because this element does not participate of an anchor layout"));
return;
@@ -222,8 +230,9 @@ void UILoader::loadElementScriptFunction(const UIElementPtr& element, OTMLNode*
functionDesc += g_resources.resolvePath(node->what()) + ":" + element->getId();
functionDesc += "[" + node->tag() + "]";
if(g_lua.loadBufferAsFunction(node->value(), functionDesc))
g_lua.setScriptObjectField(element, node->tag());
LuaValuePtr function = g_lua.loadFunction(node->value(), functionDesc);
if(function->isFunction())
element->setField(node->tag(), function);
else
logError(node->generateErrorMessage("failed to parse inline lua script"));
}
@@ -244,3 +253,8 @@ void UILoader::loadLabel(const UILabelPtr& label, OTMLNode* node)
label->setText(node->readAt("text", std::string()));
label->setAlign(parseAlignment(node->readAt("align", std::string("left"))));
}
void UILoader::loadTextEdit(const UITextEditPtr& textEdit, OTMLNode* node)
{
textEdit->setText(node->readAt("text", std::string()));
}

View File

@@ -30,13 +30,14 @@
#include <ui/uibutton.h>
#include <ui/uiwindow.h>
#include <ui/uilabel.h>
#include <ui/uitextedit.h>
#include <ui/uianchorlayout.h>
class UILoader
{
public:
/// Loads an UIElement and it's children from a FML file
UIElementPtr loadFromFile(std::string filePath, const UIContainerPtr& parent = UIContainer::getRoot());
UIElementPtr loadFromFile(std::string fileName, const UIContainerPtr& parent = UIContainer::getRoot());
private:
/// Detect element type and create it
@@ -61,6 +62,7 @@ private:
void loadButton(const UIButtonPtr& button, OTMLNode* node);
void loadWindow(const UIWindowPtr& window, OTMLNode* node);
void loadLabel(const UILabelPtr& label, OTMLNode* node);
void loadTextEdit(const UITextEditPtr& textEdit, OTMLNode* node);
};
extern UILoader g_uiLoader;

View File

@@ -53,9 +53,10 @@ void UITextEdit::onInputEvent(const InputEvent& event)
else if(event.keycode == KC_TAB) // focus next parent element
getParent()->focusNextElement();
} else if(event.type == EV_MOUSE_LDOWN) {
int pos = m_textArea.getTextPos(event.mousePos);
if(pos >= 0)
m_textArea.setCursorPos(m_textArea.getTextPos(event.mousePos));
} else if(event.type == EV_MOUSE_LUP && getRect().contains(event.mousePos)) {
m_textArea.setCursorPos(m_textArea.getTextPos(event.mousePos));
}
}

View File

@@ -1,27 +1,3 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* 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 UITEXTEDIT_H
#define UITEXTEDIT_H
@@ -31,11 +7,16 @@
class Font;
class UITextEdit;
typedef std::shared_ptr<UITextEdit> UITextEditPtr;
class UITextEdit : public UIElement
{
public:
UITextEdit();
static UITextEditPtr create() { return UITextEditPtr(new UITextEdit); }
void onInputEvent(const InputEvent& event);
void onRectUpdate();
void onFocusChange();
@@ -46,12 +27,10 @@ public:
bool isFocusable() const { return true; }
virtual const char *getScriptObjectType() const { return "UITextEdit"; }
virtual const char *getLuaTypeName() const { return "UITextEdit"; }
private:
TextArea m_textArea;
};
typedef boost::shared_ptr<UITextEdit> UITextEditPtr;
#endif // UITEXTEDIT_H

View File

@@ -1,33 +1,12 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* 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 UIWINDOW_H
#define UIWINDOW_H
#include <global.h>
#include <ui/uicontainer.h>
class UIWindow;
typedef std::shared_ptr<UIWindow> UIWindowPtr;
class UIWindow : public UIContainer
{
public:
@@ -35,12 +14,14 @@ public:
UIContainer(UI::Window),
m_moving(false) { }
static UIWindowPtr create() { return UIWindowPtr(new UIWindow); }
void onInputEvent(const InputEvent& event);
void setTitle(const std::string& title) { m_title = title; }
std::string getTitle() const { return m_title; }
virtual const char *getScriptObjectType() const { return "UIWindow"; }
virtual const char *getLuaTypeName() const { return "UIWindow"; }
virtual bool isFocusable() const { return true; }
@@ -50,6 +31,4 @@ private:
Point m_movingReference;
};
typedef boost::shared_ptr<UIWindow> UIWindowPtr;
#endif // UIWINDOW_H

View File

@@ -34,7 +34,7 @@ void UIWindowSkin::load(OTMLNode* node)
OTMLNode* headNode = node->at("head");
OTMLNode* bodyNode = node->at("body");
m_headImage = boost::dynamic_pointer_cast<BorderedImage>(loadImage(headNode));
m_headImage = std::dynamic_pointer_cast<BorderedImage>(loadImage(headNode));
m_headHeight = headNode->readAt("height", m_headImage->getDefaultSize().height());
m_headMargin = headNode->readAt("margin", 0);
m_titleAlign = parseAlignment(headNode->readAt("text align", std::string("center")));

View File

@@ -0,0 +1,16 @@
#ifndef ALGORITHMS_H
#define ALGORITHMS_H
#include <algorithm>
#include <string>
inline std::string getPathDirectory(const std::string& sourcePath)
{
std::string dir;
std::size_t pos = sourcePath.find_last_of('/');
if(pos != std::string::npos)
dir = sourcePath.substr(0, pos);
return dir;
}
#endif // ALGORITHMS_H

View File

@@ -19,11 +19,11 @@ void log(LogLevel level, const std::string& message, std::string prettyFunction
#define logError(...) log(LogError, make_string(__VA_ARGS__))
#define logFatal(...) log(LogFatal, make_string(__VA_ARGS__))
#define trace() log(LogDebug, "", __PRETTY_FUNCTION__)
#define traceDebug(...) log(LogDebug, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define traceInfo(...) log(LogInfo, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define traceWarning(...) log(LogWarning, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define traceError(...) log(LogError, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTrace() log(LogDebug, "", __PRETTY_FUNCTION__)
#define logTraceDebug(...) log(LogDebug, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceInfo(...) log(LogInfo, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceWarning(...) log(LogWarning, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceError(...) log(LogError, make_string(__VA_ARGS__), __PRETTY_FUNCTION__)
// dump utility
struct Dump {

View File

@@ -42,7 +42,7 @@ public:
inline bool operator==(const TPoint<T>& other) const { return other.x==x && other.y==y; }
inline bool operator!=(const TPoint<T>& other) const { return other.x!=x || other.y!=y; }
inline float length() const { return sqrtf((float)(x*x + y*y)); }
inline float length() const { return sqrt((float)(x*x + y*y)); }
inline T manhattanLength() const { return std::abs(x) + std::abs(y); }
inline float distanceFrom(const TPoint<T>& other) const {

View File

@@ -5,8 +5,9 @@
#include <core/platform.h>
#include <core/dispatcher.h>
#include <ui/uiskins.h>
#include <script/scriptcontext.h>
#include <core/packages.h>
#include <ui/uicontainer.h>
#include <script/luainterface.h>
#include <csignal>
@@ -68,6 +69,9 @@ int main(int argc, const char *argv[])
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
// init script stuff
g_lua.init();
// init platform stuff
Platform::init("OTClient");
@@ -92,10 +96,10 @@ int main(int argc, const char *argv[])
g_engine.enableFpsCounter();
// load ui skins
g_uiSkins.load("tibiaskin");
g_uiSkins.load("default");
// load script modules
g_lua.loadAllModules();
g_packages.loadPackages();
Platform::showWindow();
@@ -108,5 +112,6 @@ int main(int argc, const char *argv[])
saveConfigs();
Platform::terminate();
g_resources.terminate();
g_lua.terminate();
return 0;
}

View File

@@ -1,25 +1,23 @@
#include "protocollogin.h"
#include <net/outputmessage.h>
#include <net/rsa.h>
#include <script/scriptcontext.h>
#include <script/luainterface.h>
#include <boost/bind.hpp>
ProtocolLogin::ProtocolLogin()
{
trace();
}
ProtocolLogin::~ProtocolLogin()
{
trace();
}
void ProtocolLogin::login(const std::string& accountName, const std::string& accountPassword)
{
trace();
if(accountName.empty() || accountPassword.empty()) {
g_lua.pushString("You must enter an account name and password.");
callScriptTableField("onError", 1);
callField("onError", "You must enter an account name and password.");
return;
}
@@ -43,18 +41,16 @@ void ProtocolLogin::login(const std::string& accountName, const std::string& acc
//std::string host = "tecserver.zapto.org";
uint16 port = 7171;
connect(host, port, boost::bind(&ProtocolLogin::onConnect, this));
connect(host, port, std::bind(&ProtocolLogin::onConnect, this));
}
void ProtocolLogin::onConnect()
{
trace();
sendPacket();
}
void ProtocolLogin::sendPacket()
{
trace();
OutputMessage oMsg;
oMsg.addU8(0x01); // Protocol id
@@ -96,7 +92,6 @@ void ProtocolLogin::sendPacket()
void ProtocolLogin::onRecv(InputMessage *inputMessage)
{
trace();
Protocol::onRecv(inputMessage);
while(!inputMessage->end()) {
@@ -109,6 +104,14 @@ void ProtocolLogin::onRecv(InputMessage *inputMessage)
case 0x14:
parseMOTD(inputMessage);
break;
case 0x1e:
inputMessage->getU8();
inputMessage->getU8();
inputMessage->getU8();
inputMessage->getU8();
inputMessage->getU8();
callField("onError", "Client needs update.");
break;
case 0x64:
parseCharacterList(inputMessage);
break;
@@ -118,23 +121,18 @@ void ProtocolLogin::onRecv(InputMessage *inputMessage)
void ProtocolLogin::parseError(InputMessage *inputMessage)
{
trace();
std::string error = inputMessage->getString();
g_lua.pushString(error);
callScriptTableField("onError", 1);
callField("onError", error);
}
void ProtocolLogin::parseMOTD(InputMessage *inputMessage)
{
trace();
std::string motd = inputMessage->getString();
g_lua.pushString(motd);
callScriptTableField("onMotd", 1);
callField("onMotd", motd);
}
void ProtocolLogin::parseCharacterList(InputMessage *inputMessage)
{
trace();
uint8 characters = inputMessage->getU8();
for(int i = 0; i < characters; ++i) {
std::string name = inputMessage->getString();

View File

@@ -3,12 +3,17 @@
#include <net/protocol.h>
class ProtocolLogin;
typedef std::shared_ptr<ProtocolLogin> ProtocolLoginPtr;
class ProtocolLogin : public Protocol
{
public:
ProtocolLogin();
~ProtocolLogin();
static ProtocolLoginPtr create() { return ProtocolLoginPtr(new ProtocolLogin); }
void login(const std::string& accountName, const std::string& accountPassword);
void onConnect();
@@ -16,7 +21,8 @@ public:
void sendPacket();
void onRecv(InputMessage *inputMessage);
const char *getScriptObjectType() const { return "ProtocolLogin"; }
void cancel() { /* TODO: this func */ }
virtual const char* getLuaTypeName() const { return "ProtocolLogin"; }
private:
void parseError(InputMessage *inputMessage);
@@ -27,6 +33,4 @@ private:
};
typedef boost::shared_ptr<ProtocolLogin> ProtocolLoginPtr;
#endif