Skip to content

Commit

Permalink
Squirrel: Default argument support for exposed C++ functions (#3025)
Browse files Browse the repository at this point in the history
This PR updates the simplesquirrel submodule to a branch which supports exposing C++ functions (including class constructors) with default arguments.

The `Camera::set_scale()`, `scripting::Level::spawn()`, `scripting::Globals::wait()` and `MovingSprite::set_action()` functions were modified to support default arguments and their respective other functions were marked as deprecated. In case more functions are found suitable for this, this PR would be updated.
  • Loading branch information
Vankata453 authored Dec 16, 2024
1 parent 4e5457f commit 2451a82
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 89 deletions.
14 changes: 7 additions & 7 deletions src/object/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ Camera::set_mode(const std::string& mode)
}

void
Camera::ease_scale_anchor(float scale, float time, int anchor, const std::string& ease)
Camera::set_scale(float scale, float time, int anchor, const std::string& ease)
{
ease_scale(scale, time, getEasingByName(EasingMode_from_string(ease)), static_cast<AnchorPoint>(anchor));
}
Expand Down Expand Up @@ -862,12 +862,12 @@ Camera::register_class(ssq::VM& vm)
cls.addFunc<void, Camera, float, float, float>("scroll_to", &Camera::scroll_to);
cls.addFunc("get_current_scale", &Camera::get_current_scale);
cls.addFunc("get_target_scale", &Camera::get_target_scale);
cls.addFunc("set_scale", &Camera::set_scale);
cls.addFunc("set_scale_anchor", &Camera::set_scale_anchor);
cls.addFunc("scale", &Camera::scale);
cls.addFunc("scale_anchor", &Camera::scale_anchor);
cls.addFunc<void, Camera, float, float, const std::string&>("ease_scale", &Camera::ease_scale);
cls.addFunc("ease_scale_anchor", &Camera::ease_scale_anchor);
cls.addFunc("set_scale", &Camera::set_scale, ssq::DefaultArguments<float, int, const std::string&>(0.f, AnchorPoint::ANCHOR_MIDDLE, ""));
cls.addFunc("set_scale_anchor", &Camera::set_scale_anchor); // Deprecated
cls.addFunc("scale", &Camera::scale); // Deprecated
cls.addFunc("scale_anchor", &Camera::scale_anchor); // Deprecated
cls.addFunc<void, Camera, float, float, const std::string&>("ease_scale", &Camera::ease_scale); // Deprecated
cls.addFunc("ease_scale_anchor", &Camera::set_scale); // Deprecated
cls.addFunc("get_screen_width", &Camera::get_screen_width);
cls.addFunc("get_screen_height", &Camera::get_screen_height);
cls.addFunc("get_x", &Camera::get_x);
Expand Down
24 changes: 18 additions & 6 deletions src/object/camera.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,44 +161,55 @@ class Camera final : public LayerObject,
inline void scroll_to(float x, float y, float scrolltime) { scroll_to(Vector(x, y), scrolltime); }
/**
* @scripting
* @description Sets the scale factor.
* @description Fades to a specified scale factor and target position anchor in ""time"" seconds with easing (smooth movement).
NOTE: Target position anchor is only applied, if the camera is in "manual" mode.
* @param float $scale
* @param float $time
* @param int $anchor Anchor point as represented by the ""ANCHOR_*"" constants.
Optional, default is ""ANCHOR_MIDDLE"" (see ${SRG_REF_AnchorPoints}).
* @param string $ease Optional, empty by default.
*/
inline void set_scale(float scale) { ease_scale(scale, 0.f, ""); }
void set_scale(float scale, float time = 0.f, int anchor = ANCHOR_MIDDLE, const std::string& ease = "");
/**
* @scripting
* @deprecated Use ""set_scale()"" instead!
* @description Sets the scale factor and the target position anchor.
NOTE: Target position anchor is only applied, if the camera is in "manual" mode.
* @param float $scale
* @param int $anchor Anchor point as represented by the ""ANCHOR_*"" constants (see ${SRG_REF_AnchorPoints}).
*/
inline void set_scale_anchor(float scale, int anchor) { ease_scale_anchor(scale, 0, anchor, ""); }
inline void set_scale_anchor(float scale, int anchor) { set_scale(scale, 0, anchor, ""); }
/**
* @scripting
* @deprecated Use ""set_scale()"" instead!
* @description Fades to a specified scale factor in ""time"" seconds.
* @param float $scale
* @param float $time
*/
inline void scale(float scale, float time) { ease_scale(scale, time, ""); }
inline void scale(float scale, float time) { set_scale(scale, time, AnchorPoint::ANCHOR_MIDDLE, ""); }
/**
* @scripting
* @deprecated Use ""set_scale()"" instead!
* @description Fades to a specified scale factor and target position anchor in ""time"" seconds.
NOTE: Target position anchor is only applied, if the camera is in "manual" mode.
* @param float $scale
* @param float $time
* @param int $anchor Anchor point as represented by the ""ANCHOR_*"" constants (see ${SRG_REF_AnchorPoints}).
*/
inline void scale_anchor(float scale, float time, int anchor) { ease_scale_anchor(scale, time, anchor, ""); }
inline void scale_anchor(float scale, float time, int anchor) { set_scale(scale, time, anchor, ""); }
/**
* @scripting
* @deprecated Use ""set_scale()"" instead!
* @description Fades to a specified scale factor in ""time"" seconds with easing (smooth movement).
* @param float $scale
* @param float $time
* @param string $ease
*/
inline void ease_scale(float scale, float time, const std::string& ease) { ease_scale_anchor(scale, time, AnchorPoint::ANCHOR_MIDDLE, ease); }
inline void ease_scale(float scale, float time, const std::string& ease) { set_scale(scale, time, AnchorPoint::ANCHOR_MIDDLE, ease); }
#ifdef DOXYGEN_SCRIPTING
/**
* @scripting
* @deprecated Use ""set_scale()"" instead!
* @description Fades to a specified scale factor and target position anchor in ""time"" seconds with easing (smooth movement).
NOTE: Target position anchor is only applied, if the camera is in "manual" mode.
* @param float $scale
Expand All @@ -207,6 +218,7 @@ class Camera final : public LayerObject,
* @param string $ease
*/
void ease_scale_anchor(float scale, float time, int anchor, const std::string& ease);
#endif
/**
* @scripting
* @description Gets the current width of the screen.
Expand Down
1 change: 1 addition & 0 deletions src/object/floating_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ FloatingImage::register_class(ssq::VM& vm)

return &Sector::get().add<FloatingImage>(spritefile);
},
{},
false /* Do not free pointer from Squirrel */,
vm.findClass("GameObject"));

Expand Down
11 changes: 2 additions & 9 deletions src/object/moving_sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,6 @@ MovingSprite::update_hitbox()
m_col.set_unisolid(m_sprite->is_current_hitbox_unisolid());
}

void
MovingSprite::set_action(const std::string& name)
{
m_sprite->set_action(name);
update_hitbox();
}

void
MovingSprite::set_action(const std::string& name, int loops)
{
Expand Down Expand Up @@ -256,8 +249,8 @@ MovingSprite::register_class(ssq::VM& vm)
cls.addFunc("set_sprite", &MovingSprite::change_sprite);
cls.addFunc("get_sprite", &MovingSprite::get_sprite_name);
cls.addFunc("get_action", &MovingSprite::get_action);
cls.addFunc<void, MovingSprite, const std::string&>("set_action", &MovingSprite::set_action);
cls.addFunc("set_action_loops", &MovingSprite::set_action_loops);
cls.addFunc<void, MovingSprite, const std::string&, int>("set_action", &MovingSprite::set_action, ssq::DefaultArguments<int>(-1));
cls.addFunc<void, MovingSprite, const std::string&, int>("set_action_loops", &MovingSprite::set_action); // Deprecated

cls.addVar("sprite", &MovingSprite::get_sprite_name, &MovingSprite::set_sprite);
}
Expand Down
15 changes: 8 additions & 7 deletions src/object/moving_sprite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,23 @@ class MovingSprite : public MovingObject
std::string get_action() const;
/**
* @scripting
* @description Sets the current action of the sprite and resizes the bounding box.
* @description Sets the current action of the sprite, as well as the number of times it should loop, and resizes the bounding box.
NOTE: Use with care as you can easily get stuck when resizing the bounding box.
* @param string $name
* @param int $loops Optional, -1 by default (negative value means infinite). Set to -100 to continue looping from the previous action.
*/
void set_action(const std::string& name);
void set_action(const std::string& name, int loops = -1);
#ifdef DOXYGEN_SCRIPTING
/**
* @scripting
* @deprecated Use ""set_action()"" instead!
* @description Sets the current action of the sprite, as well as the number of times it should loop, and resizes the bounding box.
NOTE: Use with care as you can easily get stuck when resizing the bounding box.
* @param string $name
* @param int $loops
* @param int $loops Negative value means infinite. Set to -100 to continue looping from the previous action.
*/
inline void set_action_loops(const std::string& name, int loops) { set_action(name, loops); }

/** Sets the action from an action name, as well as the number of times it should loop. */
void set_action(const std::string& name, int loops);
void set_action_loops(const std::string& name, int loops);
#endif

/** Sets the action from an action name and a particular direction
in the form of "name-direction", eg. "walk-left".
Expand Down
1 change: 1 addition & 0 deletions src/object/text_array_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ TextArrayObject::register_class(ssq::VM& vm)

return &Sector::get().add<TextArrayObject>();
},
{},
false /* Do not free pointer from Squirrel */,
vm.findClass("GameObject"));

Expand Down
1 change: 1 addition & 0 deletions src/object/text_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ TextObject::register_class(ssq::VM& vm)

return &Sector::get().add<TextObject>();
},
{},
false /* Do not free pointer from Squirrel */,
vm.findClass("GameObject"));

Expand Down
98 changes: 49 additions & 49 deletions src/squirrel/supertux_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,55 +158,47 @@ static bool check_cutscene()
* @scripting
* @description Suspends the script execution for a specified number of seconds.
* @param float $seconds
* @param bool $forced Optional, enforces waiting while a cutscene is being skipped.
* @returns void
*/
static SQInteger wait(HSQUIRRELVM vm, float seconds)
static SQInteger wait(HSQUIRRELVM vm, float seconds, bool forced = false)
{
ssq::VM* ssq_vm = ssq::VM::get(vm);
if (ssq_vm && !ssq_vm->isThread()) return 0;

auto session = GameSession::current();
if (session && session->get_current_level().m_skip_cutscene)
if (!forced)
{
if (ssq_vm && ssq_vm->getForeignPtr())
{
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
// Wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}`.
return squirrelenv->wait_for_seconds(vm, 0);
}
else
auto session = GameSession::current();
if (session && session->get_current_level().m_skip_cutscene)
{
if (ssq_vm && ssq_vm->getForeignPtr())
{
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
// Wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}`.
return squirrelenv->wait_for_seconds(vm, 0);
}
auto squirrelvm = ssq::VM::getMain(vm).getForeignPtr<SquirrelVirtualMachine>();
return squirrelvm->wait_for_seconds(vm, 0);
}
}
else if (session && session->get_current_level().m_is_in_cutscene)
{
if (ssq_vm && ssq_vm->getForeignPtr())
{
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
// Wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}` from freezing the game.
return squirrelenv->skippable_wait_for_seconds(vm, seconds);
}
else
if (session && session->get_current_level().m_is_in_cutscene)
{
if (ssq_vm && ssq_vm->getForeignPtr())
{
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
// Wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}` from freezing the game.
return squirrelenv->skippable_wait_for_seconds(vm, seconds);
}
auto squirrelvm = ssq::VM::getMain(vm).getForeignPtr<SquirrelVirtualMachine>();
return squirrelvm->skippable_wait_for_seconds(vm, seconds);
}
}
else
if (ssq_vm && ssq_vm->getForeignPtr())
{
if (ssq_vm && ssq_vm->getForeignPtr())
{
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
return squirrelenv->wait_for_seconds(vm, seconds);
}
else
{
auto squirrelvm = ssq::VM::getMain(vm).getForeignPtr<SquirrelVirtualMachine>();
return squirrelvm->wait_for_seconds(vm, seconds);
}
auto squirrelenv = ssq_vm->getForeignPtr<SquirrelEnvironment>();
return squirrelenv->wait_for_seconds(vm, seconds);
}
auto squirrelvm = ssq::VM::getMain(vm).getForeignPtr<SquirrelVirtualMachine>();
return squirrelvm->wait_for_seconds(vm, seconds);
}

/**
Expand Down Expand Up @@ -665,15 +657,34 @@ static bool has_active_sequence()
If that spawnpoint doesn't exist either, Tux will simply end up at the origin (top-left 0, 0).
* @param string $sector
* @param string $spawnpoint
* @param string $transition Valid transitions are ""circle"" and ""fade"". If any other value is specified, no transition effect is drawn.
Optional, empty by default.
*/
static void spawn(const std::string& sector, const std::string& spawnpoint)
static void spawn(const std::string& sector, const std::string& spawnpoint, const std::string& transition = "")
{
if (!GameSession::current()) return;
GameSession::current()->respawn(sector, spawnpoint);
}

if (transition.empty())
{
GameSession::current()->respawn(sector, spawnpoint);
return;
}

ScreenFade::FadeType fade_type = ScreenFade::FadeType::NONE;

if (transition == "fade")
fade_type = ScreenFade::FadeType::FADE;
else if (transition == "circle")
fade_type = ScreenFade::FadeType::CIRCLE;
else
log_warning << "Invalid transition type '" << transition << "'." << std::endl;

GameSession::current()->respawn_with_fade(sector, spawnpoint, fade_type, {0.0f, 0.0f}, true);
}
#ifdef DOXYGEN_SCRIPTING
/**
* @scripting
* @deprecated Use ""spawn()"" instead!
* @description Respawns Tux in sector named ""sector"" at spawnpoint named ""spawnpoint"" with the given transition ""transition"".${SRG_TABLENEWPARAGRAPH}
Exceptions: If ""sector"" or ""spawnpoint"" are empty, or the specified sector does not exist, the function will bail out the first chance it gets.
If the specified spawnpoint doesn't exist, Tux will be spawned at the spawnpoint named “main”.
Expand All @@ -684,19 +695,8 @@ static void spawn(const std::string& sector, const std::string& spawnpoint)
*/
static void spawn_transition(const std::string& sector, const std::string& spawnpoint, const std::string& transition)
{
if (!GameSession::current()) return;

ScreenFade::FadeType fade_type = ScreenFade::FadeType::NONE;

if (transition == "fade")
fade_type = ScreenFade::FadeType::FADE;
else if (transition == "circle")
fade_type = ScreenFade::FadeType::CIRCLE;
else
log_warning << "Invalid transition type '" << transition << "'." << std::endl;

GameSession::current()->respawn_with_fade(sector, spawnpoint, fade_type, {0.0f, 0.0f}, true);
}
#endif

/**
* @scripting
Expand Down Expand Up @@ -860,7 +860,7 @@ void register_supertux_scripting_api(ssq::VM& vm)
vm.addFunc("start_cutscene", &scripting::Globals::start_cutscene);
vm.addFunc("end_cutscene", &scripting::Globals::end_cutscene);
vm.addFunc("check_cutscene", &scripting::Globals::check_cutscene);
vm.addFunc("wait", &scripting::Globals::wait);
vm.addFunc("wait", &scripting::Globals::wait, ssq::DefaultArguments<bool>(false));
vm.addFunc("wait_for_screenswitch", &scripting::Globals::wait_for_screenswitch);
vm.addFunc("exit_screen", &scripting::Globals::exit_screen);
vm.addFunc("translate", &scripting::Globals::translate);
Expand Down Expand Up @@ -901,8 +901,8 @@ void register_supertux_scripting_api(ssq::VM& vm)
ssq::Table level = vm.addTable("Level");
level.addFunc("finish", &scripting::Level::finish);
level.addFunc("has_active_sequence", &scripting::Level::has_active_sequence);
level.addFunc("spawn", &scripting::Level::spawn);
level.addFunc("spawn_transition", &scripting::Level::spawn_transition);
level.addFunc("spawn", &scripting::Level::spawn, ssq::DefaultArguments<const std::string&>(""));
level.addFunc("spawn_transition", &scripting::Level::spawn); // Deprecated
level.addFunc("set_start_point", &scripting::Level::set_start_point);
level.addFunc("set_start_pos", &scripting::Level::set_start_pos);
level.addFunc("set_respawn_point", &scripting::Level::set_respawn_point);
Expand Down
1 change: 1 addition & 0 deletions tools/scripting_docs_gen/class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct Parameter
std::string type {};
std::string name {};
std::string description {};
std::string default_value {};
};

struct Function
Expand Down
3 changes: 0 additions & 3 deletions tools/scripting_docs_gen/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@ int main(int argc, char** argv)
// Formatting
replace(target_data, "${SRG_NEWPARAGRAPH} ", "\r\n\r\n");
replace(target_data, "${SRG_TABLENEWPARAGRAPH}", "<br /><br />");
replace(target_data, "\"\"", "`");
replace(target_data, "NOTE:", "<br /><br />**NOTE:**");
replace(target_data, "Note:", "<br /><br />**NOTE:**");

// Write to target file
write_file(output_dir_path / std::filesystem::path("Scripting" + cl.name + ".md"), target_data);
Expand Down
21 changes: 21 additions & 0 deletions tools/scripting_docs_gen/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,27 @@ void parse_parameterlist(tinyxml2::XMLElement* p_memberdef, Function& func)

p_parameteritem = p_parameteritem->NextSiblingElement("parameteritem");
}

// Get default parameter values
tinyxml2::XMLElement* p_param = p_memberdef->FirstChildElement("param");
while (p_param)
{
tinyxml2::XMLElement* p_defval = p_param->FirstChildElement("defval");
if (p_defval)
{
tinyxml2::XMLElement* p_declname = p_param->FirstChildElement("declname");
for (Parameter& param : func.parameters)
{
if (!strcmp(p_declname->GetText(), param.name.c_str()))
{
param.default_value = p_defval->GetText();
break;
}
}
}

p_param = p_param->NextSiblingElement("param");
}
}


Expand Down
Loading

0 comments on commit 2451a82

Please sign in to comment.