mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-25 02:26:18 +02:00
Plugins: prop hunt APIs, and plugin commands in the console lookup
- reskate.entities.blueprints lists the game's object blueprints (meshes only if asked), and reskate.entities.bounds gives a blueprint's box, so a mod can pick a prop by list or at random - Attached objects take upright, turn and ground (a floor found within reach below), the "root" joint, and a 6th options argument with solid; spawned props' bodies are found and ghosted - reskate.skater.hide, reskate.world.pick, and skater.get gives right and switch - reskate.console.command takes an optional 4th table of subcommands; the console lookup suggests plugin commands word by word, and plugin commands lists the subcommands - objbody: a test command for finding which body setter takes a prop out of collision
This commit is contained in:
1 parent
c35e9a357b
commit
45346b122c
26 files changed
+1238
-36
No files matched your search
@@ -108,6 +108,12 @@ struct WorldApi {
|
||||
need(L, plugin, "overlay", "reskate.skater.xray");
|
||||
return result(L, game(plugin).xray(plugin.id(), lua_toboolean(L, 1) != 0));
|
||||
}
|
||||
// skater.hide(on): the local skater not drawn on this screen while on (nothing: true).
|
||||
static int hide_skater(lua_State* L) {
|
||||
auto& plugin = plugin_of(L);
|
||||
need(L, plugin, "skater.control", "reskate.skater.hide");
|
||||
return result(L, game(plugin).hide_skater(plugin.id(), lua_isnone(L, 1) || lua_toboolean(L, 1) != 0));
|
||||
}
|
||||
// skater.shape_launch(from, shape): the launches out of `from` ("grind", "ollie", "no_comply" or
|
||||
// "boneless") from now on, {across =, along =, up =} in m/s, each set if given (across the
|
||||
// direction of travel, + its left); nil the game's own.
|
||||
@@ -442,8 +448,10 @@ struct WorldApi {
|
||||
const auto id = entity_id(L, 1);
|
||||
const auto asset = checked_text(L, 2, 200, "a blueprint's name");
|
||||
const auto matrix = transform_of(L, 3);
|
||||
// attach = {player = id?, joint = number or name}: kept on that skater's joint, the transform
|
||||
// in the joint's frame.
|
||||
// entities.set(id, blueprint, transform, hidden?, attach?, options?).
|
||||
// attach = {player = id?, joint = number or name, upright = bool?, turn = bool?, ground = metres?}: kept on that
|
||||
// skater's joint, the transform in the joint's frame (upright: level, turned only by the joint's
|
||||
// heading; turn = false: the joint's position only, the transform's rotation in the world).
|
||||
std::optional<Game::EntityAttach> attach;
|
||||
if (!lua_isnoneornil(L, 5)) {
|
||||
luaL_checktype(L, 5, LUA_TTABLE);
|
||||
@@ -454,8 +462,31 @@ struct WorldApi {
|
||||
lua_getfield(L, 5, "joint");
|
||||
attach->joint = joint_of(L, lua_gettop(L));
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, 5, "upright");
|
||||
attach->upright = lua_toboolean(L, -1) != 0;
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, 5, "turn");
|
||||
attach->turn = lua_isnil(L, -1) || lua_toboolean(L, -1) != 0;
|
||||
lua_pop(L, 1);
|
||||
// ground = metres (or true: 2 m) below the joint to stand the object on the floor in.
|
||||
lua_getfield(L, 5, "ground");
|
||||
if (lua_isboolean(L, -1)) attach->ground = lua_toboolean(L, -1) ? 2.0f : 0.0f;
|
||||
else if (!lua_isnil(L, -1)) {
|
||||
const double reach = luaL_checknumber(L, -1);
|
||||
if (!(reach >= 0 && reach <= 50)) luaL_error(L, "an object finds the ground at most 50 m below its joint");
|
||||
attach->ground = static_cast<float>(reach);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result(L, game(plugin).entity_set(plugin.id(), id, asset, matrix, lua_toboolean(L, 4) != 0, attach));
|
||||
// options = {solid = false}: skaters go through the object.
|
||||
bool solid = true;
|
||||
if (!lua_isnoneornil(L, 6)) {
|
||||
luaL_checktype(L, 6, LUA_TTABLE);
|
||||
lua_getfield(L, 6, "solid");
|
||||
solid = lua_isnil(L, -1) || lua_toboolean(L, -1) != 0;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result(L, game(plugin).entity_set(plugin.id(), id, asset, matrix, lua_toboolean(L, 4) != 0, attach, solid));
|
||||
}
|
||||
static int entities_remove(lua_State* L) {
|
||||
auto& plugin = plugin_of(L);
|
||||
@@ -484,6 +515,78 @@ struct WorldApi {
|
||||
lua_pushboolean(L, game(plugin).entities_ready(plugin.id()));
|
||||
return 1;
|
||||
}
|
||||
// entities.blueprints(prefix?, meshes_only?): the world object blueprints loaded now, sorted;
|
||||
// with meshes_only, only those with a loaded mesh (the ones that show).
|
||||
static int entities_blueprints(lua_State* L) {
|
||||
auto& plugin = plugin_of(L);
|
||||
need(L, plugin, "world.entities", "reskate.entities.blueprints");
|
||||
const std::string prefix = lua_isnoneornil(L, 1) ? std::string{} : checked_text(L, 1, 200, "a blueprint name's start");
|
||||
const auto names = game(plugin).entity_blueprints(prefix, lua_toboolean(L, 2) != 0);
|
||||
lua_createtable(L, static_cast<int>(names.size()), 0);
|
||||
int index = 0;
|
||||
for (const auto& name : names) {
|
||||
lua_pushlstring(L, name.data(), name.size());
|
||||
lua_rawseti(L, -2, ++index);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// entities.bounds(blueprint): its mesh box in its own frame, min and max, or nil.
|
||||
static int entities_bounds(lua_State* L) {
|
||||
auto& plugin = plugin_of(L);
|
||||
need(L, plugin, "world.entities", "reskate.entities.bounds");
|
||||
const auto box = game(plugin).entity_bounds(checked_text(L, 1, 200, "a blueprint's name"));
|
||||
if (!box) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
push_position(L, (*box)[0]);
|
||||
push_position(L, (*box)[1]);
|
||||
return 2;
|
||||
}
|
||||
// world.pick(from, to): where the ray meets the world, and the object it meets: {position,
|
||||
// object = {blueprint?, position, heading, transform = {matrix}}?}, or nil when it is clear.
|
||||
static int world_pick(lua_State* L) {
|
||||
auto& plugin = plugin_of(L);
|
||||
need(L, plugin, "world.raycast", "reskate.world.pick");
|
||||
const auto from = position_of(L, 1, "the ray's start");
|
||||
const auto to = position_of(L, 2, "the ray's end");
|
||||
const float dx = to[0] - from[0], dy = to[1] - from[1], dz = to[2] - from[2];
|
||||
if (std::sqrt(dx * dx + dy * dy + dz * dz) > plugin.limits_.raycast_metres)
|
||||
luaL_error(L, "a ray is at most %d m long", static_cast<int>(plugin.limits_.raycast_metres));
|
||||
if (++plugin.raycasts_ > plugin.limits_.raycasts_per_tick)
|
||||
luaL_error(L, "more than %d raycasts in one tick", plugin.limits_.raycasts_per_tick);
|
||||
const auto pick = game(plugin).world_pick(from, to);
|
||||
if (!pick) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
lua_createtable(L, 0, 2);
|
||||
push_position(L, pick->at);
|
||||
lua_setfield(L, -2, "position");
|
||||
if (pick->object) {
|
||||
lua_createtable(L, 0, 4);
|
||||
if (!pick->blueprint.empty()) {
|
||||
lua_pushlstring(L, pick->blueprint.data(), pick->blueprint.size());
|
||||
lua_setfield(L, -2, "blueprint");
|
||||
}
|
||||
if (const auto& m = pick->matrix) {
|
||||
push_position(L, Vec3{(*m)[12], (*m)[13], (*m)[14]});
|
||||
lua_setfield(L, -2, "position");
|
||||
lua_pushnumber(L, std::atan2((*m)[8], (*m)[10])); // the forward row's heading, as the skater's
|
||||
lua_setfield(L, -2, "heading");
|
||||
lua_createtable(L, 0, 1);
|
||||
lua_createtable(L, 16, 0);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
lua_pushnumber(L, (*m)[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
lua_setfield(L, -2, "matrix");
|
||||
lua_setfield(L, -2, "transform");
|
||||
}
|
||||
lua_setfield(L, -2, "object");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static int place(lua_State* L) {
|
||||
need(L, plugin_of(L), "world.objects", "reskate.objects.place");
|
||||
auto object = pose(L, 2, 3, 4);
|
||||
@@ -1155,14 +1258,14 @@ struct WorldApi {
|
||||
static std::uint16_t joint_of(lua_State* L, int index) {
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
static constexpr std::pair<std::string_view, std::uint16_t> named[] = {
|
||||
{"right_hand", 49}, {"left_hand", 278}, {"head", 103}, {"hips", 7}, {"spine", 42}};
|
||||
{"right_hand", 49}, {"left_hand", 278}, {"head", 103}, {"hips", 7}, {"spine", 42}, {"root", 1}};
|
||||
const std::string_view name = lua_tostring(L, index);
|
||||
const auto at = std::find_if(std::begin(named), std::end(named), [&](const auto& n) { return n.first == name; });
|
||||
if (at == std::end(named)) luaL_error(L, "a joint is a number 0 to 394, or right_hand, left_hand, head, hips or spine");
|
||||
if (at == std::end(named)) luaL_error(L, "a joint is a number 0 to 394, or right_hand, left_hand, head, hips, spine or root");
|
||||
return at->second;
|
||||
}
|
||||
const double joint = luaL_checknumber(L, index);
|
||||
if (!(joint >= 0 && joint <= 394) || joint != static_cast<int>(joint)) luaL_error(L, "a joint is a number 0 to 394, or right_hand, left_hand, head, hips or spine");
|
||||
if (!(joint >= 0 && joint <= 394) || joint != static_cast<int>(joint)) luaL_error(L, "a joint is a number 0 to 394, or right_hand, left_hand, head, hips, spine or root");
|
||||
return static_cast<std::uint16_t>(joint);
|
||||
}
|
||||
static int push_joint(lua_State* L, const std::optional<Game::JointPlace>& at, std::uint16_t joint) {
|
||||
@@ -2352,7 +2455,7 @@ void WorldApi::install(Plugin& plugin, lua_State* L) {
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "reskate.permissions");
|
||||
add_functions(L, "skater", {{"state", state}, {"noclip", noclip}, {"boost", boost}, {"freeze", freeze}, {"wipeout", wipeout}, {"xray", xray},
|
||||
{"shape_launch", shape_launch}, {"reach", reach}, {"hand", hand}, {"joint", skater_joint}, {"pose", skater_pose}});
|
||||
{"shape_launch", shape_launch}, {"hide", hide_skater}, {"reach", reach}, {"hand", hand}, {"joint", skater_joint}, {"pose", skater_pose}});
|
||||
add_functions(L, "board", {{"motion", board_motion}, {"bones", board_bones}, {"set", board_set}, {"hide", board_hide}, {"clear", board_clear},
|
||||
{"park", board_park}, {"fit", board_fit}, {"toss", board_toss}});
|
||||
add_functions(L, "camera", {{"look", camera_look}, {"set", camera_set}, {"follow", camera_follow}, {"release", camera_release}, {"held", camera_held}, {"get", camera_get}});
|
||||
@@ -2361,8 +2464,9 @@ void WorldApi::install(Plugin& plugin, lua_State* L) {
|
||||
add_functions(L, "time", {{"slow", slow}, {"speed", speed}});
|
||||
add_functions(L, "objects", {{"catalog", catalog}, {"list", objects}, {"place", place}, {"move", move}, {"remove", remove}});
|
||||
add_functions(L, "entities", {{"set", entities_set}, {"remove", entities_remove}, {"clear", entities_clear}, {"status", entities_status},
|
||||
{"ready", entities_ready}});
|
||||
add_functions(L, "world", {{"set_time", set_time}, {"set_control", set_control}, {"set_park", set_park}});
|
||||
{"ready", entities_ready}, {"blueprints", entities_blueprints},
|
||||
{"bounds", entities_bounds}});
|
||||
add_functions(L, "world", {{"set_time", set_time}, {"set_control", set_control}, {"set_park", set_park}, {"pick", world_pick}});
|
||||
add_functions(L, "travel", {{"locations", locations}, {"levels", levels}, {"go", go}, {"load", load}});
|
||||
add_functions(L, "ai", {{"spawn", ai_spawn}, {"clear", ai_clear}, {"count", ai_count}});
|
||||
add_functions(L, "session", {{"skaters", skaters}, {"tag", tag}, {"joint", session_joint}, {"touch", session_touch},
|
||||
|
||||
Reference in new issue
Block a user