Skip to content

Commit

Permalink
Expand documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Niels-NTG committed Dec 28, 2022
1 parent e534573 commit 1e9c13a
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,24 @@ public BiomesHandler(MinecraftServer mcServer) {
protected void internalHandle(HttpExchange httpExchange) throws IOException {
// query parameters
Map<String, String> queryParams = parseQueryString(httpExchange.getRequestURI().getRawQuery());

// GET: x, y, z positions
int x;
int y;
int z;

// GET: Ranges in the x, y, z directions (can be negative). Defaults to 1.
int dx;
int dy;
int dz;

String dimension;

try {
x = Integer.parseInt(queryParams.getOrDefault("x", "0"));
y = Integer.parseInt(queryParams.getOrDefault("y", "0"));
z = Integer.parseInt(queryParams.getOrDefault("z", "0"));

dx = Integer.parseInt(queryParams.getOrDefault("dx", "1"));
dy = Integer.parseInt(queryParams.getOrDefault("dy", "1"));
dz = Integer.parseInt(queryParams.getOrDefault("dz", "1"));
Expand All @@ -45,15 +51,19 @@ protected void internalHandle(HttpExchange httpExchange) throws IOException {
throw new HandlerBase.HttpException(message, 400);
}

// Check if clients wants a response in a JSON format. If not, return response in plain text.
Headers requestHeaders = httpExchange.getRequestHeaders();
String acceptHeader = getHeader(requestHeaders, "Accept", "*/*");
boolean returnJson = hasJsonTypeInHeader(acceptHeader);

String method = httpExchange.getRequestMethod().toLowerCase();

String responseString;

if (method.equals("get")) {
ServerLevel serverLevel = getServerLevel(dimension);

// Calculate boundaries of area of blocks to gather biome information on.
int xOffset = x + dx;
int xMin = Math.min(x, xOffset);
int xMax = Math.max(x, xOffset);
Expand All @@ -65,7 +75,10 @@ protected void internalHandle(HttpExchange httpExchange) throws IOException {
int zOffset = z + dz;
int zMin = Math.min(z, zOffset);
int zMax = Math.max(z, zOffset);

if (returnJson) {
// Create a JsonArray with JsonObject, each contain a key-value pair for
// the x, y, z position and the namespaced biome name.
JsonArray jsonArray = new JsonArray();
for (int rangeX = xMin; rangeX < xMax; rangeX++) {
for (int rangeY = yMin; rangeY < yMax; rangeY++) {
Expand All @@ -86,6 +99,8 @@ protected void internalHandle(HttpExchange httpExchange) throws IOException {
}
responseString = new Gson().toJson(jsonArray);
} else {
// Create list of \n-separated strings containing the space-separated
// x, y, z position and the namespaced biome name.
ArrayList<String> biomesList = new ArrayList<>();
for (int rangeX = xMin; rangeX < xMax; rangeX++) {
for (int rangeY = yMin; rangeY < yMax; rangeY++) {
Expand All @@ -105,12 +120,13 @@ protected void internalHandle(HttpExchange httpExchange) throws IOException {
throw new HttpException("Method not allowed. Only GET requests are supported.", 405);
}

// Response headers
Headers responseHeaders = httpExchange.getResponseHeaders();
addDefaultHeaders(responseHeaders);
addDefaultResponseHeaders(responseHeaders);
if (returnJson) {
addResponseHeaderContentTypeJson(responseHeaders);
addResponseHeadersContentTypeJson(responseHeaders);
} else {
addResponseHeaderContentTypePlain(requestHeaders);
addResponseHeadersContentTypePlain(responseHeaders);
}

resolveRequest(httpExchange, responseString);
Expand Down
108 changes: 96 additions & 12 deletions src/main/java/com/gdmc/httpinterfacemod/handlers/BlocksHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -58,16 +57,31 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {

// query parameters
Map<String, String> queryParams = parseQueryString(httpExchange.getRequestURI().getRawQuery());

// PUT/GET: x, y, z positions
int x;
int y;
int z;

// GET: Ranges in the x, y, z directions (can be negative). Defaults to 1.
int dx;
int dy;
int dz;
boolean includeData;

// GET: Whether to include block state https://minecraft.fandom.com/wiki/Block_states
boolean includeState;

// GET: Whether to include block entity data https://minecraft.fandom.com/wiki/Chunk_format#Block_entity_format
boolean includeData;

// PUT: Defaults to true. If true, update neighbouring blocks after placement.
boolean doBlockUpdates;

// PUT: Defaults to false. If true, block updates cause item drops after placement.
boolean spawnDrops;

// PUT: Overrides both doBlockUpdates and spawnDrops if set. For more information see #getBlockFlags and
// https://minecraft.fandom.com/wiki/Block_update
int customFlags; // -1 == no custom flags

try {
Expand All @@ -79,11 +93,14 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
dy = Integer.parseInt(queryParams.getOrDefault("dy", "1"));
dz = Integer.parseInt(queryParams.getOrDefault("dz", "1"));

includeData = Boolean.parseBoolean(queryParams.getOrDefault("includeData", "false"));
includeState = Boolean.parseBoolean(queryParams.getOrDefault("includeState", "false"));

includeData = Boolean.parseBoolean(queryParams.getOrDefault("includeData", "false"));

doBlockUpdates = Boolean.parseBoolean(queryParams.getOrDefault("doBlockUpdates", "true"));

spawnDrops = Boolean.parseBoolean(queryParams.getOrDefault("spawnDrops", "false"));

customFlags = Integer.parseInt(queryParams.getOrDefault("customFlags", "-1"), 2);

dimension = queryParams.getOrDefault("dimension", null);
Expand All @@ -92,13 +109,13 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
throw new HttpException(message, 400);
}

// if content type is application/json use that otherwise return text
// Check if clients wants a response in a JSON format. If not, return response in plain text.
Headers requestHeaders = httpExchange.getRequestHeaders();
String acceptHeader = getHeader(requestHeaders, "Accept", "*/*");
boolean returnJson = hasJsonTypeInHeader(acceptHeader);

// construct response
String method = httpExchange.getRequestMethod().toLowerCase();

String responseString;

if (method.equals("put")) {
Expand All @@ -107,9 +124,10 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {

int blockFlags = customFlags >= 0 ? customFlags : getBlockFlags(doBlockUpdates, spawnDrops);

// Create instance of CommandSourceStack to use as a point of origin for any relative positioned blocks.
CommandSourceStack commandSourceStack = cmdSrc.withPosition(new Vec3(x, y, z));

List<String> returnValues = new LinkedList<>();
ArrayList<String> returnValues = new ArrayList<>();

InputStream bodyStream = httpExchange.getRequestBody();

Expand Down Expand Up @@ -203,6 +221,8 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
responseString = String.join("\n", returnValues);
}
} else if (method.equals("get")) {

// Calculate boundaries of area of blocks to gather information on.
int xOffset = x + dx;
int xMin = Math.min(x, xOffset);
int xMax = Math.max(x, xOffset);
Expand All @@ -216,6 +236,9 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
int zMax = Math.max(z, zOffset);

if (returnJson) {
// Create a JsonArray with JsonObject, each contain a key-value pair for
// the x, y, z position, the block ID, the block state (if requested and available)
// and the block entity data (if requested and available).
JsonArray jsonArray = new JsonArray();
for (int rangeX = xMin; rangeX < xMax; rangeX++) {
for (int rangeY = yMin; rangeY < yMax; rangeY++) {
Expand All @@ -239,6 +262,9 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
}
responseString = new Gson().toJson(jsonArray);
} else {
// Create list of \n-separated strings containing the x, y, z position space-separated,
// the block ID, the block state (if requested and available) between square brackets
// and the block entity data (if requested and available) between curly brackets.
ArrayList<String> responseList = new ArrayList<>();
for (int rangeX = xMin; rangeX < xMax; rangeX++) {
for (int rangeY = yMin; rangeY < yMax; rangeY++) {
Expand All @@ -263,11 +289,11 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {

// Response headers
Headers responseHeaders = httpExchange.getResponseHeaders();
addDefaultHeaders(responseHeaders);
addDefaultResponseHeaders(responseHeaders);
if (returnJson) {
addResponseHeaderContentTypeJson(responseHeaders);
addResponseHeadersContentTypeJson(responseHeaders);
} else {
addResponseHeaderContentTypePlain(responseHeaders);
addResponseHeadersContentTypePlain(responseHeaders);
}

resolveRequest(httpExchange, responseString);
Expand All @@ -278,24 +304,55 @@ private BlockState getBlockStateAtPosition(BlockPos pos) {
return serverLevel.getBlockState(pos);
}

/**
* Parse block position x y z.
* Valid values may be any positive or negative integer and can use tilde or caret notation.
* see: <a href="https://minecraft.fandom.com/wiki/Coordinates#Relative_world_coordinates">Relative World Coordinates - Minecraft Wiki</a>
*
* @param s {@code String} which may or may not contain a valid block position coordinate.
* @param commandSourceStack Origin for relative coordinates.
* @return Valid {@link BlockPos}.
* @throws CommandSyntaxException If input string cannot be parsed into a valid {@link BlockPos}.
*/
private static BlockPos getBlockPosFromString(String s, CommandSourceStack commandSourceStack) throws CommandSyntaxException {
return getBlockPosFromString(new StringReader(s), commandSourceStack);
}

/**
* Parse block position x y z.
* Valid values may be any positive or negative integer and can use tilde or caret notation.
* see: <a href="https://minecraft.fandom.com/wiki/Coordinates#Relative_world_coordinates">Relative World Coordinates - Minecraft Wiki</a>
*
* @param blockPosStringReader {@code StringReader} which may or may not contain a valid block position coordinate.
* @param commandSourceStack Origin for relative coordinates.
* @return Valid {@link BlockPos}.
* @throws CommandSyntaxException If input string reader cannot be parsed into a valid {@link BlockPos}.
*/
private static BlockPos getBlockPosFromString(StringReader blockPosStringReader, CommandSourceStack commandSourceStack) throws CommandSyntaxException {
Coordinates coordinates = BlockPosArgument.blockPos().parse(blockPosStringReader);
blockPosStringReader.skip();
return coordinates.getBlockPos(commandSourceStack);
}

/**
* @param json Valid flat {@link JsonObject} of keys with primitive values (Strings, numbers, booleans)
* @return {@code String} which can be parsed by {@link BlockStateParser} and should be the same as the return value of {@link BlockState#toString()} of the {@link BlockState} resulting from that parser.
*/
private static String getBlockStateStringFromJSONObject(JsonObject json) {
LinkedList<String> blockStateList = new LinkedList<>();
ArrayList<String> blockStateList = new ArrayList<>();
for (Map.Entry<String, JsonElement> element : json.entrySet()) {
blockStateList.add(element.getKey() + "=" + element.getValue());
}
return '[' + String.join(",", blockStateList) + ']';
}

/**
* @param pos Position in the world the block should be placed.
* @param blockState Contains both the state as well as the material of the block.
* @param blockEntityData Optional tag of NBT data to be associated with the block (eg. contents of a chest).
* @param flags Block placement flags (see {@link #getBlockFlags(boolean, boolean)} and {@link Block} for more information).
* @return return 1 if block has been placed or 0 if it couldn't be placed at the given location.
*/
private int setBlock(BlockPos pos, BlockState blockState, CompoundTag blockEntityData, int flags) {
ServerLevel serverLevel = getServerLevel(dimension);

Expand Down Expand Up @@ -326,27 +383,41 @@ private int setBlock(BlockPos pos, BlockState blockState, CompoundTag blockEntit
}
}

/**
* @param pos Position of block in the world.
* @return Namespaced name of the block material.
*/
private String getBlockAsStr(BlockPos pos) {
BlockState bs = getBlockStateAtPosition(pos);
return Objects.requireNonNull(getBlockRegistryName(bs));
}

/**
* @param pos Position of block in the world.
* @return {@link JsonObject} containing the block state data of the block at the given position.
*/
private JsonObject getBlockStateAsJsonObject(BlockPos pos) {
BlockState bs = getBlockStateAtPosition(pos);

JsonObject stateJsonObject = new JsonObject();
bs.getValues().entrySet().stream().map(propertyToStringPairFunction).filter(Objects::nonNull).forEach(pair -> stateJsonObject.add(pair.getKey(), new JsonPrimitive(pair.getValue())));
return stateJsonObject;
}

/**
* @param pos Position of block in the world.
* @return {@link String} containing the block state data of the block at the given position.
*/
private String getBlockStateAsStr(BlockPos pos) {
BlockState bs = getBlockStateAtPosition(pos);

return '[' +
bs.getValues().entrySet().stream().map(propertyToStringFunction).collect(Collectors.joining(",")) +
']';
}

/**
* @param pos Position of block in the world.
* @return {@link JsonObject} containing the block entity data of the block at the given position.
*/
private JsonObject getBlockDataAsJsonObject(BlockPos pos) {
ServerLevel serverLevel = getServerLevel(dimension);
JsonObject dataJsonObject = new JsonObject();
Expand All @@ -362,6 +433,10 @@ private JsonObject getBlockDataAsJsonObject(BlockPos pos) {
return dataJsonObject;
}

/**
* @param pos Position of block in the world.
* @return {@link String} containing the block entity data of the block at the given position.
*/
private String getBlockDataAsStr(BlockPos pos) {
ServerLevel serverLevel = getServerLevel(dimension);
String str = "{}";
Expand All @@ -373,9 +448,18 @@ private String getBlockDataAsStr(BlockPos pos) {
return str;
}

/**
* @param blockState Instance of {@link BlockState} to extract {@link Block} from.
* @return Namespaced name of the block material.
*/
public static String getBlockRegistryName(BlockState blockState) {
return getBlockRegistryName(blockState.getBlock());
}

/**
* @param block Instance of {@link Block} to find in {@link ForgeRegistries#BLOCKS}.
* @return Namespaced name of the block material.
*/
public static String getBlockRegistryName(Block block) {
return Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block)).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ public void internalHandle(HttpExchange httpExchange) throws IOException {
String responseString = new Gson().toJson(buildArea);

Headers responseHeaders = httpExchange.getResponseHeaders();
addDefaultHeaders(responseHeaders);
addResponseHeaderContentTypeJson(responseHeaders);
addDefaultResponseHeaders(responseHeaders);
addResponseHeadersContentTypeJson(responseHeaders);

resolveRequest(httpExchange, responseString);
}
Expand Down
Loading

0 comments on commit 1e9c13a

Please sign in to comment.