Add set/getAbsPos API commands and tweak API

This commit is contained in:
Bigjango13 2024-09-24 21:34:10 -07:00
parent 34b13b3257
commit 55304d1c59
8 changed files with 194 additions and 144 deletions

View File

@ -106,3 +106,4 @@ TRUE Property Scale Animated Textures
TRUE Allow High-Resolution Title TRUE Allow High-Resolution Title
TRUE Improved Classic Title Positioning TRUE Improved Classic Title Positioning
TRUE Use Updated Title TRUE Use Updated Title
TRUE Implement RaspberryJuice API

View File

@ -26,5 +26,8 @@ void misc_run_on_game_key_press(const std::function<bool(Minecraft *, int)> &fun
void misc_run_on_key_press(const std::function<bool(Minecraft *, int)> &func); void misc_run_on_key_press(const std::function<bool(Minecraft *, int)> &func);
void misc_run_on_creative_inventory_setup(const std::function<void(FillingContainer *)> &function); void misc_run_on_creative_inventory_setup(const std::function<void(FillingContainer *)> &function);
void misc_run_on_swap_buffers(const std::function<void()> &function); void misc_run_on_swap_buffers(const std::function<void()> &function);
std::string misc_get_player_username(Player *player);
std::map<int, std::string> &misc_get_entity_names();
std::string misc_get_entity_name(Entity *entity);
static constexpr int line_height = 8; static constexpr int line_height = 8;

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#pragma once
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include "server_properties.h" #include "server_properties.h"
@ -18,5 +16,4 @@ struct ServerCommand {
extern "C" { extern "C" {
std::vector<ServerCommand> *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler); std::vector<ServerCommand> *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler);
ServerProperties &get_server_properties(); ServerProperties &get_server_properties();
std::string get_player_username(Player *player);
} }

View File

@ -4,79 +4,83 @@ This mod implements all of the RaspberryJuice extensions to the MCPI API, for th
This includes: This includes:
- [x] `world.getBlocks(x0: int, y0: int, z0: int, x1: int, y1: int, z1: int) -> int[]` - [x] `world.getBlocks(x0: int, y0: int, z0: int, x1: int, y1: int, z1: int) -> int[]`
- - Gets all the block ids between x0, y0, z0 and x1, y1, z1 - Gets all the block ids between x0, y0, z0 and x1, y1, z1
- [x] `world.getPlayerId(name: str) -> int` - [x] `world.getPlayerId(name: str) -> int`
- - Gets the id of the first player who has the same name as `name`. "Fail" is returned on failure. - Gets the id of the first player who has the same name as `name`. "Fail" is returned on failure.
- [x] `entity.getName(id: int) -> str` - [x] `entity.getName(id: int) -> str`
- - Gets the name of the entity of `id`, as MCPI does not have name tags, it will just be the entity type for non-players - Gets the name of the entity of `id`, as MCPI does not have name tags, it will just be the entity type for non-players
- [x] `world.getEntities(type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]` - [x] `world.getEntities(type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]`
- - returns a list of entities - Returns a list of entities
- [x] `world.removeEntity(id: int) -> int` - [x] `world.removeEntity(id: int) -> int`
- - removes a single entity and returns 1 if successful - Removes a single entity and returns 1 if successful
- [x] `world.removeEntities(type: int) -> int` - [x] `world.removeEntities(type: int) -> int`
- - removes all entities of a type, and returns how many were removed - Removes all entities of a type, and returns how many were removed
- [x] `events.chat.posts() -> {"0", message}[]` - [x] `events.chat.posts() -> {"0", message}[]`
- - gets a list of chat messages, see the limitations section down below to see why it has a zero - Gets a list of chat messages, see the limitations section down below to see why it has a zero
- - The messages are not cleared - The messages are not cleared
- [x] `events.projectile.hits() -> {x: int, y: int, z: int, "1", owner: string, target: int}` - [x] `events.projectile.hits() -> {x: int, y: int, z: int, "1", owner: string, target: int}`
- - Returns a list of projectile hit events, the list is cleared each time it is read by this call - Returns a list of projectile hit events, the list is cleared each time it is read by this call
- - When target id is not 0, it means the projectile hit an entity and `x, y, z` is the entity's position - When target id is not 0, it means the projectile hit an entity and (x, y, z) is the entity's position
- - When target id is 0, it means the projectile hit a block and `x, y, z` is the block's position - When target id is 0, it means the projectile hit a block and (x, y, z) is the block's position
- - Unlike RaspberryJuice, the last argument is the hit entity id, not the entity's name. This shouldn't break anything, and indeed should be more useful. - Unlike RaspberryJuice, the last argument is the hit entity id, not the entity's name. This shouldn't break anything, and indeed should be more useful.
- [x] `player.setDirection(x: float, y: float, z: float)` - [x] `player.setDirection(x: float, y: float, z: float)`
- - sets rotation as if the player was at 0, 0, 0 and looking towards x, y, z - sets rotation as if the player was at 0, 0, 0 and looking towards (x, y, z)
- [x] `entity.setDirection(id: int, x: float, y: float, z: float)` - [x] `entity.setDirection(id: int, x: float, y: float, z: float)`
- - sets rotation as if the entity of `id` was at 0, 0, 0 and looking towards x, y, z - Sets rotation as if the entity of `id` was at 0, 0, 0 and looking towards (x, y, z)
- [x] `player.getDirection() -> {x: float, y: float, z: float}` - [x] `player.getDirection() -> {x: float, y: float, z: float}`
- - gets the location the player would be looking at if they were at 0, 0, 0 - Gets the location the player would be looking at if they were at 0, 0, 0
- [x] `entity.getDirection() -> {x: float, y: float, z: float}` - [x] `entity.getDirection() -> {x: float, y: float, z: float}`
- - gets the location the entity of `id` would be looking at if they were at 0, 0, 0 - Gets the location the entity of `id` would be looking at if they were at 0, 0, 0
- [x] `player.setRotation(id: int)` - [x] `player.setRotation(id: int)`
- - Sets the yaw of the player - Sets the yaw of the player
- [x] `entity.setRotation(id: int)` - [x] `entity.setRotation(id: int)`
- - Sets the yaw of the entity of `id` - Sets the yaw of the entity of `id`
- [x] `player.getRotation` - [x] `player.getRotation`
- - Gets the yaw of the player - Gets the yaw of the player
- [x] `entity.getRotation` - [x] `entity.getRotation`
- - Gets the yaw of the entity of `id` - Gets the yaw of the entity of `id`
- [x] `player.getPitch` - [x] `player.getPitch`
- - Gets the pitch of the player - Gets the pitch of the player
- [x] `entity.getPitch` - [x] `entity.getPitch`
- - Gets the pitch of the entity of `id` - Gets the pitch of the entity of `id`
- [x] `player.setPitch(id: int)` - [x] `player.setPitch(id: int)`
- - Sets the pitch of the player - Sets the pitch of the player
- [x] `entity.setPitch(id: int)` - [x] `entity.setPitch(id: int)`
- - Sets the pitch of the entity of `id` - Sets the pitch of the entity of `id`
- [x] `player.getEntities(dist: int, type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]` - [x] `player.getEntities(dist: int, type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]`
- - Gets all entities within `dist` of the player if the entity is of `type` (if `type` is -1, all entity types are included). - Gets all entities within `dist` of the player if the entity is of `type` (if `type` is -1, all entity types are included).
- - This can include the player. - This can include the player.
- [x] `entity.getEntities(id: int, dist: int, type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]` - [x] `entity.getEntities(id: int, dist: int, type: int) -> {id: int, type: int, name: str, x: float, y: float, z: float}[]`
- - Gets all entities within `dist` of the entity of `id` if the entity is of `type` (if `type` is -1, all entity types are included). - Gets all entities within `dist` of the entity of `id` if the entity is of `type` (if `type` is -1, all entity types are included).
- - This can include the entity. - This can include the entity.
- [x] `player.removeEntities(dist: int, type: int) -> int` - [x] `player.removeEntities(dist: int, type: int) -> int`
- - Removes all entities within `dist` of the player if the entity is of `type` (if `type` is -1, all entity types are included). - Removes all entities within `dist` of the player if the entity is of `type` (if `type` is -1, all entity types are included).
- - This will not include any players. - This will not include any players.
- - It returns the number of entities removed. - It returns the number of entities removed.
- [x] `entity.removeEntities(id: int, dist: int, type: int) -> int` - [x] `entity.removeEntities(id: int, dist: int, type: int) -> int`
- - Removes all entities within `dist` of the entity of `id` if the entity is of `type` (if `type` is -1, all entity types are included). - Removes all entities within `dist` of the entity of `id` if the entity is of `type` (if `type` is -1, all entity types are included).
- - This will not include any players, but may include the entity calling it if the entity is not a player. - This will not include any players, but may include the entity calling it if the entity is not a player.
- - It returns the number of entities removed. - It returns the number of entities removed.
- [x] `world.setSign(x: int, y: int, z: int, id: int, data: int, [l1: str], [l2: str], [l3: str], [l4: str])` - [x] `world.setSign(x: int, y: int, z: int, id: int, data: int, [l1: str], [l2: str], [l3: str], [l4: str])`
- - Sets a block of `id:data` at the specified point, if the block is a sign, it will attempt to set lines 1 through 4 of the sign to the given text - Sets a block of `id:data` at the specified point, if the block is a sign, it will attempt to set lines 1 through 4 of the sign to the given text
- - For the API, the lines must be below 100 characters, however when loading signs MCPI will cap it at 16 characters (this can be disabled by patching out the call at `0xd1e2c`). - For the API, the lines must be below 100 characters, however when loading signs MCPI will cap it at 16 characters (this can be disabled by patching out the call at `0xd1e2c`).
- - The lines are optional - The lines are optional
- - The wiki has a list of blocks: https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Block_List, sign is 63 and wall sign is 68 - The wiki has a list of blocks: https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Block_List, sign is 63 and wall sign is 68
- [x] `world.spawnEntity(x: int, y: int, z: int, type: int) -> int` - [x] `world.spawnEntity(x: int, y: int, z: int, type: int) -> int`
- - Spawns an entity of `type` at the given position - Spawns an entity of `type` at the given position
- - Entities with a type of 0 cannot be spawned - Entities with a type of 0 cannot be spawned
- - The list of entity types can be found by running the command below, or on the wiki: https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Entity_List - The list of entity types can be found by running the command below, or on the wiki: https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Entity_List
- [x] `world.getEntityTypes() -> {type: int, name: str}` - [x] `world.getEntityTypes() -> {type: int, name: str}`
- - Returns a list of known entity types, if there are modded entities this list may be incorrect - Returns a list of known entity types, if there are modded entities this list may be incorrect
- [x] `player.getAbsPos() -> {x: int, y: int, z: int}`
- Gets the absolute position of the player, aka, without passing it through `OffsetPosTranslator`
- [x] `player.setAbsPos(x: int, y: int, z: int)`
- Sets the absolute position of the player, aka, without passing it through `OffsetPosTranslator`
It does not implement (due to MCPI limitations): It does not implement (due to MCPI limitations):
- Per-entity events - Per-entity events
- Per-player events - Per-player events
- `player.getAbsPos`/`player.setAbsPos` as MCPI already does this
- `events.chat.posts`'s id field is always set to -1 - `events.chat.posts`'s id field is always set to -1
- `events.chat.posts` only returns the last 30 messages, and does *not* clear them after each API call - `events.chat.posts` only returns the last 30 messages, and does *not* clear them after each API call

View File

@ -8,6 +8,7 @@
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include <mods/init/init.h> #include <mods/init/init.h>
#include <mods/misc/misc.h>
#include <mods/server/server.h> #include <mods/server/server.h>
#include <mods/feature/feature.h> #include <mods/feature/feature.h>
@ -36,34 +37,7 @@ static std::string getBlocks(CommandServer *commandserver, Vec3 start, Vec3 end)
return ret + "\n"; return ret + "\n";
} }
static std::map<int, std::string> names = { static void setDir(Entity *entity, float x, float y, float z) {
// Unsavables
{0, "Unknown"},
// Animals
{10, "Chicken"}, {11, "Cow"}, {12, "Pig"}, {13, "Sheep"},
// Hostiles
{32, "Zombie"}, {33, "Creeper"}, {34, "Skeleton"}, {35, "Spider"}, {36, "PigZombie"},
// Special 2, projectiles
{80, "Arrow"}, {81, "Snowball"}, {82, "ThrownEgg"},
// Special 1, misc
{64, "ItemEntity"}, {65, "PrimedTnt"}, {66, "FallingTile"}, {83, "Painting"}
};
void setEntityName(int type, std::string name) {
names[type] = name;
}
std::string getEntityName(Entity *entity) {
if (entity == NULL) {
return "";
} else if (entity->isPlayer()) {
return get_player_username((Player *) entity);
} else {
int type = entity->getEntityTypeId();
if (names.find(type) != names.end()) return names[type];
return std::to_string(entity->id);
}
}
void setDir(Entity *entity, float x, float y, float z) {
if (entity == NULL) return; if (entity == NULL) return;
constexpr double _2PI = 2 * M_PI; constexpr double _2PI = 2 * M_PI;
@ -76,7 +50,7 @@ void setDir(Entity *entity, float x, float y, float z) {
float xz = sqrt(x * x + z * z); float xz = sqrt(x * x + z * z);
entity->pitch = (float) atan(-y / xz) * (180.0f / M_PI); entity->pitch = (float) atan(-y / xz) * (180.0f / M_PI);
} }
Vec3 getDir(Entity *entity) { static Vec3 getDir(Entity *entity) {
float y = -sin(entity->pitch * (M_PI / 180)); float y = -sin(entity->pitch * (M_PI / 180));
float xz = cos(entity->pitch * (M_PI / 180)); float xz = cos(entity->pitch * (M_PI / 180));
float x = -xz * sin(entity->yaw * (M_PI / 180)); float x = -xz * sin(entity->yaw * (M_PI / 180));
@ -84,14 +58,14 @@ Vec3 getDir(Entity *entity) {
return Vec3{x, y, z}; return Vec3{x, y, z};
} }
std::string getEntityData(CommandServer *commandserver, Entity *entity) { static std::string getEntityData(CommandServer *commandserver, Entity *entity) {
float x = entity->x, y = entity->y - entity->height_offset, z = entity->z; float x = entity->x, y = entity->y - entity->height_offset, z = entity->z;
commandserver->pos_translator.to(x, y, z); commandserver->pos_translator.to(x, y, z);
return std::to_string(entity->id) + "," + return std::to_string(entity->id) + "," +
// type // type
std::to_string(entity->getEntityTypeId()) + "," + std::to_string(entity->getEntityTypeId()) + "," +
// name // name
getEntityName(entity) + "," + misc_get_entity_name(entity) + "," +
// x // x
std::to_string(x) + "," + std::to_string(x) + "," +
// y // y
@ -100,7 +74,7 @@ std::string getEntityData(CommandServer *commandserver, Entity *entity) {
std::to_string(z); std::to_string(z);
} }
float edist(Entity *e1, Entity *e2) { static float distance_between(Entity *e1, Entity *e2) {
if (e1 == NULL || e2 == NULL) return 0; if (e1 == NULL || e2 == NULL) return 0;
float dx = e2->x - e1->x; float dx = e2->x - e1->x;
float dy = e2->y - e1->y; float dy = e2->y - e1->y;
@ -127,7 +101,7 @@ constexpr size_t EVENT_SIZE = 50;
static int event_at = 0, event_start = 0; static int event_at = 0, event_start = 0;
static ProjectileHitEvent hitEvents[EVENT_SIZE]; static ProjectileHitEvent hitEvents[EVENT_SIZE];
void addProjectile(ProjectileHitEvent event) { static void addProjectile(ProjectileHitEvent event) {
hitEvents[event_at] = event; hitEvents[event_at] = event;
event_at++; event_at++;
event_at %= EVENT_SIZE; event_at %= EVENT_SIZE;
@ -137,7 +111,7 @@ void addProjectile(ProjectileHitEvent event) {
} }
} }
ProjectileHitEvent popProjectile() { static ProjectileHitEvent popProjectile() {
if (event_start == event_at) { if (event_start == event_at) {
ERR("Over popped projectile hit events!"); ERR("Over popped projectile hit events!");
} }
@ -147,31 +121,32 @@ ProjectileHitEvent popProjectile() {
return ret; return ret;
} }
static const std::string fail = "Fail\n";
std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServer *commandserver, ConnectedClient &client, const std::string &command) { std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServer *commandserver, ConnectedClient &client, const std::string &command) {
size_t arg_start = command.find("("); size_t arg_start = command.find("(");
if (arg_start == std::string::npos) return "Fail\n"; if (arg_start == std::string::npos) return fail;
std::string cmd = command.substr(0, arg_start); std::string cmd = command.substr(0, arg_start);
// rfind so ) in input doesn't break // rfind so ) in input doesn't break
size_t cmd_end = command.rfind(")"); size_t cmd_end = command.rfind(")");
if (cmd_end == std::string::npos) return "Fail\n"; if (cmd_end == std::string::npos) return fail;
std::string args = command.substr(arg_start + 1, cmd_end - arg_start - 1); std::string args = command.substr(arg_start + 1, cmd_end - arg_start - 1);
// And now the big if-else chain // And now the big if-else chain
if (cmd == "world.getBlocks") { if (cmd == "world.getBlocks") {
int x0, y0, z0, x1, y1, z1; int x0, y0, z0, x1, y1, z1;
int ret = sscanf(args.c_str(), "%d,%d,%d,%d,%d,%d", &x0, &y0, &z0, &x1, &y1, &z1); int ret = sscanf(args.c_str(), "%d,%d,%d,%d,%d,%d", &x0, &y0, &z0, &x1, &y1, &z1);
if (ret != 6) return "Fail\n"; if (ret != 6) return fail;
// Get the blocks // Get the blocks
return getBlocks(commandserver, Vec3{(float) x0, (float) y0, (float) z0}, Vec3{(float) x1, (float) y1, (float) z1}); return getBlocks(commandserver, Vec3{(float) x0, (float) y0, (float) z0}, Vec3{(float) x1, (float) y1, (float) z1});
} else if (cmd == "world.getPlayerId") { } else if (cmd == "world.getPlayerId") {
for (Player *player : commandserver->minecraft->level->players) { for (Player *player : commandserver->minecraft->level->players) {
if (get_player_username(player) == args) if (misc_get_player_username(player) == args)
return std::to_string(player->id) + "\n"; return std::to_string(player->id) + "\n";
} }
INFO("Player [%s] not found.", args.c_str()); WARN("Player [%s] not found.", args.c_str());
return "Fail\n"; return fail;
} else if (cmd == "entity.getName") { } else if (cmd == "entity.getName") {
int id; int id;
int ret = sscanf(args.c_str(), "%d", &id); int ret = sscanf(args.c_str(), "%d", &id);
@ -179,9 +154,9 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Player (or Entity) [%i] not found in entity.getName.", id); WARN("Player (or Entity) [%i] not found in entity.getName.", id);
} }
return getEntityName(entity) + "\n"; return misc_get_entity_name(entity) + "\n";
} else if (cmd == "world.getEntities") { } else if (cmd == "world.getEntities") {
int type; int type;
int ret = sscanf(args.c_str(), "%d", &type); int ret = sscanf(args.c_str(), "%d", &type);
@ -228,7 +203,6 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
for (GuiMessage gm : commandserver->minecraft->gui.messages) { for (GuiMessage gm : commandserver->minecraft->gui.messages) {
std::string message = gm.message; std::string message = gm.message;
std::replace(message.begin(), message.end(), '|', '\\'); std::replace(message.begin(), message.end(), '|', '\\');
INFO("%s %i", message.c_str(), gm.time);
ret += "0," + message + "|"; ret += "0," + message + "|";
} }
if (ret.size() > 1) ret.pop_back(); if (ret.size() > 1) ret.pop_back();
@ -240,7 +214,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
} }
if (result.size() > 1) result.pop_back(); if (result.size() > 1) result.pop_back();
return result + "\n"; return result + "\n";
} else if (cmd == "player.setDirection") { } else if (cmd == "player.setDirection" && commandserver->minecraft->player) {
float x, y, z; float x, y, z;
int ret = sscanf(args.c_str(), "%f,%f,%f", &x, &y, &z); int ret = sscanf(args.c_str(), "%f,%f,%f", &x, &y, &z);
if (ret != 3) return ""; if (ret != 3) return "";
@ -252,11 +226,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 4) return ""; if (ret != 4) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
} else { } else {
setDir(entity, x, y, z); setDir(entity, x, y, z);
} }
} else if (cmd == "player.getDirection") { } else if (cmd == "player.getDirection" && commandserver->minecraft->player) {
Vec3 vec = getDir((Entity *) commandserver->minecraft->player); Vec3 vec = getDir((Entity *) commandserver->minecraft->player);
return std::to_string(vec.x) + "," + std::to_string(vec.y) + "," + std::to_string(vec.z) + "\n"; return std::to_string(vec.x) + "," + std::to_string(vec.y) + "," + std::to_string(vec.z) + "\n";
} else if (cmd == "entity.getDirection") { } else if (cmd == "entity.getDirection") {
@ -265,13 +239,13 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 1) return ""; if (ret != 1) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
return "Fail\n"; return fail;
} else { } else {
Vec3 vec = getDir(entity); Vec3 vec = getDir(entity);
return std::to_string(vec.x) + "," + std::to_string(vec.y) + "," + std::to_string(vec.z) + "\n"; return std::to_string(vec.x) + "," + std::to_string(vec.y) + "," + std::to_string(vec.z) + "\n";
} }
} else if (cmd == "player.setRotation") { } else if (cmd == "player.setRotation" && commandserver->minecraft->player) {
float yaw; float yaw;
int ret = sscanf(args.c_str(), "%f", &yaw); int ret = sscanf(args.c_str(), "%f", &yaw);
if (ret != 1) return ""; if (ret != 1) return "";
@ -283,11 +257,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 2) return ""; if (ret != 2) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
} else { } else {
entity->yaw = yaw; entity->yaw = yaw;
} }
} else if (cmd == "player.setPitch") { } else if (cmd == "player.setPitch" && commandserver->minecraft->player) {
float pitch; float pitch;
int ret = sscanf(args.c_str(), "%f", &pitch); int ret = sscanf(args.c_str(), "%f", &pitch);
if (ret != 1) return ""; if (ret != 1) return "";
@ -299,11 +273,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 2) return ""; if (ret != 2) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
} else { } else {
entity->pitch = pitch; entity->pitch = pitch;
} }
} else if (cmd == "player.getRotation") { } else if (cmd == "player.getRotation" && commandserver->minecraft->player) {
return std::to_string(commandserver->minecraft->player->yaw) + "\n"; return std::to_string(commandserver->minecraft->player->yaw) + "\n";
} else if (cmd == "entity.getRotation") { } else if (cmd == "entity.getRotation") {
int id; int id;
@ -311,12 +285,12 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 1) return ""; if (ret != 1) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
return "Fail\n"; return fail;
} else { } else {
return std::to_string(entity->yaw) + "\n"; return std::to_string(entity->yaw) + "\n";
} }
} else if (cmd == "player.getPitch") { } else if (cmd == "player.getPitch" && commandserver->minecraft->player) {
return std::to_string(commandserver->minecraft->player->pitch) + "\n"; return std::to_string(commandserver->minecraft->player->pitch) + "\n";
} else if (cmd == "entity.getPitch") { } else if (cmd == "entity.getPitch") {
int id; int id;
@ -324,8 +298,8 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 1) return ""; if (ret != 1) return "";
Entity *entity = commandserver->minecraft->level->getEntity(id); Entity *entity = commandserver->minecraft->level->getEntity(id);
if (entity == NULL) { if (entity == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
return "Fail\n"; return fail;
} else { } else {
return std::to_string(entity->pitch) + "\n"; return std::to_string(entity->pitch) + "\n";
} }
@ -335,7 +309,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
Entity *src = NULL; Entity *src = NULL;
if (cmd == "player.getEntities") { if (cmd == "player.getEntities") {
int ret = sscanf(args.c_str(), "%d,%d", &dist, &type); int ret = sscanf(args.c_str(), "%d,%d", &dist, &type);
if (ret != 2) return ""; if (ret != 2 || commandserver->minecraft->player == NULL) return "";
src = (Entity *) commandserver->minecraft->player; src = (Entity *) commandserver->minecraft->player;
} else { } else {
int id = 0; int id = 0;
@ -343,14 +317,14 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 3) return ""; if (ret != 3) return "";
src = commandserver->minecraft->level->getEntity(id); src = commandserver->minecraft->level->getEntity(id);
if (src == NULL) { if (src == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
return "Fail\n"; return fail;
} }
} }
// Run // Run
std::string result = ""; std::string result = "";
for (Entity *entity : commandserver->minecraft->level->entities) { for (Entity *entity : commandserver->minecraft->level->entities) {
if ((type == -1 || entity->getEntityTypeId() == type) && edist(src, entity) < dist) { if ((type == -1 || entity->getEntityTypeId() == type) && distance_between(src, entity) < dist) {
result += getEntityData(commandserver, entity) + "|"; result += getEntityData(commandserver, entity) + "|";
} }
} }
@ -362,7 +336,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
Entity *src = NULL; Entity *src = NULL;
if (cmd == "player.removeEntities") { if (cmd == "player.removeEntities") {
int ret = sscanf(args.c_str(), "%d,%d", &dist, &type); int ret = sscanf(args.c_str(), "%d,%d", &dist, &type);
if (ret != 2) return ""; if (ret != 2 || commandserver->minecraft->player == NULL) return "";
src = (Entity *) commandserver->minecraft->player; src = (Entity *) commandserver->minecraft->player;
} else { } else {
int id = 0; int id = 0;
@ -370,14 +344,14 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
if (ret != 3) return ""; if (ret != 3) return "";
src = commandserver->minecraft->level->getEntity(id); src = commandserver->minecraft->level->getEntity(id);
if (src == NULL) { if (src == NULL) {
INFO("Entity [%i] not found.", id); WARN("Entity [%i] not found.", id);
return "Fail\n"; return fail;
} }
} }
// Run // Run
int removed = 0; int removed = 0;
for (Entity *entity : commandserver->minecraft->level->entities) { for (Entity *entity : commandserver->minecraft->level->entities) {
if ((type == -1 || entity->getEntityTypeId() == type) && edist(src, entity) < dist && !entity->isPlayer()) { if ((type == -1 || entity->getEntityTypeId() == type) && distance_between(src, entity) < dist && !entity->isPlayer()) {
entity->remove(); entity->remove();
removed++; removed++;
} }
@ -388,7 +362,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
int x, y, z, id, data; int x, y, z, id, data;
char l1[100], l2[100], l3[100], l4[100]; char l1[100], l2[100], l3[100], l4[100];
int ret = sscanf(args.c_str(), "%d,%d,%d,%d,%d,%99[^,],%99[^,],%99[^,],%99s", &x, &y, &z, &id, &data, l1, l2, l3, l4); int ret = sscanf(args.c_str(), "%d,%d,%d,%d,%d,%99[^,],%99[^,],%99[^,],%99s", &x, &y, &z, &id, &data, l1, l2, l3, l4);
if (ret < 5) return "Fail\n"; if (ret < 5) return fail;
// Translate // Translate
commandserver->pos_translator.from(x, y, z); commandserver->pos_translator.from(x, y, z);
// Set block // Set block
@ -406,7 +380,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
float x, y, z; float x, y, z;
int id; int id;
int ret = sscanf(args.c_str(), "%f,%f,%f,%d", &x, &y, &z, &id); int ret = sscanf(args.c_str(), "%f,%f,%f,%d", &x, &y, &z, &id);
if (ret != 4) return "Fail\n"; if (ret != 4) return fail;
// Translate // Translate
int ix = x, iy = y, iz = z; int ix = x, iy = y, iz = z;
int ix1 = x, iy1 = y, iz1 = z; int ix1 = x, iy1 = y, iz1 = z;
@ -421,17 +395,26 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
} else { } else {
entity = EntityFactory::CreateEntity(id, commandserver->minecraft->level); entity = EntityFactory::CreateEntity(id, commandserver->minecraft->level);
} }
if (entity == NULL) return "Fail\n"; if (entity == NULL) return fail;
entity->moveTo(x, y, z, 0, 0); entity->moveTo(x, y, z, 0, 0);
commandserver->minecraft->level->addEntity(entity); commandserver->minecraft->level->addEntity(entity);
return std::to_string(entity->id) + "\n"; return std::to_string(entity->id) + "\n";
} else if (cmd == "world.getEntityTypes") { } else if (cmd == "world.getEntityTypes") {
std::string result = ""; std::string result = "";
for (auto &i : names) { for (auto &i : misc_get_entity_names()) {
result += std::to_string(i.first) + "," + i.second + "|"; result += std::to_string(i.first) + "," + i.second + "|";
} }
if (result.size() > 1) result.pop_back(); if (result.size() > 1) result.pop_back();
return result + "\n"; return result + "\n";
} else if (cmd == "player.setAbsPos" && commandserver->minecraft->player) {
float x, y, z;
int ret = sscanf(args.c_str(), "%f,%f,%f", &x, &y, &z);
if (ret != 3) return fail;
commandserver->minecraft->player->moveTo(x, y, z, commandserver->minecraft->player->yaw, commandserver->minecraft->player->pitch);
} else if (cmd == "player.getAbsPos" && commandserver->minecraft->player) {
return std::to_string(commandserver->minecraft->player->x) + ","
+ std::to_string(commandserver->minecraft->player->y) + ","
+ std::to_string(commandserver->minecraft->player->z) + "\n";
} else { } else {
// Either invalid or a vanilla command, either way hand it off to the orignal handler // Either invalid or a vanilla command, either way hand it off to the orignal handler
return old(commandserver, client, command); return old(commandserver, client, command);
@ -442,21 +425,21 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
// Arrow entity hit // Arrow entity hit
static Entity *shooter = NULL; static Entity *shooter = NULL;
HitResult *Arrow_tick_HitResult_constructor_injection(HitResult *self, Entity *target) { static HitResult *Arrow_tick_HitResult_constructor_injection(HitResult *self, Entity *target) {
// Orignal // Orignal
self->type = 1; self->type = 1;
self->entity = target; self->entity = target;
self->unknown = false; self->unknown = false;
self->x = target->x; self->exact.x = target->x;
self->y = target->y; self->exact.y = target->y;
self->z = target->z; self->exact.z = target->z;
// Add event // Add event
if (shooter && shooter->isPlayer()) { if (shooter && shooter->isPlayer()) {
addProjectile(ProjectileHitEvent{ addProjectile(ProjectileHitEvent{
.x = (int) self->x, .x = (int) target->x,
.y = (int) self->y, .y = (int) target->y,
.z = (int) self->z, .z = (int) target->z,
.owner = get_player_username((Player *) shooter), .owner = misc_get_player_username((Player *) shooter),
.targetId = target->id .targetId = target->id
}); });
} }
@ -464,27 +447,58 @@ HitResult *Arrow_tick_HitResult_constructor_injection(HitResult *self, Entity *t
} }
// Arrow block hit // Arrow block hit
void Arrow_tick_injection(Arrow_tick_t old, Arrow *self) { static void Arrow_tick_injection(Arrow_tick_t old, Arrow *self) {
int oldFlightTime = self->flight_time; int oldFlightTime = self->flight_time;
shooter = self->level->getEntity(self->getAuxData()); shooter = self->level->getEntity(self->getAuxData());
old(self); old(self);
if (self && !self->pending_removal && self->grounded && oldFlightTime != self->flight_time) { if (self && !self->pending_removal && self->grounded && oldFlightTime != self->flight_time) {
if (shooter && shooter->isPlayer()) { if (shooter && shooter->isPlayer()) {
// Hit! Get the data // Hit! Get the data
INFO("B_ADDED");
addProjectile(ProjectileHitEvent{ addProjectile(ProjectileHitEvent{
.x = self->hit_x, .x = self->hit_x,
.y = self->hit_y, .y = self->hit_y,
.z = self->hit_z, .z = self->hit_z,
.owner = get_player_username((Player *) shooter), .owner = misc_get_player_username((Player *) shooter),
.targetId = 0 .targetId = 0
}); });
} }
} }
} }
// Throwable hits
static void Throwable_tick_Throwable_onHit_injection(Throwable *self, HitResult *res) {
if (res == NULL || res->type == 2) return self->onHit(res);
Entity *thrower = self->level->getEntity(self->getAuxData());
if (thrower == NULL || !thrower->isPlayer()) return self->onHit(res);
ProjectileHitEvent event;
if (res->type == 1 && res->entity) {
// Entity
event = ProjectileHitEvent {
.x = (int) res->exact.x,
.y = (int) res->exact.y,
.z = (int) res->exact.z,
.owner = misc_get_player_username((Player *) thrower),
.targetId = res->entity->id
};
} else {
// Tile
event = ProjectileHitEvent {
.x = res->x,
.y = res->y,
.z = res->z,
.owner = misc_get_player_username((Player *) thrower),
.targetId = 0
};
}
addProjectile(event);
self->onHit(res);
}
void init_api() { void init_api() {
if (feature_has("Implement RaspberryJuice API", server_enabled)) {
overwrite_calls(CommandServer_parse, CommandServer_parse_injection); overwrite_calls(CommandServer_parse, CommandServer_parse_injection);
overwrite_calls(Arrow_tick, Arrow_tick_injection); overwrite_calls(Arrow_tick, Arrow_tick_injection);
overwrite_call((void *) 0x8b1e8, (void *) Arrow_tick_HitResult_constructor_injection); overwrite_call((void *) 0x8b1e8, (void *) Arrow_tick_HitResult_constructor_injection);
overwrite_call((void *) 0x8c5a4, (void *) Throwable_tick_Throwable_onHit_injection);
}
} }

View File

@ -4,10 +4,10 @@
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include <mods/init/init.h> #include <mods/init/init.h>
#include <mods/misc/misc.h>
#include <mods/feature/feature.h> #include <mods/feature/feature.h>
// Death Messages // Death Messages
static const char *monster_names[] = {"Zombie", "Creeper", "Skeleton", "Spider", "Zombie Pigman"};
std::string get_death_message(Player *player, Entity *cause, const bool was_shot = false) { std::string get_death_message(Player *player, Entity *cause, const bool was_shot = false) {
// Prepare Death Message // Prepare Death Message
std::string message = player->username; std::string message = player->username;
@ -29,7 +29,7 @@ std::string get_death_message(Player *player, Entity *cause, const bool was_shot
} else if (32 <= type_id && type_id <= 36) { } else if (32 <= type_id && type_id <= 36) {
// Normal monster // Normal monster
message += "a "; message += "a ";
message += monster_names[type_id - 32]; message += misc_get_entity_names()[type_id];
} else { } else {
// Unknown creature // Unknown creature
message += "a mysterious beast"; message += "a mysterious beast";

View File

@ -129,6 +129,45 @@ void misc_render_background(int color, const Minecraft *minecraft, const int x,
t->draw(); t->draw();
} }
// Get Player's Username
std::string misc_get_player_username(Player *player) {
const std::string *username = &player->username;
char *safe_username_c = from_cp437(username->c_str());
std::string safe_username = safe_username_c;
free(safe_username_c);
return safe_username;
}
std::map<int, std::string> &misc_get_entity_names() {
static std::map<int, std::string> entity_names = {
// Unsavables
{0, "Unknown"},
// Animals
{10, "Chicken"}, {11, "Cow"}, {12, "Pig"}, {13, "Sheep"},
// Hostiles
{32, "Zombie"}, {33, "Creeper"}, {34, "Skeleton"}, {35, "Spider"}, {36, "Zombie Pigman"},
// Special 1, misc
{64, "ItemEntity"}, {65, "PrimedTnt"}, {66, "FallingTile"}, {83, "Painting"},
// Special 2, projectiles
{80, "Arrow"}, {81, "Snowball"}, {82, "ThrownEgg"}
};
return entity_names;
};
std::string misc_get_entity_name(Entity *entity) {
if (entity == NULL) {
return "";
} else if (entity->isPlayer()) {
return misc_get_player_username((Player *) entity);
} else {
int type = entity->getEntityTypeId();
std::map<int, std::string> &names = misc_get_entity_names();
if (names.find(type) != names.end()) return names[type];
return std::to_string(entity->id);
}
}
// Init // Init
void _init_misc_api() { void _init_misc_api() {
// Handle Custom Creative Inventory Setup Behavior // Handle Custom Creative Inventory Setup Behavior

View File

@ -111,14 +111,6 @@ static std::string get_blacklist_file() {
static std::vector<Player *> get_players_in_level(Level *level) { static std::vector<Player *> get_players_in_level(Level *level) {
return level->players; return level->players;
} }
// Get Player's Username
std::string get_player_username(Player *player) {
const std::string *username = &player->username;
char *safe_username_c = from_cp437(username->c_str());
std::string safe_username = safe_username_c;
free(safe_username_c);
return safe_username;
}
// Get Level From Minecraft // Get Level From Minecraft
static Level *get_level(const Minecraft *minecraft) { static Level *get_level(const Minecraft *minecraft) {
return minecraft->level; return minecraft->level;
@ -133,7 +125,7 @@ static void find_players(Minecraft *minecraft, const std::string &target_usernam
for (std::size_t i = 0; i < players.size(); i++) { for (std::size_t i = 0; i < players.size(); i++) {
// Iterate Players // Iterate Players
Player *player = players[i]; Player *player = players[i];
std::string username = get_player_username(player); std::string username = misc_get_player_username(player);
if (all_players || username == target_username) { if (all_players || username == target_username) {
// Run Callback // Run Callback
callback(minecraft, username, player); callback(minecraft, username, player);