Skip to content

Commit

Permalink
Move scripting reference classes to another file, richer Console sugg…
Browse files Browse the repository at this point in the history
…estions
  • Loading branch information
Vankata453 committed Dec 18, 2023
1 parent a99fe41 commit 9b107a0
Show file tree
Hide file tree
Showing 14 changed files with 471 additions and 174 deletions.
26 changes: 22 additions & 4 deletions data/scripts/reference.stsr
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
(class
(name "Camera")
(summary (_ "A `Camera` that was given a name can be manipulated by scripts."))
(instances (_ "An instance named `Camera` (`sector.Camera` in the console) is available.The mode of the camera is either normal (the camera is following the player) or autoscroll. In the latter mode the camera is forced along a specified `Path`."))
(instances (_ "An instance named `Camera` (`sector.Camera` in the console) is available. The mode of the camera is either normal (the camera is following the player) or autoscroll. In the latter mode the camera is forced along a specified `Path`."))
(function
(name "reload_config")
(type "void")
Expand Down Expand Up @@ -1695,7 +1695,7 @@
(class
(name "FloatingImage")
(summary (_ "This class provides the ability to create, edit, and remove images floating in midair on the screen, such as the SuperTux logo. It is implemented as a wrapper around a sprite, so any sprite actions are applicable."))
(instances (_ "Floating Images are created in a script or from the console. Constructor:```<floatimage> <- FloatingImage(string filename)```This creates a `FloatingImage` from `filename` (which is relative to the data directory root)."))
(instances (_ "Floating Images are created in a script or from the console. Constructor: ```<floatimage> <- FloatingImage(string filename)``` This creates a `FloatingImage` from `filename` (which is relative to the data directory root)."))
(function
(name "set_layer")
(type "void")
Expand Down Expand Up @@ -1801,7 +1801,7 @@
(class
(name "GameObjectManager")
(summary (_ "This class provides basic controlling functions for a sector. Applies for both worldmap and in-level sectors."))
(instances (_ "For in-level sectors, an instance under `sector.settings` is available from scripts and the console.For worldmap sectors, such instance is available under `worldmap.settings`."))
(instances (_ "For in-level sectors, an instance under `sector.settings` is available from scripts and the console. For worldmap sectors, such instance is available under `worldmap.settings`."))
(function
(name "set_ambient_light")
(type "void")
Expand Down Expand Up @@ -2292,6 +2292,24 @@
(type "string")
)
)
(function
(name "register_scripting_reference")
(type "void")
(description (_ "Registers a scripting reference data file (\"supertux-scripting-reference\")."))
(parameter
(name "filename")
(type "string")
)
)
(function
(name "unregister_scripting_reference")
(type "void")
(description (_ "Unregisters scripting reference data, loaded from the specified file."))
(parameter
(name "filename")
(type "string")
)
)
(class
(name "Gradient")
(summary (_ "A `Gradient` that was given a name can be controlled by scripts."))
Expand Down Expand Up @@ -3574,7 +3592,7 @@
)
(class
(name "TextArray")
(summary (_ "A `TextArrayObject` that was given a name can be controlled by scripts. Supports all functions of `Text`, applying them to the current text item.Intended for scripts with narration."))
(summary (_ "A `TextArrayObject` that was given a name can be controlled by scripts. Supports all functions of `Text`, applying them to the current text item. Intended for scripts with narration."))
(instances (_ "A `TextArrayObject` is instantiated by placing a definition inside a level. It can then be accessed by its name from a script or via `sector.name` from the console."))
(function
(name "clear")
Expand Down
2 changes: 1 addition & 1 deletion src/interface/control_scriptbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ ControlScriptbox::on_caret_move()

m_selected_suggestion = 0;
m_suggestions_offset = 0.f;
m_suggestions = squirrel::autocomplete(line_content, true);
m_suggestions = squirrel::get_suggestions(line_content, true);

calculate_suggestion_rect();
update_description();
Expand Down
2 changes: 1 addition & 1 deletion src/interface/control_scriptbox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <vector>

#include "interface/control_scrollbar.hpp"
#include "squirrel/autocomplete.hpp"
#include "squirrel/suggestions.hpp"

class ControlScriptbox final : public ControlTextbox
{
Expand Down
1 change: 1 addition & 0 deletions src/interface/control_textbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ ControlTextbox::ControlTextbox(bool multiline) :
ControlTextbox::~ControlTextbox()
{
parse_value();
MouseCursor::current()->set_action(MouseCursorAction::SELECT);
}

void
Expand Down
11 changes: 11 additions & 0 deletions src/scripting/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "object/camera.hpp"
#include "object/player.hpp"
#include "physfs/ifile_stream.hpp"
#include "squirrel/scripting_reference.hpp"
#include "supertux/console.hpp"
#include "supertux/debug.hpp"
#include "supertux/game_manager.hpp"
Expand Down Expand Up @@ -482,6 +483,16 @@ void play_demo(const std::string& filename)
session->play_demo(filename);
}

void register_scripting_reference(const std::string& filename)
{
squirrel::register_scripting_reference(filename);
}

void unregister_scripting_reference(const std::string& filename)
{
squirrel::unregister_scripting_reference(filename);
}

}

/* EOF */
12 changes: 12 additions & 0 deletions src/scripting/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,18 @@ void record_demo(const std::string& filename);
*/
void play_demo(const std::string& filename);

/**
* Registers a scripting reference data file ("supertux-scripting-reference").
* @param string $filename
*/
void register_scripting_reference(const std::string& filename);

/**
* Unregisters scripting reference data, loaded from the specified file.
* @param string $filename
*/
void unregister_scripting_reference(const std::string& filename);

#ifdef DOXYGEN_SCRIPTING
}
#endif
Expand Down
60 changes: 60 additions & 0 deletions src/scripting/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12549,6 +12549,52 @@ static SQInteger play_demo_wrapper(HSQUIRRELVM vm)

}

static SQInteger register_scripting_reference_wrapper(HSQUIRRELVM vm)
{
const SQChar* arg0;
if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
sq_throwerror(vm, _SC("Argument 1 not a string"));
return SQ_ERROR;
}

try {
scripting::register_scripting_reference(arg0);

return 0;

} catch(std::exception& e) {
sq_throwerror(vm, e.what());
return SQ_ERROR;
} catch(...) {
sq_throwerror(vm, _SC("Unexpected exception while executing function 'register_scripting_reference'"));
return SQ_ERROR;
}

}

static SQInteger unregister_scripting_reference_wrapper(HSQUIRRELVM vm)
{
const SQChar* arg0;
if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
sq_throwerror(vm, _SC("Argument 1 not a string"));
return SQ_ERROR;
}

try {
scripting::unregister_scripting_reference(arg0);

return 0;

} catch(std::exception& e) {
sq_throwerror(vm, e.what());
return SQ_ERROR;
} catch(...) {
sq_throwerror(vm, _SC("Unexpected exception while executing function 'unregister_scripting_reference'"));
return SQ_ERROR;
}

}

static SQInteger Level_finish_wrapper(HSQUIRRELVM vm)
{
SQBool arg0;
Expand Down Expand Up @@ -14030,6 +14076,20 @@ void register_supertux_wrapper(HSQUIRRELVM v)
throw SquirrelError(v, "Couldn't register function 'play_demo'");
}

sq_pushstring(v, "register_scripting_reference", -1);
sq_newclosure(v, &register_scripting_reference_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, ".s");
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'register_scripting_reference'");
}

sq_pushstring(v, "unregister_scripting_reference", -1);
sq_newclosure(v, &unregister_scripting_reference_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, ".s");
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'unregister_scripting_reference'");
}

sq_pushstring(v, "Level_finish", -1);
sq_newclosure(v, &Level_finish_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, ".b|n");
Expand Down
178 changes: 178 additions & 0 deletions src/squirrel/scripting_reference.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// SuperTux
// Copyright (C) 2023 Vankata453
//
// 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 3 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; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "squirrel/scripting_reference.hpp"

#include <algorithm>

#include "util/log.hpp"
#include "util/reader_document.hpp"
#include "util/reader_iterator.hpp"
#include "util/reader_mapping.hpp"

namespace squirrel {

ScriptingObject::ScriptingObject(const ReaderMapping& reader) :
name()
{
reader.get("name", name);
if (name.empty())
throw std::runtime_error("No name specified.");
}

ScriptingConstant::ScriptingConstant(const ReaderMapping& reader) :
ScriptingObject(reader),
type(),
description(),
detailed_description()
{
reader.get("type", type);
reader.get("description", description);
reader.get("detailed-description", detailed_description);
}

ScriptingFunction::ScriptingFunction(const ReaderMapping& reader) :
ScriptingObject(reader),
type(),
description(),
detailed_description(),
parameters()
{
reader.get("type", type);
reader.get("description", description);
reader.get("detailed-description", detailed_description);

auto iter = reader.get_iter();
while (iter.next())
{
if (iter.get_key() != "parameter")
continue;

auto param_reader = iter.as_mapping();

Parameter param;
param_reader.get("type", param.type);
param_reader.get("name", param.name);
param_reader.get("description", param.description);

parameters.push_back(std::move(param));
}
}

ScriptingClass::ScriptingClass(const ReaderMapping& reader) :
ScriptingObject(reader),
base_classes(),
summary(),
instances(),
constants(),
functions(),
classes()
{
reader.get("summary", summary);
reader.get("instances", instances);

auto iter = reader.get_iter();
while (iter.next())
{
if (iter.get_key() == "base-class")
{
std::string base_class_name;
iter.get(base_class_name);
base_classes.push_back(std::move(base_class_name));
continue;
}

add_object(iter.get_key(), iter.as_mapping());
}
}

void
ScriptingClass::add_object(const std::string& key, const ReaderMapping& reader)
{
try
{
if (key == "constant")
constants.push_back(ScriptingConstant(reader));
else if (key == "function")
functions.push_back(ScriptingFunction(reader));
else if (key == "class")
classes.push_back(ScriptingClass(reader));
}
catch (const std::exception& err)
{
log_warning << "Error adding scripting reference object '" << key << "': " << err.what() << std::endl;
}
}

ScriptingRoot::ScriptingRoot(const std::string& file_) :
ScriptingClass(),
file(file_)
{
}

std::vector<std::unique_ptr<ScriptingRoot>> s_scripting_roots;

bool
has_registered_reference_file(const std::string& file)
{
return std::any_of(s_scripting_roots.begin(), s_scripting_roots.end(),
[&file](const auto& root) { return root->file == file; });
}

void
register_scripting_reference(const std::string& file)
{
if (has_registered_reference_file(file))
{
log_warning << "Cannot register scripting reference data twice from the same file: '" << file << "'." << std::endl;
return;
}

try
{
auto scripting_root = std::make_unique<ScriptingRoot>(file);

auto doc = ReaderDocument::from_file(file);
auto root = doc.get_root();
if (root.get_name() == "supertux-scripting-reference")
{
auto iter = root.get_mapping().get_iter();
while (iter.next())
scripting_root->add_object(iter.get_key(), iter.as_mapping());
}
else
{
throw std::runtime_error("File is not a 'supertux-scripting-reference' file.");
}

s_scripting_roots.push_back(std::move(scripting_root));
}
catch (const std::exception& err)
{
log_warning << "Cannot load scripting reference data from '" << file << "': " << err.what() << std::endl;
}
}

void
unregister_scripting_reference(const std::string& file)
{
s_scripting_roots.erase(
std::remove_if(s_scripting_roots.begin(), s_scripting_roots.end(),
[&file](const auto& root) { return root->file == file; }),
s_scripting_roots.end());
}

} // namespace squirrel
Loading

0 comments on commit 9b107a0

Please sign in to comment.