Add set/getAbsPos API commands and tweak API
This commit is contained in:
parent
34b13b3257
commit
55304d1c59
@ -106,3 +106,4 @@ TRUE Property Scale Animated Textures
|
||||
TRUE Allow High-Resolution Title
|
||||
TRUE Improved Classic Title Positioning
|
||||
TRUE Use Updated Title
|
||||
TRUE Implement RaspberryJuice API
|
@ -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_creative_inventory_setup(const std::function<void(FillingContainer *)> &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;
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include "server_properties.h"
|
||||
@ -18,5 +16,4 @@ struct ServerCommand {
|
||||
extern "C" {
|
||||
std::vector<ServerCommand> *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler);
|
||||
ServerProperties &get_server_properties();
|
||||
std::string get_player_username(Player *player);
|
||||
}
|
@ -4,79 +4,83 @@ This mod implements all of the RaspberryJuice extensions to the MCPI API, for th
|
||||
|
||||
This includes:
|
||||
- [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`
|
||||
- - 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`
|
||||
- - 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}[]`
|
||||
- - returns a list of entities
|
||||
- Returns a list of entities
|
||||
- [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`
|
||||
- - 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}[]`
|
||||
- - gets a list of chat messages, see the limitations section down below to see why it has a zero
|
||||
- - The messages are not cleared
|
||||
- Gets a list of chat messages, see the limitations section down below to see why it has a zero
|
||||
- The messages are not cleared
|
||||
- [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
|
||||
- - 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
|
||||
- - 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.
|
||||
- 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 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.
|
||||
- [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)`
|
||||
- - 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}`
|
||||
- - 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}`
|
||||
- - 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)`
|
||||
- - Sets the yaw of the player
|
||||
- Sets the yaw of the player
|
||||
- [x] `entity.setRotation(id: int)`
|
||||
- - Sets the yaw of the entity of `id`
|
||||
- Sets the yaw of the entity of `id`
|
||||
- [x] `player.getRotation`
|
||||
- - Gets the yaw of the player
|
||||
- Gets the yaw of the player
|
||||
- [x] `entity.getRotation`
|
||||
- - Gets the yaw of the entity of `id`
|
||||
- Gets the yaw of the entity of `id`
|
||||
- [x] `player.getPitch`
|
||||
- - Gets the pitch of the player
|
||||
- Gets the pitch of the player
|
||||
- [x] `entity.getPitch`
|
||||
- - Gets the pitch of the entity of `id`
|
||||
- Gets the pitch of the entity of `id`
|
||||
- [x] `player.setPitch(id: int)`
|
||||
- - Sets the pitch of the player
|
||||
- Sets the pitch of the player
|
||||
- [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}[]`
|
||||
- - 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.
|
||||
- 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.
|
||||
- [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).
|
||||
- - This can include the entity.
|
||||
- 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.
|
||||
- [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).
|
||||
- - This will not include any players.
|
||||
- - It returns the number of entities removed.
|
||||
- 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.
|
||||
- It returns the number of entities removed.
|
||||
- [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).
|
||||
- - 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.
|
||||
- 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.
|
||||
- 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])`
|
||||
- - 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`).
|
||||
- - 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
|
||||
- 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`).
|
||||
- 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
|
||||
- [x] `world.spawnEntity(x: int, y: int, z: int, type: int) -> int`
|
||||
- - Spawns an entity of `type` at the given position
|
||||
- - 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
|
||||
- Spawns an entity of `type` at the given position
|
||||
- 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
|
||||
- [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):
|
||||
- Per-entity 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` only returns the last 30 messages, and does *not* clear them after each API call
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/init/init.h>
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/server/server.h>
|
||||
#include <mods/feature/feature.h>
|
||||
|
||||
@ -36,34 +37,7 @@ static std::string getBlocks(CommandServer *commandserver, Vec3 start, Vec3 end)
|
||||
return ret + "\n";
|
||||
}
|
||||
|
||||
static std::map<int, std::string> names = {
|
||||
// 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) {
|
||||
static void setDir(Entity *entity, float x, float y, float z) {
|
||||
if (entity == NULL) return;
|
||||
|
||||
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);
|
||||
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 xz = cos(entity->pitch * (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};
|
||||
}
|
||||
|
||||
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;
|
||||
commandserver->pos_translator.to(x, y, z);
|
||||
return std::to_string(entity->id) + "," +
|
||||
// type
|
||||
std::to_string(entity->getEntityTypeId()) + "," +
|
||||
// name
|
||||
getEntityName(entity) + "," +
|
||||
misc_get_entity_name(entity) + "," +
|
||||
// x
|
||||
std::to_string(x) + "," +
|
||||
// y
|
||||
@ -100,7 +74,7 @@ std::string getEntityData(CommandServer *commandserver, Entity *entity) {
|
||||
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;
|
||||
float dx = e2->x - e1->x;
|
||||
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 ProjectileHitEvent hitEvents[EVENT_SIZE];
|
||||
|
||||
void addProjectile(ProjectileHitEvent event) {
|
||||
static void addProjectile(ProjectileHitEvent event) {
|
||||
hitEvents[event_at] = event;
|
||||
event_at++;
|
||||
event_at %= EVENT_SIZE;
|
||||
@ -137,7 +111,7 @@ void addProjectile(ProjectileHitEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
ProjectileHitEvent popProjectile() {
|
||||
static ProjectileHitEvent popProjectile() {
|
||||
if (event_start == event_at) {
|
||||
ERR("Over popped projectile hit events!");
|
||||
}
|
||||
@ -147,31 +121,32 @@ ProjectileHitEvent popProjectile() {
|
||||
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) {
|
||||
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);
|
||||
|
||||
// rfind so ) in input doesn't break
|
||||
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);
|
||||
|
||||
// And now the big if-else chain
|
||||
if (cmd == "world.getBlocks") {
|
||||
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);
|
||||
if (ret != 6) return "Fail\n";
|
||||
if (ret != 6) return fail;
|
||||
|
||||
// Get the blocks
|
||||
return getBlocks(commandserver, Vec3{(float) x0, (float) y0, (float) z0}, Vec3{(float) x1, (float) y1, (float) z1});
|
||||
} else if (cmd == "world.getPlayerId") {
|
||||
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";
|
||||
}
|
||||
INFO("Player [%s] not found.", args.c_str());
|
||||
return "Fail\n";
|
||||
WARN("Player [%s] not found.", args.c_str());
|
||||
return fail;
|
||||
} else if (cmd == "entity.getName") {
|
||||
int 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);
|
||||
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") {
|
||||
int 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) {
|
||||
std::string message = gm.message;
|
||||
std::replace(message.begin(), message.end(), '|', '\\');
|
||||
INFO("%s %i", message.c_str(), gm.time);
|
||||
ret += "0," + message + "|";
|
||||
}
|
||||
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();
|
||||
return result + "\n";
|
||||
} else if (cmd == "player.setDirection") {
|
||||
} else if (cmd == "player.setDirection" && commandserver->minecraft->player) {
|
||||
float x, y, z;
|
||||
int ret = sscanf(args.c_str(), "%f,%f,%f", &x, &y, &z);
|
||||
if (ret != 3) return "";
|
||||
@ -252,11 +226,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 4) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
WARN("Entity [%i] not found.", id);
|
||||
} else {
|
||||
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);
|
||||
return std::to_string(vec.x) + "," + std::to_string(vec.y) + "," + std::to_string(vec.z) + "\n";
|
||||
} else if (cmd == "entity.getDirection") {
|
||||
@ -265,13 +239,13 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 1) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
return "Fail\n";
|
||||
WARN("Entity [%i] not found.", id);
|
||||
return fail;
|
||||
} else {
|
||||
Vec3 vec = getDir(entity);
|
||||
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;
|
||||
int ret = sscanf(args.c_str(), "%f", &yaw);
|
||||
if (ret != 1) return "";
|
||||
@ -283,11 +257,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 2) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
WARN("Entity [%i] not found.", id);
|
||||
} else {
|
||||
entity->yaw = yaw;
|
||||
}
|
||||
} else if (cmd == "player.setPitch") {
|
||||
} else if (cmd == "player.setPitch" && commandserver->minecraft->player) {
|
||||
float pitch;
|
||||
int ret = sscanf(args.c_str(), "%f", &pitch);
|
||||
if (ret != 1) return "";
|
||||
@ -299,11 +273,11 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 2) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
WARN("Entity [%i] not found.", id);
|
||||
} else {
|
||||
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";
|
||||
} else if (cmd == "entity.getRotation") {
|
||||
int id;
|
||||
@ -311,12 +285,12 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 1) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
return "Fail\n";
|
||||
WARN("Entity [%i] not found.", id);
|
||||
return fail;
|
||||
} else {
|
||||
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";
|
||||
} else if (cmd == "entity.getPitch") {
|
||||
int id;
|
||||
@ -324,8 +298,8 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 1) return "";
|
||||
Entity *entity = commandserver->minecraft->level->getEntity(id);
|
||||
if (entity == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
return "Fail\n";
|
||||
WARN("Entity [%i] not found.", id);
|
||||
return fail;
|
||||
} else {
|
||||
return std::to_string(entity->pitch) + "\n";
|
||||
}
|
||||
@ -335,7 +309,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
Entity *src = NULL;
|
||||
if (cmd == "player.getEntities") {
|
||||
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;
|
||||
} else {
|
||||
int id = 0;
|
||||
@ -343,14 +317,14 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 3) return "";
|
||||
src = commandserver->minecraft->level->getEntity(id);
|
||||
if (src == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
return "Fail\n";
|
||||
WARN("Entity [%i] not found.", id);
|
||||
return fail;
|
||||
}
|
||||
}
|
||||
// Run
|
||||
std::string result = "";
|
||||
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) + "|";
|
||||
}
|
||||
}
|
||||
@ -362,7 +336,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
Entity *src = NULL;
|
||||
if (cmd == "player.removeEntities") {
|
||||
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;
|
||||
} else {
|
||||
int id = 0;
|
||||
@ -370,14 +344,14 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
if (ret != 3) return "";
|
||||
src = commandserver->minecraft->level->getEntity(id);
|
||||
if (src == NULL) {
|
||||
INFO("Entity [%i] not found.", id);
|
||||
return "Fail\n";
|
||||
WARN("Entity [%i] not found.", id);
|
||||
return fail;
|
||||
}
|
||||
}
|
||||
// Run
|
||||
int removed = 0;
|
||||
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();
|
||||
removed++;
|
||||
}
|
||||
@ -388,7 +362,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
int x, y, z, id, data;
|
||||
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);
|
||||
if (ret < 5) return "Fail\n";
|
||||
if (ret < 5) return fail;
|
||||
// Translate
|
||||
commandserver->pos_translator.from(x, y, z);
|
||||
// Set block
|
||||
@ -406,7 +380,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
float x, y, z;
|
||||
int 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
|
||||
int ix = x, iy = y, iz = z;
|
||||
int ix1 = x, iy1 = y, iz1 = z;
|
||||
@ -421,17 +395,26 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
} else {
|
||||
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);
|
||||
commandserver->minecraft->level->addEntity(entity);
|
||||
return std::to_string(entity->id) + "\n";
|
||||
} else if (cmd == "world.getEntityTypes") {
|
||||
std::string result = "";
|
||||
for (auto &i : names) {
|
||||
for (auto &i : misc_get_entity_names()) {
|
||||
result += std::to_string(i.first) + "," + i.second + "|";
|
||||
}
|
||||
if (result.size() > 1) result.pop_back();
|
||||
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 {
|
||||
// Either invalid or a vanilla command, either way hand it off to the orignal handler
|
||||
return old(commandserver, client, command);
|
||||
@ -442,21 +425,21 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ
|
||||
|
||||
// Arrow entity hit
|
||||
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
|
||||
self->type = 1;
|
||||
self->entity = target;
|
||||
self->unknown = false;
|
||||
self->x = target->x;
|
||||
self->y = target->y;
|
||||
self->z = target->z;
|
||||
self->exact.x = target->x;
|
||||
self->exact.y = target->y;
|
||||
self->exact.z = target->z;
|
||||
// Add event
|
||||
if (shooter && shooter->isPlayer()) {
|
||||
addProjectile(ProjectileHitEvent{
|
||||
.x = (int) self->x,
|
||||
.y = (int) self->y,
|
||||
.z = (int) self->z,
|
||||
.owner = get_player_username((Player *) shooter),
|
||||
.x = (int) target->x,
|
||||
.y = (int) target->y,
|
||||
.z = (int) target->z,
|
||||
.owner = misc_get_player_username((Player *) shooter),
|
||||
.targetId = target->id
|
||||
});
|
||||
}
|
||||
@ -464,27 +447,58 @@ HitResult *Arrow_tick_HitResult_constructor_injection(HitResult *self, Entity *t
|
||||
}
|
||||
|
||||
// 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;
|
||||
shooter = self->level->getEntity(self->getAuxData());
|
||||
old(self);
|
||||
if (self && !self->pending_removal && self->grounded && oldFlightTime != self->flight_time) {
|
||||
if (shooter && shooter->isPlayer()) {
|
||||
// Hit! Get the data
|
||||
INFO("B_ADDED");
|
||||
addProjectile(ProjectileHitEvent{
|
||||
.x = self->hit_x,
|
||||
.y = self->hit_y,
|
||||
.z = self->hit_z,
|
||||
.owner = get_player_username((Player *) shooter),
|
||||
.owner = misc_get_player_username((Player *) shooter),
|
||||
.targetId = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_api() {
|
||||
overwrite_calls(CommandServer_parse, CommandServer_parse_injection);
|
||||
overwrite_calls(Arrow_tick, Arrow_tick_injection);
|
||||
overwrite_call((void *) 0x8b1e8, (void *) Arrow_tick_HitResult_constructor_injection);
|
||||
// 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() {
|
||||
if (feature_has("Implement RaspberryJuice API", server_enabled)) {
|
||||
overwrite_calls(CommandServer_parse, CommandServer_parse_injection);
|
||||
overwrite_calls(Arrow_tick, Arrow_tick_injection);
|
||||
overwrite_call((void *) 0x8b1e8, (void *) Arrow_tick_HitResult_constructor_injection);
|
||||
overwrite_call((void *) 0x8c5a4, (void *) Throwable_tick_Throwable_onHit_injection);
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/init/init.h>
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/feature/feature.h>
|
||||
|
||||
// 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) {
|
||||
// Prepare Death Message
|
||||
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) {
|
||||
// Normal monster
|
||||
message += "a ";
|
||||
message += monster_names[type_id - 32];
|
||||
message += misc_get_entity_names()[type_id];
|
||||
} else {
|
||||
// Unknown creature
|
||||
message += "a mysterious beast";
|
||||
|
@ -129,6 +129,45 @@ void misc_render_background(int color, const Minecraft *minecraft, const int x,
|
||||
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
|
||||
void _init_misc_api() {
|
||||
// Handle Custom Creative Inventory Setup Behavior
|
||||
|
@ -111,14 +111,6 @@ static std::string get_blacklist_file() {
|
||||
static std::vector<Player *> get_players_in_level(Level *level) {
|
||||
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
|
||||
static Level *get_level(const Minecraft *minecraft) {
|
||||
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++) {
|
||||
// Iterate Players
|
||||
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) {
|
||||
// Run Callback
|
||||
callback(minecraft, username, player);
|
||||
|
Loading…
Reference in New Issue
Block a user