mirror of
https://github.com/edubart/otclient.git
synced 2025-10-14 11:34:54 +02:00
new script engine, and things maybe be bugged for a while
This commit is contained in:
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "modules.h"
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#ifndef MODULES_H
|
||||
#define MODULES_H
|
||||
|
||||
class Modules
|
||||
{
|
||||
};
|
||||
|
||||
#endif // MODULES_H
|
29
src/framework/core/packages.cpp
Normal file
29
src/framework/core/packages.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
15
src/framework/core/packages.h
Normal file
15
src/framework/core/packages.h
Normal 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
|
@@ -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 ¤tPath)
|
||||
{
|
||||
//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)
|
||||
|
@@ -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
|
||||
|
@@ -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]);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -75,6 +75,6 @@ private:
|
||||
Size m_glyphsSize[256];
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Font> FontPtr;
|
||||
typedef std::shared_ptr<Font> FontPtr;
|
||||
|
||||
#endif // FONT_H
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -44,6 +44,6 @@ protected:
|
||||
Rect m_textureCoords;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Image> ImagePtr;
|
||||
typedef std::shared_ptr<Image> ImagePtr;
|
||||
|
||||
#endif // IMAGE_H
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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));*/
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
191
src/framework/script/luabinder.h
Normal file
191
src/framework/script/luabinder.h
Normal 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
|
19
src/framework/script/luadeclarations.h
Normal file
19
src/framework/script/luadeclarations.h
Normal 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
|
39
src/framework/script/luaexception.cpp
Normal file
39
src/framework/script/luaexception.cpp
Normal 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);
|
||||
}
|
38
src/framework/script/luaexception.h
Normal file
38
src/framework/script/luaexception.h
Normal 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
|
54
src/framework/script/luafunctions.cpp
Normal file
54
src/framework/script/luafunctions.cpp
Normal 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);
|
||||
}
|
235
src/framework/script/luainterface.cpp
Normal file
235
src/framework/script/luainterface.cpp
Normal 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;
|
||||
}
|
||||
|
73
src/framework/script/luainterface.h
Normal file
73
src/framework/script/luainterface.h
Normal 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
|
24
src/framework/script/luaobject.cpp
Normal file
24
src/framework/script/luaobject.cpp
Normal 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();
|
||||
}
|
50
src/framework/script/luaobject.h
Normal file
50
src/framework/script/luaobject.h
Normal 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
|
604
src/framework/script/luastate.cpp
Normal file
604
src/framework/script/luastate.cpp
Normal 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);
|
||||
}
|
126
src/framework/script/luastate.h
Normal file
126
src/framework/script/luastate.h
Normal 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
|
234
src/framework/script/luavalue.cpp
Normal file
234
src/framework/script/luavalue.cpp
Normal 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());
|
||||
}
|
||||
|
78
src/framework/script/luavalue.h
Normal file
78
src/framework/script/luavalue.h
Normal 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
|
76
src/framework/script/luavaluecasts.cpp
Normal file
76
src/framework/script/luavaluecasts.cpp
Normal 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;
|
||||
}
|
80
src/framework/script/luavaluecasts.h
Normal file
80
src/framework/script/luavaluecasts.h
Normal 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
|
@@ -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;
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -1,10 +0,0 @@
|
||||
|
||||
#ifndef SCRIPTFUNCTIONS_H
|
||||
#define SCRIPTFUNCTIONS_H
|
||||
|
||||
#include <global.h>
|
||||
#include "scriptobject.h"
|
||||
|
||||
void registerScriptFunctions();
|
||||
|
||||
#endif // SCRIPTFUNCTIONS_H
|
@@ -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");
|
||||
}
|
||||
|
@@ -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
|
285
src/framework/script_bak/luafunctions.cpp
Normal file
285
src/framework/script_bak/luafunctions.cpp
Normal 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;
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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())
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -43,6 +43,6 @@ private:
|
||||
Color m_fontColor;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<UIElementSkin> UIElementSkinPtr;
|
||||
typedef std::shared_ptr<UIElementSkin> UIElementSkinPtr;
|
||||
|
||||
#endif // UIELEMENTSKIN_H
|
||||
|
@@ -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
|
||||
|
@@ -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() { }
|
||||
|
@@ -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()));
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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")));
|
||||
|
16
src/framework/util/algorithms.h
Normal file
16
src/framework/util/algorithms.h
Normal 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
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
11
src/main.cpp
11
src/main.cpp
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user