minecraft: query and parse player positions

This commit is contained in:
2026-06-12 02:22:26 +09:00
parent de777030b0
commit 20171830ea
4 changed files with 152 additions and 9 deletions
+28 -9
View File
@@ -1,8 +1,13 @@
/*
* main.c - Main entry point for the wamf executable.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "rcon.h"
#include "minecraft.h"
const char *LOCALHOST = "127.0.0.1";
@@ -42,17 +47,31 @@ int main(void) {
exit(EXIT_FAILURE);
}
const char *get_player_positions_cmd = "execute as @a run data get entity @s Pos";
printf("\nexecuting command: %s\n", get_player_positions_cmd);
char *response = rcon_command_multipacket(sockfd, get_player_positions_cmd);
if (response) {
printf("\n=== player positions ===\n");
printf("%s\n", response);
} else {
fprintf(stderr, "failed to get player positions\n");
player_entity_t* entities = malloc(sizeof(player_entity_t) * 20);
if (!entities) {
perror("malloc failed");
close(sockfd);
exit(EXIT_FAILURE);
}
if (query_player_entities(sockfd, 20, entities) < 0) {
fprintf(stderr, "failed to query player entities\n");
free(entities);
close(sockfd);
exit(EXIT_FAILURE);
}
printf("\n=== player positions ===\n");
for (size_t i = 0; i < 20 && entities[i].name != NULL; i++) {
printf("%s: (%.2f, %.2f, %.2f)\n", entities[i].name, entities[i].x, entities[i].y, entities[i].z);
}
for (size_t i = 0; i < 20; i++) {
free_player_entity(&entities[i]);
}
free(entities);
close(sockfd);
return 0;
}
+103
View File
@@ -0,0 +1,103 @@
/*
* minecraft.c - Minecraft specific RCON client implementation
*
* This file implements some Minecraft-specific RCON commands and utilities,
* such as parsing player position data.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "minecraft.h"
#include "rcon.h"
void free_player_entity(player_entity_t *entity) {
if (entity->name) {
free(entity->name);
entity->name = NULL;
}
}
// Parses lines of of the format:
// <user> has the following entity data: [-1234.1234567891234d, 71.0d,
// 113.0000000000001d]
int parse_player_entity(const char *response, player_entity_t *entity) {
const char *prefix = " has the following entity data: [";
char *prefix_pos = strstr(response, prefix);
if (!prefix_pos) {
fprintf(stderr, "invalid response format: missing prefix\n");
return -1;
}
size_t name_len = prefix_pos - response;
entity->name = malloc(name_len + 1);
if (!entity->name) {
perror("malloc failed");
return -1;
}
strncpy(entity->name, response, name_len);
entity->name[name_len] = '\0';
const char *coords_start = prefix_pos + strlen(prefix);
const char *coords_end = strchr(coords_start, ']');
if (!coords_end) {
fprintf(stderr, "invalid response format: missing closing bracket\n");
free(entity->name);
return -1;
}
char coords_str[256];
size_t coords_len = coords_end - coords_start;
if (coords_len >= sizeof(coords_str)) {
fprintf(stderr, "coordinates string too long\n");
free(entity->name);
return -1;
}
strncpy(coords_str, coords_start, coords_len);
coords_str[coords_len] = '\0';
if (sscanf(coords_str, "%lfd, %lfd, %lfd", &entity->x, &entity->y,
&entity->z) != 3) {
fprintf(stderr, "invalid coordinates format\n");
free(entity->name);
return -1;
}
return 0;
}
int query_player_entities(int sockfd, size_t max_entities,
player_entity_t *entities) {
char *response = rcon_command_multipacket(
sockfd, "execute as @a run data get entity @s Pos");
if (!response) {
fprintf(stderr, "failed to execute command\n");
return -1;
}
size_t entity_count = 0;
for (size_t i = 0; i < max_entities; i++) {
char *line = strtok(response, "\n");
if (!line)
break;
printf("parsing line: '%s'\n", line);
if (parse_player_entity(line, &entities[entity_count]) == 0) {
entity_count++;
} else {
fprintf(stderr, "failed to parse player entity from line: %s\n", line);
}
};
if (entity_count == max_entities) {
fprintf(
stderr,
"warning: more player entities in response than provided space for\n");
}
// WARNING: response is not malloced :skull: - don't free it!
// free(response);
return (int)entity_count;
}
+15
View File
@@ -0,0 +1,15 @@
#include <stddef.h>
typedef struct {
char *name;
double x;
double y;
double z;
} player_entity_t;
void free_player_entity(player_entity_t *entity);
int parse_player_entity(const char *response, player_entity_t *entity);
int query_player_entities(int sockfd, size_t entities_size,
player_entity_t *entities);
+6
View File
@@ -1,3 +1,9 @@
/*
* rcon.c - RCON client implementation
*
* This file implements some basic functions for communicating with arbitrary RCON servers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>