Final Touches On The API
This commit is contained in:
parent
be820dd362
commit
71e660575f
33
docs/API.md
33
docs/API.md
@ -16,7 +16,7 @@ By default, MCPI-Reborn runs in a "compatibility mode." This makes it completely
|
||||
* <b>Bold</b> text only applies to the compatibility mode.
|
||||
* <ins>Underlined</ins> text only applies when it is disabled.
|
||||
* Text enclosed in curly braces (for instance `{text}`) is meant to be [Base64-URL](https://base64.guru/standards/base64url)-encoded when the compatibility mode is disabled.
|
||||
* In compatibility mode, entity type IDs are automatically translated to/from their [MC Java equivalents](https://mcreator.net/wiki/entity-ids#toc-index-2).
|
||||
* In the compatibility mode, entity type IDs are automatically translated to/from their [MC Java equivalents](https://mcreator.net/wiki/entity-ids#toc-index-2).
|
||||
|
||||
## Commands
|
||||
* Commands are formatted like `<command>(<args>)` and may return a response. The response `Fail` indicates an error.
|
||||
@ -88,30 +88,30 @@ By default, MCPI-Reborn runs in a "compatibility mode." This makes it completely
|
||||
* Description: Retrieve the entity ID of the specified player.
|
||||
* Output: `entity_id`
|
||||
* `world.getEntities(entity_type_id)`
|
||||
* Description: Retrieve all entities of the specified type[^1].
|
||||
* Description: Retrieve all entities of the specified type[^1][^2].
|
||||
* Output: List <code>entity_id,entity_type_id<b>,entity_type_name</b>,:x:,:y:,:z:</code>
|
||||
* `entity.getEntities(entity_id,distance,entity_type_id)`
|
||||
* Description: Retrieve all entities of the specified type[^1] within the given distance of the provided entity.
|
||||
* Description: Retrieve all entities of the specified type[^1][^2] within the given distance of the provided entity.
|
||||
* Output: See above.
|
||||
* `world.removeEntity(entity_id)`
|
||||
* Description: Remove the specified entity.
|
||||
* Description: Remove the specified entity[^1].
|
||||
* Output: `number_of_entities_removed`
|
||||
* `world.removeEntities(entity_type_id)`
|
||||
* Description: Remove all entities of the specified type[^1].
|
||||
* Description: Remove all entities of the specified type[^1][^2].
|
||||
* Output: See above.
|
||||
* `entity.removeEntities(entity_id,distance,entity_type_id)`
|
||||
* Description: Remove all entities of the specified type[^1] within the given distance of the provided entity.
|
||||
* Description: Remove all entities of the specified type[^1][^2] within the given distance of the provided entity.
|
||||
* Output: See above.
|
||||
* `world.spawnEntity(x,y,x,entity_type_id)`
|
||||
* Description: Spawn the specified entity at the given position.
|
||||
* Output: `entity_id`
|
||||
* `world.getEntityTypes()`
|
||||
* Description: Retrieve all known entity types.
|
||||
* Description: Retrieve all spawnable entity types.
|
||||
* Output: List of `entity_type_id,entity_type_name`
|
||||
* `world.setSign(x,y,z,id,data[,{line_1}][,{line_2}][,{line_3}][,{line_4}])`
|
||||
* Description: Set the specified block at the given location. If the block is a sign, then also set its contents.
|
||||
* `entity.getName(entity_id)`
|
||||
* Description: Retrieve the name of the specified entity.
|
||||
* Description: Retrieve the name of the specified entity. For players, this will be their username.
|
||||
* Output: `{entity_name}`
|
||||
* `entity.setDirection(entity_id,:x:,:y:,:z:)`
|
||||
* Description: Set the specified entity's rotation using a unit vector.
|
||||
@ -128,10 +128,10 @@ By default, MCPI-Reborn runs in a "compatibility mode." This makes it completely
|
||||
* `entity.getPitch(entity_id)`
|
||||
* Description: Retrieve the specified entity's pitch.
|
||||
* Output: `:pitch:`
|
||||
* `entity.setAbsPos(entity_id,:x:,:y:,:z:)`[^2]
|
||||
* Description: Move the specified entity to the given absolute[^3] position.
|
||||
* `entity.getAbsPos(entity_id)`[^2]
|
||||
* Description: Retrieve the given entity's absolute[^3] position.
|
||||
* `entity.setAbsPos(entity_id,:x:,:y:,:z:)`[^3]
|
||||
* Description: Move the specified entity to the given absolute[^4] position.
|
||||
* `entity.getAbsPos(entity_id)`[^3]
|
||||
* Description: Retrieve the given entity's absolute[^4] position.
|
||||
* Output: `:x:,:y:,:z:`
|
||||
* `entity.events.block.hits(entity_id)`
|
||||
* Description: Retrieve all queued block hit events produced by the specified entity.
|
||||
@ -163,9 +163,10 @@ By default, MCPI-Reborn runs in a "compatibility mode." This makes it completely
|
||||
* Description: Retrieve the text of the given sign.
|
||||
* Output: List of `{line}`
|
||||
* `entity.getType(entity_id)`
|
||||
* Description: Check the type of the given entity.
|
||||
* Description: Check the type of the given entity. For special entities like players, this will be `0`.
|
||||
* Output: `entity_type_id`
|
||||
|
||||
[^1]: If the ID is `-1`, it will match all entities.
|
||||
[^2]: RaspberryJuice only implements the `player.*` versions of these commands.
|
||||
[^3]: The API normally applies an offset to all coordinates, these commands use the raw data.
|
||||
[^1]: These commands will never match players.
|
||||
[^2]: If the ID is `-1`, it will match all entities.
|
||||
[^3]: RaspberryJuice only implements the `player.*` versions of these commands.
|
||||
[^4]: The API normally applies an offset to all coordinates, these commands use the raw data.
|
@ -102,6 +102,7 @@ add_library(mods SHARED
|
||||
# api
|
||||
src/api/api.cpp
|
||||
src/api/events.cpp
|
||||
src/api/compat.cpp
|
||||
# shading
|
||||
src/shading/init.cpp
|
||||
src/shading/tesselator.cpp
|
||||
|
@ -1,13 +1,8 @@
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
#include <libreborn/util/string.h>
|
||||
#include <libreborn/patch.h>
|
||||
#include <libreborn/config.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/api/api.h>
|
||||
#include <mods/init/init.h>
|
||||
@ -16,62 +11,6 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
// Compatibility Mode
|
||||
bool api_compat_mode = true;
|
||||
|
||||
// Read String Input
|
||||
static std::string get_input(std::string message) {
|
||||
// Decode
|
||||
if (!api_compat_mode) {
|
||||
message = misc_base64_decode(message);
|
||||
}
|
||||
// Convert To CP-437
|
||||
return to_cp437(message);
|
||||
}
|
||||
// Output String
|
||||
std::string api_get_output(std::string message, const bool replace_comma) {
|
||||
// Convert To Unicode
|
||||
message = from_cp437(message);
|
||||
// Escape Characters
|
||||
if (api_compat_mode) {
|
||||
// Output In Plaintext For RJ Compatibility
|
||||
std::ranges::replace(message, list_separator, '\\');
|
||||
if (replace_comma) {
|
||||
std::ranges::replace(message, arg_separator, '.');
|
||||
}
|
||||
} else {
|
||||
// Encode
|
||||
message = misc_base64_encode(message);
|
||||
}
|
||||
// Return
|
||||
return message;
|
||||
}
|
||||
|
||||
// Join Strings Into Output
|
||||
std::string api_join_outputs(const std::vector<std::string> &pieces, const char separator) {
|
||||
// Join
|
||||
std::string out;
|
||||
for (std::string piece : pieces) {
|
||||
// Check
|
||||
if (piece.find(separator) != std::string::npos) {
|
||||
// This Should Be Escapes
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Remove Trailing Newline
|
||||
if (!piece.empty() && piece.back() == '\n') {
|
||||
piece.pop_back();
|
||||
}
|
||||
// Add
|
||||
out += piece + separator;
|
||||
}
|
||||
// Remove Hanging Comma
|
||||
if (!out.empty()) {
|
||||
out.pop_back();
|
||||
}
|
||||
// Return
|
||||
return out + '\n';
|
||||
}
|
||||
|
||||
// Get Blocks In Region
|
||||
static std::string get_blocks(CommandServer *server, const Vec3 &start, const Vec3 &end) {
|
||||
// Start Coordinate
|
||||
@ -180,46 +119,6 @@ static Vec3 get_dir(const Entity *entity) {
|
||||
return Vec3{x, y, z};
|
||||
}
|
||||
|
||||
// Entity Types
|
||||
static std::unordered_map<int, EntityType> modern_entity_id_mapping = {
|
||||
{93, EntityType::CHICKEN},
|
||||
{92, EntityType::COW},
|
||||
{90, EntityType::PIG},
|
||||
{91, EntityType::SHEEP},
|
||||
{54, EntityType::ZOMBIE},
|
||||
{50, EntityType::CREEPER},
|
||||
{51, EntityType::SKELETON},
|
||||
{52, EntityType::SPIDER},
|
||||
{57, EntityType::ZOMBIE_PIGMAN},
|
||||
{1, EntityType::DROPPED_ITEM},
|
||||
{20, EntityType::PRIMED_TNT},
|
||||
{21, EntityType::FALLING_SAND},
|
||||
{10, EntityType::ARROW},
|
||||
{11, EntityType::THROWN_SNOWBALL},
|
||||
{7, EntityType::THROWN_EGG},
|
||||
{9, EntityType::PAINTING}
|
||||
};
|
||||
void api_convert_to_outside_entity_type(int &type) {
|
||||
if (!api_compat_mode) {
|
||||
return;
|
||||
}
|
||||
// Convert To RJ-Compatible Entity Type
|
||||
for (const std::pair<const int, EntityType> &pair : modern_entity_id_mapping) {
|
||||
if (static_cast<int>(pair.second) == type) {
|
||||
type = pair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
void api_convert_to_mcpi_entity_type(int &type) {
|
||||
if (!api_compat_mode) {
|
||||
return;
|
||||
}
|
||||
// Convert To Native Entity Type
|
||||
if (modern_entity_id_mapping.contains(type)) {
|
||||
type = static_cast<int>(modern_entity_id_mapping[type]);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Entity To String
|
||||
static std::string get_entity_message(CommandServer *server, Entity *entity) {
|
||||
std::vector<std::string> pieces;
|
||||
@ -252,7 +151,7 @@ static float distance_between(const Entity *e1, const Entity *e2) {
|
||||
const float dx = e2->x - e1->x;
|
||||
const float dy = e2->y - e1->y;
|
||||
const float dz = e2->z - e1->z;
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
return std::sqrt((dx * dx) + (dy * dy) + (dz * dz));
|
||||
}
|
||||
|
||||
// Get Sign Tile Entity
|
||||
@ -291,6 +190,7 @@ static const std::string player_namespace = "player.";
|
||||
#define next_int(out) next_number(out, int, std::stoi)
|
||||
#define next_float(out) next_number(out, float, std::stof)
|
||||
std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServer *server, ConnectedClient &client, const std::string &command) {
|
||||
// Parse Command
|
||||
size_t arg_start = command.find('(');
|
||||
if (arg_start == std::string::npos) {
|
||||
return CommandServer::Fail;
|
||||
@ -324,7 +224,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
// Parse
|
||||
next_string(input, true);
|
||||
// Search
|
||||
std::string username = get_input(input);
|
||||
std::string username = api_get_input(input);
|
||||
for (Player *player : server->minecraft->level->players) {
|
||||
if (misc_get_player_username_utf(player) == username) {
|
||||
// Found
|
||||
@ -402,7 +302,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
// Run
|
||||
std::vector<std::string> result;
|
||||
for (Entity *entity : server->minecraft->level->entities) {
|
||||
if (is_entity_selected(entity, type) && distance_between(src, entity) < dist) {
|
||||
if (is_entity_selected(entity, type) && distance_between(src, entity) <= dist) {
|
||||
result.push_back(get_entity_message(server, entity));
|
||||
}
|
||||
}
|
||||
@ -419,7 +319,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
// Run
|
||||
int removed = 0;
|
||||
for (Entity *entity : server->minecraft->level->entities) {
|
||||
if (is_entity_selected(entity, type) && distance_between(src, entity) < dist) {
|
||||
if (is_entity_selected(entity, type) && distance_between(src, entity) <= dist) {
|
||||
entity->remove();
|
||||
removed++;
|
||||
}
|
||||
@ -554,7 +454,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (sign != nullptr) {
|
||||
#define next_sign_line(i) \
|
||||
next_string(line_##i, false); \
|
||||
sign->lines[i] = get_input(line_##i); \
|
||||
sign->lines[i] = api_get_input(line_##i); \
|
||||
(void) 0
|
||||
next_sign_line(0);
|
||||
next_sign_line(1);
|
||||
|
104
mods/src/api/compat.cpp
Normal file
104
mods/src/api/compat.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <libreborn/util/string.h>
|
||||
#include <libreborn/log.h>
|
||||
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
// Compatibility Mode
|
||||
bool api_compat_mode = true;
|
||||
|
||||
// Read String Input
|
||||
std::string api_get_input(std::string message) {
|
||||
// Decode
|
||||
if (!api_compat_mode) {
|
||||
message = misc_base64_decode(message);
|
||||
}
|
||||
// Convert To CP-437
|
||||
return to_cp437(message);
|
||||
}
|
||||
// Output String
|
||||
std::string api_get_output(std::string message, const bool replace_comma) {
|
||||
// Convert To Unicode
|
||||
message = from_cp437(message);
|
||||
// Escape Characters
|
||||
if (api_compat_mode) {
|
||||
// Output In Plaintext For RJ Compatibility
|
||||
std::ranges::replace(message, list_separator, '\\');
|
||||
if (replace_comma) {
|
||||
std::ranges::replace(message, arg_separator, '.');
|
||||
}
|
||||
} else {
|
||||
// Encode
|
||||
message = misc_base64_encode(message);
|
||||
}
|
||||
// Return
|
||||
return message;
|
||||
}
|
||||
|
||||
// Join Strings Into Output
|
||||
std::string api_join_outputs(const std::vector<std::string> &pieces, const char separator) {
|
||||
// Join
|
||||
std::string out;
|
||||
for (std::string piece : pieces) {
|
||||
// Check
|
||||
if (piece.find(separator) != std::string::npos) {
|
||||
// This Should Be Escapes
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Remove Trailing Newline
|
||||
if (!piece.empty() && piece.back() == '\n') {
|
||||
piece.pop_back();
|
||||
}
|
||||
// Add
|
||||
out += piece + separator;
|
||||
}
|
||||
// Remove Hanging Comma
|
||||
if (!out.empty()) {
|
||||
out.pop_back();
|
||||
}
|
||||
// Return
|
||||
return out + '\n';
|
||||
}
|
||||
|
||||
// Entity Types
|
||||
static std::unordered_map<int, EntityType> modern_entity_id_mapping = {
|
||||
{93, EntityType::CHICKEN},
|
||||
{92, EntityType::COW},
|
||||
{90, EntityType::PIG},
|
||||
{91, EntityType::SHEEP},
|
||||
{54, EntityType::ZOMBIE},
|
||||
{50, EntityType::CREEPER},
|
||||
{51, EntityType::SKELETON},
|
||||
{52, EntityType::SPIDER},
|
||||
{57, EntityType::ZOMBIE_PIGMAN},
|
||||
{1, EntityType::DROPPED_ITEM},
|
||||
{20, EntityType::PRIMED_TNT},
|
||||
{21, EntityType::FALLING_SAND},
|
||||
{10, EntityType::ARROW},
|
||||
{11, EntityType::THROWN_SNOWBALL},
|
||||
{7, EntityType::THROWN_EGG},
|
||||
{9, EntityType::PAINTING}
|
||||
};
|
||||
void api_convert_to_outside_entity_type(int &type) {
|
||||
if (!api_compat_mode) {
|
||||
return;
|
||||
}
|
||||
// Convert To RJ-Compatible Entity Type
|
||||
for (const std::pair<const int, EntityType> &pair : modern_entity_id_mapping) {
|
||||
if (static_cast<int>(pair.second) == type) {
|
||||
type = pair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
void api_convert_to_mcpi_entity_type(int &type) {
|
||||
if (!api_compat_mode) {
|
||||
return;
|
||||
}
|
||||
// Convert To Native Entity Type
|
||||
if (modern_entity_id_mapping.contains(type)) {
|
||||
type = static_cast<int>(modern_entity_id_mapping[type]);
|
||||
}
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#include <optional>
|
||||
|
||||
#include <libreborn/patch.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/chat/chat.h>
|
||||
|
@ -1,11 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
__attribute__((visibility("internal"))) extern bool api_compat_mode;
|
||||
|
||||
static constexpr int no_entity_id = -1;
|
||||
static constexpr char arg_separator = ',';
|
||||
static constexpr char list_separator = '|';
|
||||
static constexpr char arg_separator = ','; // Used For Arguments And Tuples
|
||||
static constexpr char list_separator = '|'; // Used For Lists
|
||||
|
||||
__attribute__((visibility("internal"))) std::string api_get_input(std::string message);
|
||||
__attribute__((visibility("internal"))) std::string api_get_output(std::string message, bool replace_comma);
|
||||
__attribute__((visibility("internal"))) std::string api_join_outputs(const std::vector<std::string> &pieces, char separator);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user