Add lua console
- Add an internal command logger to the lua kernel base, and expose this. - Redirect the internal lua `print` to the command logger. - Add an external logger registration system to lua kernel, in addition to the internal one. - Add a lua console dialog which binds to a lua kernel base and permits to review the contents of the logger and issue new commands, and report errors. - Add a hotkey binding to launch the lua console "`" - Adds tab completion support to the lua console
This commit is contained in:
parent
9fdc91e8a9
commit
2021a42d5b
20 changed files with 800 additions and 8 deletions
|
@ -518,5 +518,8 @@
|
|||
command="changelanguage"
|
||||
key="l"
|
||||
[/hotkey]
|
||||
|
||||
[hotkey]
|
||||
command="global__lua__console"
|
||||
key="`"
|
||||
[/hotkey]
|
||||
#undef IF_APPLE_CMD_ELSE_CTRL
|
||||
|
|
129
data/gui/default/window/lua_interpreter.cfg
Normal file
129
data/gui/default/window/lua_interpreter.cfg
Normal file
|
@ -0,0 +1,129 @@
|
|||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Definition of the window to show chat log.
|
||||
###
|
||||
|
||||
[window]
|
||||
id = "lua_interpreter"
|
||||
description = "Lua interpreter console dialog."
|
||||
|
||||
[resolution]
|
||||
definition = "default"
|
||||
automatic_placement = "true"
|
||||
vertical_placement = "center"
|
||||
horizontal_placement = "center"
|
||||
#maximum_width = 800
|
||||
#maximum_height = 600
|
||||
|
||||
[tooltip]
|
||||
id = "tooltip_large"
|
||||
[/tooltip]
|
||||
|
||||
[helptip]
|
||||
id = "tooltip_large"
|
||||
[/helptip]
|
||||
|
||||
[grid]
|
||||
[row] #header
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 7
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "title"
|
||||
label = _ "Lua Console"
|
||||
[/label]
|
||||
[/column]
|
||||
[/row]
|
||||
[row] #choice
|
||||
grow_factor="7"
|
||||
[column]
|
||||
grow_factor = 7
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = "true"
|
||||
|
||||
#
|
||||
# HACK:
|
||||
# In order to reserve a minimum screen space for the
|
||||
# central widget and avoid sudden window size changes when
|
||||
# switching pages or entering text in the search box, we
|
||||
# use two spacer widgets within a subgrid to restrict this
|
||||
# cell's minimum size. It's important to keep the spacers'
|
||||
# dimensions within certain limits so as to not cause
|
||||
# dialog-spanning scrollbars to appear on 800x480.
|
||||
#
|
||||
|
||||
{GUI_FORCE_WIDGET_MINIMUM_SIZE 600 400 (
|
||||
[scroll_label]
|
||||
id = "msg"
|
||||
definition = "description"
|
||||
label = ""
|
||||
[/scroll_label]
|
||||
)}
|
||||
[/column]
|
||||
[/row]
|
||||
[row]
|
||||
grow_factor=0
|
||||
[column]
|
||||
grow_factor = 7
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = "true"
|
||||
|
||||
[text_box]
|
||||
id = "text_entry"
|
||||
definition = "default"
|
||||
history = "lua_text_entry"
|
||||
label = ""
|
||||
[/text_box]
|
||||
[/column]
|
||||
[/row]
|
||||
[row] #status
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
horizontal_grow = "true"
|
||||
|
||||
[grid]
|
||||
[row]
|
||||
[column]
|
||||
grow_factor = 0
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
[button]
|
||||
id = "copy"
|
||||
definition = "action_copy"
|
||||
label = _ "clipboard^Copy"
|
||||
# FIXME: tooltips cause weird interactions with map
|
||||
# labels while running a GUI2 dialog, so let's
|
||||
# not use a tooltip yet.
|
||||
#tooltip = _ "Copy this log to clipboard"
|
||||
[/button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
[button]
|
||||
id = "cancel"
|
||||
definition = "default"
|
||||
label = _ "Close"
|
||||
[/button]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
[/resolution]
|
||||
[/window]
|
||||
|
||||
# kate: indent-mode normal; encoding utf-8; space-indent on;
|
|
@ -877,6 +877,7 @@ set(wesnoth-main_SRC
|
|||
gui/dialogs/lobby/lobby_info.cpp
|
||||
gui/dialogs/lobby_main.cpp
|
||||
gui/dialogs/lobby_player_info.cpp
|
||||
gui/dialogs/lua_interpreter.cpp
|
||||
gui/dialogs/message.cpp
|
||||
gui/dialogs/mp_alerts_options.cpp
|
||||
gui/dialogs/mp_change_control.cpp
|
||||
|
|
|
@ -411,6 +411,7 @@ wesnoth_sources = Split("""
|
|||
gui/dialogs/lobby/lobby_info.cpp
|
||||
gui/dialogs/lobby_main.cpp
|
||||
gui/dialogs/lobby_player_info.cpp
|
||||
gui/dialogs/lua_interpreter.cpp
|
||||
gui/dialogs/message.cpp
|
||||
gui/dialogs/mp_alerts_options.cpp
|
||||
gui/dialogs/mp_cmd_wrapper.cpp
|
||||
|
|
309
src/gui/dialogs/lua_interpreter.cpp
Normal file
309
src/gui/dialogs/lua_interpreter.cpp
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2014 by Yurii Chernyi <terraninfo@terraninfo.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/dialogs/lua_interpreter.hpp"
|
||||
|
||||
#include "gui/auxiliary/find_widget.tpp"
|
||||
#include "gui/dialogs/helper.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
|
||||
#include "desktop/clipboard.hpp"
|
||||
#include "game_errors.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "resources.hpp" //for help fetching lua kernel pointers
|
||||
#include "scripting/application_lua_kernel.hpp" //needed for the WHICH_KERNEL version of display
|
||||
#include "scripting/game_lua_kernel.hpp" //needed for the WHICH_KERNEL version of display
|
||||
#include "scripting/lua_kernel_base.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
#include "log.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
static lg::log_domain log_lua_int("lua/interpreter");
|
||||
#define DBG_LUA LOG_STREAM(debug, log_lua_int)
|
||||
#define LOG_LUA LOG_STREAM(info, log_lua_int)
|
||||
#define WRN_LUA LOG_STREAM(warn, log_lua_int)
|
||||
#define ERR_LUA LOG_STREAM(err, log_lua_int)
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
/*WIKI
|
||||
* @page = GUIWindowDefinitionWML
|
||||
* @order = 3_chat_log
|
||||
*
|
||||
* == Settings manager ==
|
||||
*
|
||||
* This shows the settings manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
REGISTER_DIALOG(lua_interpreter)
|
||||
|
||||
void tlua_interpreter::display(CVideo& video, lua_kernel_base * lk) {
|
||||
if (!lk) {
|
||||
ERR_LUA << "Tried to open console with a null lua kernel pointer.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
tlua_interpreter(*lk).show(video);
|
||||
}
|
||||
|
||||
void tlua_interpreter::display(CVideo& video, tlua_interpreter::WHICH_KERNEL which) {
|
||||
if (which == tlua_interpreter::APP) {
|
||||
display(video, resources::app_lua_kernel);
|
||||
} else if (which == tlua_interpreter::GAME) {
|
||||
display(video, resources::lua_kernel);
|
||||
}
|
||||
}
|
||||
|
||||
twindow* tlua_interpreter::build_window(CVideo& video)
|
||||
{
|
||||
return build(video, window_id());
|
||||
}
|
||||
|
||||
|
||||
void tlua_interpreter::pre_show(CVideo& /*video*/, twindow& window)
|
||||
{
|
||||
LOG_LUA << "Entering tlua_interpreter::view::pre_show" << std::endl;
|
||||
bind(window);
|
||||
update_contents();
|
||||
//window.invalidate_layout(); // workaround for assertion failure
|
||||
LOG_LUA << "Exiting tlua_interpreter::view::pre_show" << std::endl;
|
||||
}
|
||||
|
||||
void tlua_interpreter::bind(twindow& window)
|
||||
{
|
||||
LOG_LUA << "Entering tlua_interpreter::bind" << std::endl;
|
||||
msg_label = &find_widget<tscroll_label>(&window, "msg", false);
|
||||
msg_label->set_use_markup(true);
|
||||
msg_label->set_vertical_scrollbar_mode(tscrollbar_container::always_visible);
|
||||
msg_label->set_label("");
|
||||
|
||||
text_entry = &find_widget<ttext_box>(&window, "text_entry", false);
|
||||
//text_entry->set_text_changed_callback(
|
||||
// boost::bind(&view::filter, this, boost::ref(window)));
|
||||
window.keyboard_capture(text_entry);
|
||||
window.set_click_dismiss(false);
|
||||
window.set_enter_disabled(true);
|
||||
|
||||
connect_signal_pre_key_press(
|
||||
*text_entry,
|
||||
boost::bind(&tlua_interpreter::input_keypress_callback,
|
||||
this,
|
||||
_3,
|
||||
_4,
|
||||
_5,
|
||||
boost::ref(window)));
|
||||
|
||||
|
||||
copy_button = &find_widget<tbutton>(&window, "copy", false);
|
||||
connect_signal_mouse_left_click(
|
||||
*copy_button,
|
||||
boost::bind(&tlua_interpreter::handle_copy_button_clicked,
|
||||
this,
|
||||
boost::ref(window)));
|
||||
|
||||
if (!desktop::clipboard::available()) {
|
||||
copy_button->set_active(false);
|
||||
copy_button->set_tooltip(_("Clipboard support not found, contact your packager."));
|
||||
}
|
||||
|
||||
LOG_LUA << "Exiting tlua_interpreter::bind" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
class tlua_interpreter::model {
|
||||
private:
|
||||
lua_kernel_base & L_;
|
||||
std::stringstream log_;
|
||||
|
||||
public:
|
||||
model (lua_kernel_base & lk)
|
||||
: L_(lk)
|
||||
, log_()
|
||||
{
|
||||
DBG_LUA << "constructing a tlua_interpreter::model\n";
|
||||
//DBG_LUA << "incoming:\n" << lk.get_log().rdbuf() << "\n.\n";
|
||||
log_ << lk.get_log().str() << std::flush;
|
||||
L_.set_external_log(&log_); //register our log to get commands and output from the lua interpreter
|
||||
//DBG_LUA << "recieved:\n" << log_.str() << "\n.\n";
|
||||
|
||||
DBG_LUA << "finished constructing a tlua_interpreter::model\n";
|
||||
|
||||
}
|
||||
|
||||
~model()
|
||||
{
|
||||
DBG_LUA << "destroying a tlua_interpreter::model\n";
|
||||
L_.set_external_log(NULL); //deregister our log since it's about to be destroyed
|
||||
}
|
||||
|
||||
bool execute(const std::string & cmd); // no throw of lua_error. should handle formatting any syntax errors to the interpreter log.
|
||||
|
||||
void add_dialog_message(const std::string & msg); //formats a message from the dialog, puts in interpreter log but not lua's log
|
||||
|
||||
std::string get_log() const { return log_.str(); }
|
||||
|
||||
std::vector<std::string> get_globals() { return L_.get_global_var_names(); }
|
||||
std::vector<std::string> get_attribute_names(const std::string & s) { return L_.get_attribute_names(s); }
|
||||
};
|
||||
|
||||
bool tlua_interpreter::model::execute (const std::string & cmd)
|
||||
{
|
||||
LOG_LUA << "tlua_interpreter::model::execute...\n";
|
||||
try {
|
||||
L_.throwing_run(cmd.c_str());
|
||||
return true;
|
||||
} catch (game::lua_error & e) {
|
||||
add_dialog_message(std::string(e.what()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void tlua_interpreter::model::add_dialog_message(const std::string & msg) {
|
||||
log_ << "<span color='#8888FF'>" << font::escape_text(msg) << "</span>\n";
|
||||
}
|
||||
|
||||
tlua_interpreter::tlua_interpreter(lua_kernel_base & lk)
|
||||
: model_(new tlua_interpreter::model(lk))
|
||||
, msg_label(NULL)
|
||||
, copy_button(NULL)
|
||||
, text_entry(NULL)
|
||||
{
|
||||
LOG_LUA << "entering tlua_interpreter ctor...\n";
|
||||
LOG_LUA << "finished tlua_interpreter ctor...\n";
|
||||
}
|
||||
|
||||
void tlua_interpreter::update_contents()
|
||||
{
|
||||
LOG_LUA << "tlua_interpreter update_contents...\n";
|
||||
if (msg_label) {
|
||||
msg_label->set_label(model_->get_log());
|
||||
msg_label->scroll_vertical_scrollbar(tscrollbar_::END);
|
||||
}
|
||||
LOG_LUA << "tlua_interpreter update_contents finished\n";
|
||||
}
|
||||
|
||||
void tlua_interpreter::handle_copy_button_clicked(twindow & /*window*/)
|
||||
{
|
||||
desktop::clipboard::copy_to_clipboard(model_->get_log(), false);
|
||||
}
|
||||
|
||||
void tlua_interpreter::input_keypress_callback(bool& handled,
|
||||
bool& halt,
|
||||
const SDLKey key,
|
||||
twindow& /*window*/)
|
||||
{
|
||||
LOG_LUA << "keypress_callback\n";
|
||||
if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
|
||||
LOG_LUA << "executing...\n";
|
||||
model_->execute(text_entry->get_value());
|
||||
update_contents();
|
||||
text_entry->set_value("");
|
||||
handled = true;
|
||||
halt = true;
|
||||
LOG_LUA << "finished executing\n";
|
||||
} else if(key == SDLK_TAB) {
|
||||
std::string text = text_entry->get_value();
|
||||
|
||||
std::string prefix;
|
||||
size_t idx = text.find_last_of(" (");
|
||||
if (idx != std::string::npos) {
|
||||
prefix = text.substr(0, idx+1);
|
||||
text = text.substr(idx+1);
|
||||
}
|
||||
|
||||
std::vector<std::string> matches;
|
||||
|
||||
if (text.find('.') == std::string::npos) {
|
||||
matches = model_->get_globals();
|
||||
matches.push_back("and");
|
||||
matches.push_back("break");
|
||||
matches.push_back("else");
|
||||
matches.push_back("elseif");
|
||||
matches.push_back("end");
|
||||
matches.push_back("false");
|
||||
matches.push_back("for");
|
||||
matches.push_back("function");
|
||||
matches.push_back("local");
|
||||
matches.push_back("nil");
|
||||
matches.push_back("not");
|
||||
matches.push_back("repeat");
|
||||
matches.push_back("return");
|
||||
matches.push_back("then");
|
||||
matches.push_back("true");
|
||||
matches.push_back("until");
|
||||
matches.push_back("while");
|
||||
} else {
|
||||
matches = model_->get_attribute_names(text);
|
||||
}
|
||||
|
||||
//bool line_start = utils::word_completion(text, matches);
|
||||
if (text.size() > 0) { // this if is to avoid wierd behavior in word_completion, where it thinks nothing matches the empty string
|
||||
utils::word_completion(text, matches);
|
||||
}
|
||||
|
||||
if(matches.empty()) {
|
||||
handled = true; //there's no point in putting tabs in the command line
|
||||
halt = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//if(matches.size() == 1) {
|
||||
//text.append(" "); //line_start ? ": " : " ");
|
||||
//} else {
|
||||
if (matches.size() > 1) {
|
||||
//std::string completion_list = utils::join(matches, " ");
|
||||
|
||||
const size_t wrap_limit = 80;
|
||||
std::string buffer;
|
||||
|
||||
for (size_t idx = 0; idx < matches.size(); ++idx) {
|
||||
if (buffer.size() + 1 + matches.at(idx).size() > wrap_limit) {
|
||||
model_->add_dialog_message(buffer);
|
||||
buffer = matches.at(idx);
|
||||
} else {
|
||||
if (buffer.size()) {
|
||||
buffer += (" " + matches.at(idx));
|
||||
} else {
|
||||
buffer = matches.at(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model_->add_dialog_message(buffer);
|
||||
update_contents();
|
||||
}
|
||||
text_entry->set_value(prefix + text);
|
||||
handled = true;
|
||||
halt = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace gui2
|
70
src/gui/dialogs/lua_interpreter.hpp
Normal file
70
src/gui/dialogs/lua_interpreter.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef GUI_DIALOGS_LUA_INT_HPP_INCLUDED
|
||||
#define GUI_DIALOGS_LUA_INT_HPP_INCLUDED
|
||||
|
||||
#include "gui/dialogs/dialog.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/scroll_label.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
class lua_kernel_base;
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
class tlua_interpreter : public tdialog
|
||||
{
|
||||
public:
|
||||
class model;
|
||||
|
||||
tlua_interpreter(lua_kernel_base & lk);
|
||||
|
||||
/** Inherited from tdialog. */
|
||||
twindow* build_window(CVideo& video);
|
||||
|
||||
/** Inherited from tdialog. */
|
||||
void pre_show(CVideo& video, twindow& window);
|
||||
|
||||
enum WHICH_KERNEL { APP, GAME };
|
||||
static void display(CVideo& video, lua_kernel_base * lk);
|
||||
static void display(CVideo& video, WHICH_KERNEL which);
|
||||
private:
|
||||
boost::scoped_ptr<model> model_;
|
||||
|
||||
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const;
|
||||
|
||||
void bind(twindow& window);
|
||||
|
||||
void update_contents();
|
||||
|
||||
void handle_copy_button_clicked(twindow & window);
|
||||
|
||||
void input_keypress_callback(bool& handled,
|
||||
bool& halt,
|
||||
const SDLKey key,
|
||||
twindow& window);
|
||||
|
||||
tscroll_label* msg_label;
|
||||
tbutton* copy_button;
|
||||
ttext_box* text_entry;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ! GUI_DIALOGS_CHAT_LOG_HPP_INCLUDED */
|
|
@ -26,6 +26,7 @@
|
|||
#include "gui/auxiliary/tips.hpp"
|
||||
#include "gui/dialogs/debug_clock.hpp"
|
||||
#include "gui/dialogs/language_selection.hpp"
|
||||
#include "gui/dialogs/lua_interpreter.hpp"
|
||||
//#define DEBUG_TOOLTIP
|
||||
#ifdef DEBUG_TOOLTIP
|
||||
#include "gui/dialogs/tip.hpp"
|
||||
|
@ -47,6 +48,9 @@ static lg::log_domain log_config("config");
|
|||
#define ERR_CF LOG_STREAM(err, log_config)
|
||||
#define WRN_CF LOG_STREAM(warn, log_config)
|
||||
|
||||
static lg::log_domain log_general("general");
|
||||
#define ERR_GEN LOG_STREAM(err, log_general)
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
|
@ -188,6 +192,12 @@ static bool fullscreen(CVideo& video)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool launch_lua_console(twindow & window)
|
||||
{
|
||||
gui2::tlua_interpreter::display(window.video(), gui2::tlua_interpreter::APP);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ttitle_screen::post_build(CVideo& video, twindow& window)
|
||||
{
|
||||
/** @todo Should become a title screen hotkey. */
|
||||
|
@ -258,6 +268,10 @@ void ttitle_screen::post_build(CVideo& video, twindow& window)
|
|||
|
||||
window.register_hotkey(hotkey::HOTKEY_QUIT_GAME,
|
||||
boost::bind(&hotkey, boost::ref(window), QUIT_GAME));
|
||||
|
||||
window.register_hotkey(
|
||||
hotkey::LUA_CONSOLE,
|
||||
boost::bind(&launch_lua_console, boost::ref(window)));
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TOOLTIP
|
||||
|
|
|
@ -130,7 +130,7 @@ void tscrollbar_::set_item_position(const unsigned item_position)
|
|||
? item_count_ - visible_items_
|
||||
: item_position;
|
||||
|
||||
item_position_ = (item_position_ + step_size_ - 1) / step_size_;
|
||||
item_position_ = ((step_size_ * item_position_) + step_size_ - 1) / step_size_; // round to nearest step size
|
||||
|
||||
if(all_items_visible()) {
|
||||
item_position_ = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "boost/foreach.hpp"
|
||||
|
||||
#include "gui/dialogs/lua_interpreter.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
#include "gui/dialogs/screenshot_notification.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
|
@ -32,6 +33,7 @@
|
|||
|
||||
static lg::log_domain log_config("config");
|
||||
#define ERR_G LOG_STREAM(err, lg::general)
|
||||
#define WRN_G LOG_STREAM(warn, lg::general)
|
||||
#define LOG_G LOG_STREAM(info, lg::general)
|
||||
#define DBG_G LOG_STREAM(debug, lg::general)
|
||||
#define ERR_CF LOG_STREAM(err, log_config)
|
||||
|
@ -688,6 +690,13 @@ void execute_command(display& disp, const hotkey_command& command, command_execu
|
|||
}
|
||||
break;
|
||||
}
|
||||
case LUA_CONSOLE: {
|
||||
if (!disp.in_game()) {
|
||||
WRN_G << "caution: attempting to interface console with game lua kernel when we are not in game...\n";
|
||||
}
|
||||
gui2::tlua_interpreter::display(disp.video(), gui2::tlua_interpreter::GAME);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG_G << "command_executor: unknown command number " << command.id << ", ignoring.\n";
|
||||
break;
|
||||
|
|
|
@ -259,6 +259,8 @@ hotkey::hotkey_command_temp hotkey_list_[] = {
|
|||
|
||||
{ hotkey::GLOBAL__HELPTIP, "global__helptip", N_("Show Helptip"), false, scope_game | scope_editor | scope_main, "" },
|
||||
|
||||
{ hotkey::LUA_CONSOLE, "global__lua__console", N_("Show Lua Console"), false, scope_game | scope_editor | scope_main, ""},
|
||||
|
||||
//This list item must stay at the end since it is used as terminator for iterating.
|
||||
{ hotkey::HOTKEY_NULL, "null", N_("Unrecognized Command"), true, hotkey::SCOPE_COUNT, "" }
|
||||
};
|
||||
|
|
|
@ -96,6 +96,7 @@ enum HOTKEY_COMMAND {
|
|||
TITLE_SCREEN__EDITOR,
|
||||
TITLE_SCREEN__CREDITS,
|
||||
GLOBAL__HELPTIP,
|
||||
LUA_CONSOLE,
|
||||
|
||||
HOTKEY_WML,
|
||||
|
||||
|
|
|
@ -793,6 +793,7 @@ bool play_controller::can_execute_command(const hotkey::hotkey_command& cmd, int
|
|||
case hotkey::HOTKEY_MINIMAP_DRAW_VILLAGES:
|
||||
case hotkey::HOTKEY_NULL:
|
||||
case hotkey::HOTKEY_SAVE_REPLAY:
|
||||
case hotkey::LUA_CONSOLE:
|
||||
return true;
|
||||
|
||||
// Commands that have some preconditions:
|
||||
|
|
|
@ -54,6 +54,9 @@ application_lua_kernel::application_lua_kernel()
|
|||
|
||||
bool application_lua_kernel::initialize(game_launcher * gl)
|
||||
{
|
||||
|
||||
cmd_log_ << "Adding game_launcher...\n";
|
||||
|
||||
//if (resources::app_lua_kernel && resources::app_lua_kernel != this) {
|
||||
// throw "you appear to have multiple application lua kernels, this is bad";
|
||||
//}
|
||||
|
|
|
@ -26,6 +26,8 @@ public:
|
|||
application_lua_kernel();
|
||||
bool initialize(game_launcher* gl);
|
||||
|
||||
virtual std::string my_name() { return "Application Lua Kernel"; }
|
||||
|
||||
static int intf_set_script(lua_State * L); /* Registers a lua function as the current script */
|
||||
void call_script(const config & cfg); /* Call the current script, with config passed as argument */
|
||||
};
|
||||
|
|
|
@ -2877,6 +2877,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
{
|
||||
lua_State *L = mState;
|
||||
|
||||
cmd_log_ << "Registering game-specific wesnoth lib functions...\n";
|
||||
|
||||
// Put some callback functions in the scripting environment.
|
||||
static luaL_Reg const callbacks[] = {
|
||||
{ "add_known_unit", &intf_add_known_unit },
|
||||
|
@ -2954,6 +2956,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_setglobal(L, "wesnoth");
|
||||
|
||||
// Create the getside metatable.
|
||||
cmd_log_ << "Adding getside metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, getsideKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
|
@ -2966,6 +2970,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the gettype metatable.
|
||||
cmd_log_ << "Adding gettype metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, gettypeKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
|
@ -2976,6 +2982,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
//Create the getrace metatable
|
||||
cmd_log_ << "Adding getrace metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, getraceKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
|
@ -2986,6 +2994,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the getunit metatable.
|
||||
cmd_log_ << "Adding getunit metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, getunitKey);
|
||||
lua_createtable(L, 0, 5);
|
||||
|
@ -3002,6 +3012,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the unit status metatable.
|
||||
cmd_log_ << "Adding unit status metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, ustatusKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
|
@ -3014,6 +3026,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the unit variables metatable.
|
||||
cmd_log_ << "Adding unit variables metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, unitvarKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
|
@ -3026,6 +3040,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the vconfig metatable.
|
||||
cmd_log_ << "Adding vconfig metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, vconfigKey);
|
||||
lua_createtable(L, 0, 4);
|
||||
|
@ -3040,9 +3056,13 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the ai elements table.
|
||||
cmd_log_ << "Adding ai elements table...\n";
|
||||
|
||||
ai::lua_ai_context::init(L);
|
||||
|
||||
// Create the game_config variable with its metatable.
|
||||
cmd_log_ << "Adding game_config table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 3);
|
||||
|
@ -3057,6 +3077,8 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_pop(L, 1);
|
||||
|
||||
// Create the current variable with its metatable.
|
||||
cmd_log_ << "Adding wesnoth current table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
|
@ -3069,18 +3091,24 @@ LuaKernel::LuaKernel(const config &cfg)
|
|||
lua_pop(L, 1);
|
||||
|
||||
// Create the wml_actions table.
|
||||
cmd_log_ << "Adding wml_actions table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
lua_setfield(L, -2, "wml_actions");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the game_events table.
|
||||
cmd_log_ << "Adding game_events table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
lua_setfield(L, -2, "game_events");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the theme_items table.
|
||||
cmd_log_ << "Adding theme_items table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
lua_createtable(L, 0, 2);
|
||||
|
@ -3122,6 +3150,8 @@ void LuaKernel::initialize()
|
|||
lua_pop(L, 2);
|
||||
|
||||
// Create the unit_types table.
|
||||
cmd_log_ << "Adding unit_types table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_pushlightuserdata(L
|
||||
, gettypeKey);
|
||||
|
@ -3140,6 +3170,8 @@ void LuaKernel::initialize()
|
|||
lua_pop(L, 2);
|
||||
|
||||
//Create the races table.
|
||||
cmd_log_ << "Adding races table...\n";
|
||||
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_pushlightuserdata(L
|
||||
, getraceKey);
|
||||
|
@ -3160,6 +3192,8 @@ void LuaKernel::initialize()
|
|||
lua_pop(L, 2);
|
||||
|
||||
// Execute the preload scripts.
|
||||
cmd_log_ << "Running preload scripts...\n";
|
||||
|
||||
game_config::load_config(preload_config);
|
||||
BOOST_FOREACH(const config &cfg, preload_scripts) {
|
||||
run(cfg["code"].str().c_str());
|
||||
|
|
|
@ -37,6 +37,9 @@ class LuaKernel : public lua_kernel_base
|
|||
|
||||
public:
|
||||
LuaKernel(const config &);
|
||||
|
||||
virtual std::string my_name() { return "Game Lua Kernel"; }
|
||||
|
||||
void initialize();
|
||||
void save_game(config &);
|
||||
void load_game();
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
static lg::log_domain log_scripting_lua("scripting/lua");
|
||||
#define DBG_LUA LOG_STREAM(debug, log_scripting_lua)
|
||||
#define LOG_LUA LOG_STREAM(info, log_scripting_lua)
|
||||
#define WRN_LUA LOG_STREAM(warn, log_scripting_lua)
|
||||
#define ERR_LUA LOG_STREAM(err, log_scripting_lua)
|
||||
|
@ -220,15 +221,87 @@ static int intf_compare_versions(lua_State* L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement print function -- instead of printing to std::cout, print to the command log.
|
||||
* Intended to be bound to this' command_log at registration time.
|
||||
*/
|
||||
int lua_kernel_base::intf_print(lua_State* L)
|
||||
{
|
||||
DBG_LUA << "intf_print called:\n";
|
||||
size_t nargs = lua_gettop(L);
|
||||
|
||||
for (size_t i = 2; i <= nargs; ++i) { // ignore first argument, since it's the userdata from boost cfunc binding
|
||||
cmd_log_ << lua_tostring(L,i);
|
||||
DBG_LUA << "'" << lua_tostring(L,i) << "'\n";
|
||||
}
|
||||
|
||||
cmd_log_ << "\n";
|
||||
DBG_LUA << "\n";
|
||||
|
||||
lua_pop(L, nargs - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make the possibility to push the boost::bind 'ed intf_print onto the lua stack, using a dispatcher to get around the C++ / boost::function aspect of this
|
||||
char const * boost_cfunc = "Boost_C_Function";
|
||||
|
||||
typedef boost::function<int(lua_State*)> lua_cfunc;
|
||||
|
||||
static int intf_boost_cfunc_dispatcher ( lua_State* L )
|
||||
{
|
||||
lua_cfunc *f = static_cast<lua_cfunc *> (lua_touserdata(L, 1));
|
||||
int result = (*f)(L);
|
||||
lua_remove(L,1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int intf_boost_cfunc_cleanup ( lua_State* L )
|
||||
{
|
||||
lua_cfunc * d = static_cast< lua_cfunc *> (luaL_testudata(L, 1, boost_cfunc));
|
||||
if (d == NULL) {
|
||||
ERR_LUA << "boost_cfunc_cleanup called on data of type: " << lua_typename( L, lua_type( L, 1 ) ) << std::endl;
|
||||
ERR_LUA << "This may indicate a memory leak, please report at bugs.wesnoth.org" << std::endl;
|
||||
} else {
|
||||
d->~lua_cfunc();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_boost_cfunc_metatable ( lua_State* L )
|
||||
{
|
||||
luaL_newmetatable(L, boost_cfunc);
|
||||
lua_pushcfunction(L, intf_boost_cfunc_dispatcher);
|
||||
lua_setfield(L, -2, "__call");
|
||||
lua_pushcfunction(L, intf_boost_cfunc_cleanup);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushvalue(L, -1); //make a copy of this table, set it to be its own __index table
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
static void push_boost_cfunc( lua_State* L, const lua_cfunc & f )
|
||||
{
|
||||
void * p = lua_newuserdata(L, sizeof(lua_cfunc));
|
||||
luaL_setmetatable(L, boost_cfunc);
|
||||
new (p) lua_cfunc(f);
|
||||
}
|
||||
|
||||
// End Callback implementations
|
||||
|
||||
lua_kernel_base::lua_kernel_base()
|
||||
: mState(luaL_newstate())
|
||||
, cmd_log_()
|
||||
{
|
||||
lua_State *L = mState;
|
||||
|
||||
cmd_log_ << "Initializing " << my_name() << "...\n";
|
||||
|
||||
// Open safe libraries.
|
||||
// Debug and OS are not, but most of their functions will be disabled below.
|
||||
cmd_log_ << "Adding standard libs...\n";
|
||||
|
||||
static const luaL_Reg safe_libs[] = {
|
||||
{ "", luaopen_base },
|
||||
{ "table", luaopen_table },
|
||||
|
@ -276,6 +349,8 @@ lua_kernel_base::lua_kernel_base()
|
|||
lua_setglobal(L, "loadfile");
|
||||
|
||||
// Store the error handler.
|
||||
cmd_log_ << "Adding error handler...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, executeKey);
|
||||
lua_getglobal(L, "debug");
|
||||
|
@ -285,6 +360,8 @@ lua_kernel_base::lua_kernel_base()
|
|||
lua_pop(L, 1);
|
||||
|
||||
// Create the gettext metatable.
|
||||
cmd_log_ << "Adding gettext metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, gettextKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
|
@ -295,6 +372,8 @@ lua_kernel_base::lua_kernel_base()
|
|||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create the tstring metatable.
|
||||
cmd_log_ << "Adding tstring metatable...\n";
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, tstringKey);
|
||||
lua_createtable(L, 0, 4);
|
||||
|
@ -311,6 +390,7 @@ lua_kernel_base::lua_kernel_base()
|
|||
lua_settop(L, 0);
|
||||
|
||||
// Add some callback from the wesnoth lib
|
||||
cmd_log_ << "Registering basic wesnoth API...\n";
|
||||
|
||||
static luaL_Reg const callbacks[] = {
|
||||
{ "compare_versions", &intf_compare_versions },
|
||||
|
@ -325,7 +405,6 @@ lua_kernel_base::lua_kernel_base()
|
|||
{ "set_dialog_markup", &intf_set_dialog_markup },
|
||||
{ "set_dialog_value", &intf_set_dialog_value },
|
||||
{ "show_dialog", &intf_show_dialog },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -336,6 +415,18 @@ lua_kernel_base::lua_kernel_base()
|
|||
luaL_setfuncs(L, callbacks, 0);
|
||||
lua_setglobal(L, "wesnoth");
|
||||
|
||||
// Define the Boost_C_Function metatable ( so we can override print to point to a C++ member function )
|
||||
cmd_log_ << "Adding boost cfunc proxy...\n";
|
||||
|
||||
register_boost_cfunc_metatable(L);
|
||||
|
||||
// Override the print function
|
||||
cmd_log_ << "Redirecting print function...\n";
|
||||
|
||||
lua_cfunc my_print = boost::bind(&lua_kernel_base::intf_print, this, _1);
|
||||
push_boost_cfunc(L, my_print);
|
||||
lua_setglobal(L, "print");
|
||||
|
||||
// Create the package table.
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
|
@ -444,18 +535,27 @@ bool lua_kernel_base::load_string(char const * prog, error_handler e_h)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Call load_string and protected call. Make them throw exceptions, and if we catch one, reformat it with signature for this function and log it.
|
||||
// Call load_string and protected call. Make them throw exceptions.
|
||||
//
|
||||
void lua_kernel_base::throwing_run(const char * prog) {
|
||||
cmd_log_ << "$ " << prog << "\n";
|
||||
error_handler eh = boost::bind(&lua_kernel_base::throw_exception, this, _1, _2 );
|
||||
load_string(prog, eh);
|
||||
protected_call(0, 0, eh);
|
||||
}
|
||||
|
||||
// Do a throwing run, but if we catch a lua_error, reformat it with signature for this function and log it.
|
||||
void lua_kernel_base::run(const char * prog) {
|
||||
try {
|
||||
error_handler eh = boost::bind(&lua_kernel_base::throw_exception, this, _1, _2 );
|
||||
load_string(prog, eh);
|
||||
protected_call(0, 0, eh);
|
||||
throwing_run(prog);
|
||||
} catch (game::lua_error & e) {
|
||||
cmd_log_ << e.what() << "\n";
|
||||
lua_kernel_base::log_error(e.what(), "In function lua_kernel::run()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads the "package" package into the Lua environment.
|
||||
* This action is inherently unsafe, as Lua scripts will now be able to
|
||||
|
@ -469,3 +569,67 @@ void lua_kernel_base::load_package()
|
|||
lua_pushstring(L, "package");
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the global variable names in the Lua environment. This is useful for tab completion.
|
||||
*/
|
||||
std::vector<std::string> lua_kernel_base::get_global_var_names()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
lua_State *L = mState;
|
||||
|
||||
int idx = lua_gettop(L);
|
||||
lua_getglobal(L, "_G");
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, idx+1) != 0) {
|
||||
if (lua_isstring(L, -2)) {
|
||||
ret.push_back(lua_tostring(L,-2));
|
||||
}
|
||||
lua_pop(L,1);
|
||||
}
|
||||
lua_settop(L, idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all attribute names of an extended variable name. This is useful for tab completion.
|
||||
*/
|
||||
std::vector<std::string> lua_kernel_base::get_attribute_names(const std::string & input)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
std::string var_path = input; // it's convenient to make a copy, even if it's a little slower
|
||||
|
||||
lua_State *L = mState;
|
||||
|
||||
int base = lua_gettop(L);
|
||||
lua_getglobal(L, "_G");
|
||||
|
||||
size_t idx = var_path.find('.');
|
||||
size_t last_dot = 0;
|
||||
while (idx != std::string::npos ) {
|
||||
last_dot += idx + 1; // Since idx was not npos, add it to the "last_dot" idx, so that last_dot keeps track of indices in input string
|
||||
lua_pushstring(L, var_path.substr(0, idx).c_str()); //push the part of the path up to the period
|
||||
lua_rawget(L, -2);
|
||||
|
||||
if (!lua_istable(L,-1) && !lua_isuserdata(L,-1)) {
|
||||
return ret; //if we didn't get a table or userdata we can't proceed
|
||||
}
|
||||
|
||||
var_path = var_path.substr(idx+1); // chop off the part of the path we just dereferenced
|
||||
idx = var_path.find('.'); // find the next .
|
||||
}
|
||||
|
||||
std::string prefix = input.substr(0, last_dot);
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_isstring(L, -2)) {
|
||||
ret.push_back(prefix + lua_tostring(L,-2));
|
||||
}
|
||||
lua_pop(L,1);
|
||||
}
|
||||
lua_settop(L, base);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,10 @@
|
|||
#ifndef SCRIPTING_LUA_KERNEL_BASE_HPP
|
||||
#define SCRIPTING_LUA_KERNEL_BASE_HPP
|
||||
|
||||
#include <string> // for string
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "utils/boost_function_guarded.hpp"
|
||||
|
||||
struct lua_State;
|
||||
|
@ -28,8 +31,20 @@ public:
|
|||
/** Runs a plain script. Doesn't throw lua_error.*/
|
||||
void run(char const *prog);
|
||||
|
||||
/** Runs a plain script, but reports errors by throwing lua_error.*/
|
||||
void throwing_run(char const * prog);
|
||||
|
||||
void load_package();
|
||||
|
||||
std::vector<std::string> get_global_var_names();
|
||||
std::vector<std::string> get_attribute_names(const std::string & var_path);
|
||||
|
||||
virtual std::string my_name() { return "Basic Lua Kernel"; }
|
||||
|
||||
const std::stringstream & get_log() { cmd_log_.log_ << std::flush; return cmd_log_.log_; }
|
||||
void clear_log() { cmd_log_.log_.str(""); cmd_log_.log_.clear(); }
|
||||
void set_external_log( std::ostream * lg ) { cmd_log_.external_log_ = lg; }
|
||||
|
||||
virtual void log_error(char const* msg, char const* context = "Lua error");
|
||||
virtual void throw_exception(char const* msg, char const* context = "Lua error"); //throws game::lua_error
|
||||
|
||||
|
@ -38,6 +53,33 @@ public:
|
|||
protected:
|
||||
lua_State *mState;
|
||||
|
||||
struct command_log {
|
||||
std::stringstream log_;
|
||||
std::ostream * external_log_;
|
||||
|
||||
command_log()
|
||||
: log_()
|
||||
, external_log_(NULL)
|
||||
{}
|
||||
|
||||
inline command_log & operator<< (const std::string & str) {
|
||||
log_ << str;
|
||||
if (external_log_) {
|
||||
(*external_log_) << str;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline command_log & operator<< (char const* str) {
|
||||
return *this << std::string(str);
|
||||
}
|
||||
};
|
||||
|
||||
command_log cmd_log_;
|
||||
|
||||
// Print text to the command log for this lua kernel. Used as a replacement impl for lua print.
|
||||
int intf_print(lua_State * L);
|
||||
|
||||
// Execute a protected call. Error handler is called in case of an error, using syntax for log_error and throw_exception above. Returns true if successful.
|
||||
bool protected_call(int nArgs, int nRets, error_handler);
|
||||
// Load a string onto the stack as a function. Returns true if successful, error handler is called if not.
|
||||
|
|
|
@ -91,6 +91,8 @@ mapgen_lua_kernel::mapgen_lua_kernel()
|
|||
lua_State *L = mState;
|
||||
|
||||
// Add mersenne twister rng wrapper
|
||||
cmd_log_ << "Adding mt19937 metatable...\n";
|
||||
|
||||
luaL_newmetatable(L, Rng);
|
||||
|
||||
static luaL_Reg const callbacks[] = {
|
||||
|
|
|
@ -25,6 +25,8 @@ class mapgen_lua_kernel : public lua_kernel_base {
|
|||
public:
|
||||
mapgen_lua_kernel();
|
||||
|
||||
virtual std::string my_name() { return "Mapgen Lua Kernel"; }
|
||||
|
||||
std::string create_map(const char * prog, const config & generator); // throws game::lua_error
|
||||
config create_scenario(const char * prog, const config & generator); // throws game::lua_error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue