diff --git a/README.md b/README.md
index c405a0e40d..729763545c 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[
](https://discord.swofty.net)
-A 26.1.2 Minestom-based recreation of Hypixel SkyBlock with a properly abstracted, scalable microservices architecture.
+A 26.2 Minestom-based recreation of Hypixel with a properly abstracted, scalable microservices architecture.
> **Note**: This implementation is under active development and is not yet production-ready.
diff --git a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/commands/ChunkExporterCommand.java b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/commands/ChunkExporterCommand.java
index 31be3312bc..9d1df190ff 100644
--- a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/commands/ChunkExporterCommand.java
+++ b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/commands/ChunkExporterCommand.java
@@ -19,6 +19,8 @@ public static void register() {
.executes(context -> start(context, ChunkExportRecorder.CaptureMode.CHUNKS))
.then(ClientCommands.literal("block_displays")
.executes(context -> start(context, ChunkExportRecorder.CaptureMode.BLOCK_DISPLAYS)))
+ .then(ClientCommands.literal("bedwars")
+ .executes(context -> start(context, ChunkExportRecorder.CaptureMode.BEDWARS)))
.then(ClientCommands.literal("ravengard")
.then(ClientCommands.argument("name", StringArgumentType.string())
.executes(context -> startStitchedRavengard(context,
diff --git a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/KeybindRegistry.java b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/KeybindRegistry.java
index a2a4b9545b..69cd3360a1 100644
--- a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/KeybindRegistry.java
+++ b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/KeybindRegistry.java
@@ -12,6 +12,7 @@ public final class KeybindRegistry {
public static KeyMapping copyLoreKey;
public static KeyMapping copyChatKey;
public static KeyMapping copyGuiKey;
+ public static KeyMapping copyCurrentGuiKey;
public static KeyMapping entityPacketInspectorKey;
private static boolean chatCopyPressed = false;
@@ -25,6 +26,12 @@ public static void register() {
KeyMapping.Category.MISC
));
+ copyCurrentGuiKey = KeyMappingHelper.registerKeyMapping(new KeyMapping(
+ "key.thehypixelrecreationmod.copycurrentgui",
+ GLFW.GLFW_KEY_PAGE_DOWN,
+ KeyMapping.Category.MISC
+ ));
+
copyLoreKey = KeyMappingHelper.registerKeyMapping(new KeyMapping(
"key.thehypixelrecreationmod.copylore",
GLFW.GLFW_KEY_L,
@@ -62,6 +69,10 @@ public static void register() {
GuiCaptureRecorder.toggle(client);
return false;
}
+ if (copyCurrentGuiKey.matches(key)) {
+ CopyCurrentGui.copyCurrentGui(client);
+ return false;
+ }
return true;
});
});
diff --git a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/worldexport/ChunkExportRecorder.java b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/worldexport/ChunkExportRecorder.java
index cb529d66d5..65f41adb25 100644
--- a/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/worldexport/ChunkExportRecorder.java
+++ b/clientmod/src/main/java/gg/itzkatze/thehypixelrecreationmod/features/worldexport/ChunkExportRecorder.java
@@ -1,8 +1,8 @@
package gg.itzkatze.thehypixelrecreationmod.features.worldexport;
-import gg.itzkatze.thehypixelrecreationmod.utils.PolarConvert;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import gg.itzkatze.thehypixelrecreationmod.utils.PolarConvert;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.nbt.CompoundTag;
@@ -12,6 +12,7 @@
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Display;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.level.storage.TagValueOutput;
import java.io.IOException;
@@ -30,6 +31,7 @@ public final class ChunkExportRecorder {
private static final Map RECORDED_BLOCK_DISPLAYS = new LinkedHashMap<>();
private static final Map RECORDED_RAVENGARD_OBJECTS = new LinkedHashMap<>();
private static final Set MOVING_ENTITIES = new HashSet<>();
+ private static final Map RECORDED_SPRAY_POSITIONS = new LinkedHashMap<>();
private static LoadedChunkExporter.SessionContext sessionContext;
private static Instant startedAt;
@@ -61,6 +63,7 @@ public static StartResult start(CaptureMode mode, String sessionName) {
RECORDED_BLOCK_DISPLAYS.clear();
RECORDED_RAVENGARD_OBJECTS.clear();
MOVING_ENTITIES.clear();
+ RECORDED_SPRAY_POSITIONS.clear();
captureMode = mode;
stitchedSessionName = sessionName == null ? null : LoadedChunkExporter.sanitizeSessionName(sessionName);
try {
@@ -107,6 +110,9 @@ public static StopResult stop(String sessionName) throws IOException {
if (captureMode == CaptureMode.RAVENGARD) {
writeRavengardConfiguration(polarResult.path(), RECORDED_RAVENGARD_OBJECTS.values());
}
+ if (captureMode == CaptureMode.BEDWARS) {
+ writeBedWarsConfiguration(polarResult.path());
+ }
if (stitchedSessionName != null) saveCheckpoint(stitchedSessionName);
clearSession();
return new StopResult(
@@ -171,6 +177,15 @@ private static void captureCurrentWorld(ClientLevel level, boolean requireMatchi
if (captureMode == CaptureMode.BLOCK_DISPLAYS || captureMode == CaptureMode.RAVENGARD) {
captureBlockDisplays(level);
}
+ if (captureMode == CaptureMode.BEDWARS) captureSprayPositions(level);
+ }
+ }
+
+ private static void captureSprayPositions(ClientLevel level) {
+ for (Entity entity : level.entitiesForRendering()) {
+ if (!(entity instanceof ItemFrame frame)) continue;
+ RECORDED_SPRAY_POSITIONS.put(frame.getUUID(), new BedWarsSprayPosition(
+ frame.getBlockX(), frame.getBlockY(), frame.getBlockZ(), frame.getDirection().getName()));
}
}
@@ -226,6 +241,7 @@ private static void clearSession() {
RECORDED_BLOCK_DISPLAYS.clear();
RECORDED_RAVENGARD_OBJECTS.clear();
MOVING_ENTITIES.clear();
+ RECORDED_SPRAY_POSITIONS.clear();
sessionContext = null;
startedAt = null;
ticksUntilCapture = 0;
@@ -252,6 +268,13 @@ private static void writeRavengardConfiguration(Path polarPath, Collection teams;
private MapLocations locations;
private Map globalGenerator;
+ private List sprays;
@Getter
@Setter
public static class MapLocations {
private HypixelPosition waiting;
private HypixelPosition spectator;
+ private CuboidPosition waitingLobby;
}
@Getter
@@ -61,6 +63,12 @@ public static class GlobalGenerator {
public record TwoBlockPosition(Vec3i feet, Vec3i head) {
}
+ public record CuboidPosition(Vec3i min, Vec3i max) {
+ }
+
+ public record SprayPosition(int x, int y, int z, String facing) {
+ }
+
public record MinMax(double min, double max) {
}
@@ -70,7 +78,7 @@ public enum GlobalGeneratorKey {
public enum TeamKey {
RED("Red", "§c", 0xFF5555, Material.RED_BED, Material.RED_WOOL),
- BLUE("Blue", "§9", 0x5555FF, Material.BLUE_BED, Material.BLUE_BED),
+ BLUE("Blue", "§9", 0x5555FF, Material.BLUE_BED, Material.BLUE_WOOL),
GREEN("Green", "§a", 0x55FF55, Material.LIME_BED, Material.LIME_WOOL),
YELLOW("Yellow", "§e", 0xFFFF55, Material.YELLOW_BED, Material.YELLOW_WOOL),
AQUA("Aqua", "§b", 0x00AAAA, Material.LIGHT_BLUE_BED, Material.LIGHT_BLUE_WOOL),
diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayDataBatchProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayDataBatchProtocolObject.java
index 617ffc0d2c..0fec93f904 100644
--- a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayDataBatchProtocolObject.java
+++ b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayDataBatchProtocolObject.java
@@ -3,6 +3,7 @@
import net.swofty.commons.protocol.JacksonSerializer;
import net.swofty.commons.protocol.RedisProtocol;
import net.swofty.commons.protocol.Serializer;
+import net.swofty.commons.replay.protocol.ReplaySection;
import java.util.UUID;
@@ -22,12 +23,24 @@ public Serializer getReturnSerializer() {
public record BatchMessage(
UUID replayId,
- int batchIndex,
+ ReplaySection section,
+ int sequence,
int startTick,
int endTick,
- int recordableCount,
- byte[] compressedData
- ) {}
+ int uncompressedLength,
+ int recordCount,
+ int checksum,
+ byte[] compressedPayload
+ ) {
+ public BatchMessage {
+ compressedPayload = compressedPayload.clone();
+ }
+
+ @Override
+ public byte[] compressedPayload() {
+ return compressedPayload.clone();
+ }
+ }
public record BatchResponse(boolean success, long bytesReceived) {}
}
diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayLoadProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayLoadProtocolObject.java
index ccbb74d4c2..76cac58b71 100644
--- a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayLoadProtocolObject.java
+++ b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayLoadProtocolObject.java
@@ -1,12 +1,11 @@
package net.swofty.commons.protocol.objects.replay;
-import net.swofty.commons.ServerType;
import net.swofty.commons.protocol.JacksonSerializer;
import net.swofty.commons.protocol.RedisProtocol;
import net.swofty.commons.protocol.Serializer;
+import net.swofty.commons.replay.protocol.ReplayChunk;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
public class ReplayLoadProtocolObject extends RedisProtocol<
@@ -28,38 +27,7 @@ public record LoadRequest(UUID replayId) {}
public record LoadResponse(
boolean success,
String errorMessage,
- ReplayMetadata metadata,
- List dataChunks
- ) {}
-
- public record ReplayMetadata(
- UUID replayId,
- String gameId,
- ServerType serverType,
- String serverId,
- String gameTypeName,
- String mapName,
- String mapHash,
- int version,
- long startTime,
- long endTime,
- int durationTicks,
- Map players,
- Map> teams,
- Map teamInfo,
- String winnerId,
- String winnerType,
- long dataSize,
- double mapCenterX,
- double mapCenterZ
- ) {}
-
- public record TeamInfo(String name, String colorCode, int color) {}
-
- public record DataChunk(
- int chunkIndex,
- int startTick,
- int endTick,
- byte[] compressedData
+ ReplayProtocolDto.Metadata metadata,
+ List chunks
) {}
}
diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayProtocolDto.java b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayProtocolDto.java
new file mode 100644
index 0000000000..8c33987b70
--- /dev/null
+++ b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayProtocolDto.java
@@ -0,0 +1,76 @@
+package net.swofty.commons.protocol.objects.replay;
+
+import net.swofty.commons.ServerType;
+
+import java.util.List;
+import java.util.UUID;
+
+public final class ReplayProtocolDto {
+ private ReplayProtocolDto() {
+ }
+
+ public record Descriptor(
+ UUID replayId,
+ String gameId,
+ String gameType,
+ ServerType serverType,
+ String serverId,
+ String mapName,
+ String mapHash,
+ double mapCenterX,
+ double mapCenterZ,
+ int formatVersion,
+ long startTime,
+ long endTime,
+ int durationTicks,
+ long dataSize
+ ) {
+ }
+
+ public record Participant(
+ UUID uuid,
+ int entityId,
+ String username,
+ String textureValue,
+ String textureSignature,
+ String displayNameJson,
+ String prefixJson,
+ String suffixJson
+ ) {
+ }
+
+ public record GameMetadataEnvelope(String gameType, int schemaVersion, byte[] payload) {
+ public GameMetadataEnvelope {
+ if (gameType == null || gameType.isBlank())
+ throw new IllegalArgumentException("gameType must not be blank");
+ if (schemaVersion < 1) throw new IllegalArgumentException("schemaVersion must be positive");
+ if (payload.length > 16 * 1024 * 1024)
+ throw new IllegalArgumentException("Replay game metadata is too large");
+ payload = payload.clone();
+ }
+
+ @Override
+ public byte[] payload() {
+ return payload.clone();
+ }
+ }
+
+ public record Metadata(Descriptor descriptor, List participants, GameMetadataEnvelope gameMetadata) {
+ public Metadata {
+ if (participants.size() > 10_000)
+ throw new IllegalArgumentException("Replay contains too many participants");
+ participants = List.copyOf(participants);
+ for (Participant participant : participants) {
+ validateComponent(participant.displayNameJson());
+ validateComponent(participant.prefixJson());
+ validateComponent(participant.suffixJson());
+ }
+ }
+
+ private static void validateComponent(String component) {
+ if (component == null || component.length() > 1_048_576) {
+ throw new IllegalArgumentException("Invalid replay component JSON");
+ }
+ }
+ }
+}
diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayStartProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayStartProtocolObject.java
index d3deeee5aa..8468ae0a6d 100644
--- a/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayStartProtocolObject.java
+++ b/commons/src/main/java/net/swofty/commons/protocol/objects/replay/ReplayStartProtocolObject.java
@@ -1,14 +1,9 @@
package net.swofty.commons.protocol.objects.replay;
-import net.swofty.commons.ServerType;
import net.swofty.commons.protocol.JacksonSerializer;
import net.swofty.commons.protocol.RedisProtocol;
import net.swofty.commons.protocol.Serializer;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
public class ReplayStartProtocolObject extends RedisProtocol<
ReplayStartProtocolObject.StartMessage,
ReplayStartProtocolObject.StartResponse> {
@@ -24,22 +19,9 @@ public Serializer getReturnSerializer() {
}
public record StartMessage(
- UUID replayId,
- String gameId,
- ServerType serverType,
- String serverId,
- String gameTypeName,
- String mapName,
- String mapHash,
- long startTime,
- double mapCenterX,
- double mapCenterZ,
- Map players,
- Map> teams,
- Map teamInfo
+ ReplayProtocolDto.Metadata metadata
) {}
public record StartResponse(boolean success, String message) {}
- public record TeamInfo(String name, String colorCode, int color) {}
}
diff --git a/commons/src/main/java/net/swofty/commons/redis/RedisClient.java b/commons/src/main/java/net/swofty/commons/redis/RedisClient.java
index 2489302a8a..3553a46fec 100644
--- a/commons/src/main/java/net/swofty/commons/redis/RedisClient.java
+++ b/commons/src/main/java/net/swofty/commons/redis/RedisClient.java
@@ -2,7 +2,6 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
-
import net.swofty.commons.ServiceType;
import net.swofty.commons.protocol.RedisProtocol;
import net.swofty.commons.protocol.objects.PingProtocol;
diff --git a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayChunk.java b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayChunk.java
new file mode 100644
index 0000000000..4cd2791c34
--- /dev/null
+++ b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayChunk.java
@@ -0,0 +1,46 @@
+package net.swofty.commons.replay.protocol;
+
+import java.util.Arrays;
+
+public record ReplayChunk(
+ ReplaySection section,
+ int sequence,
+ int startTick,
+ int endTick,
+ int uncompressedLength,
+ int recordCount,
+ int checksum,
+ byte[] compressedPayload
+) {
+ public ReplayChunk {
+ if (section == null) throw new IllegalArgumentException("section is required");
+ if (sequence < 0) throw new IllegalArgumentException("sequence must not be negative");
+ if (startTick < 0 || endTick < startTick) throw new IllegalArgumentException("invalid tick range");
+ if (uncompressedLength < 0 || recordCount < 0) throw new IllegalArgumentException("invalid chunk counts");
+ compressedPayload = compressedPayload.clone();
+ }
+
+ @Override
+ public byte[] compressedPayload() {
+ return compressedPayload.clone();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof ReplayChunk chunk
+ && section == chunk.section
+ && sequence == chunk.sequence
+ && startTick == chunk.startTick
+ && endTick == chunk.endTick
+ && uncompressedLength == chunk.uncompressedLength
+ && recordCount == chunk.recordCount
+ && checksum == chunk.checksum
+ && Arrays.equals(compressedPayload, chunk.compressedPayload);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * java.util.Objects.hash(section, sequence, startTick, endTick, uncompressedLength, recordCount, checksum)
+ + Arrays.hashCode(compressedPayload);
+ }
+}
diff --git a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayCompression.java b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayCompression.java
index 79d89db940..a4736d6ec8 100644
--- a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayCompression.java
+++ b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayCompression.java
@@ -10,14 +10,25 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ReplayCompression {
private static final int LEVEL = 3;
+ public static final int DEFAULT_MAX_DECOMPRESSED_BYTES = 64 * 1024 * 1024;
public static byte[] compress(byte[] data) {
return Zstd.compress(data, LEVEL);
}
public static byte[] decompress(byte[] compressedData) throws IOException {
+ return decompress(compressedData, DEFAULT_MAX_DECOMPRESSED_BYTES);
+ }
+
+ public static byte[] decompress(byte[] compressedData, int maxDecompressedBytes) throws IOException {
+ if (compressedData == null || compressedData.length == 0) {
+ throw new IOException("Replay payload is empty");
+ }
+ if (maxDecompressedBytes <= 0) {
+ throw new IllegalArgumentException("maxDecompressedBytes must be positive");
+ }
long size = Zstd.getFrameContentSize(compressedData);
- if (size <= 0 || size > Integer.MAX_VALUE) {
+ if (size <= 0 || size > maxDecompressedBytes) {
throw new IOException("Invalid zstd frame content size: " + size);
}
diff --git a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayDataReader.java b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayDataReader.java
index db35a3fe60..4e02c1f4b6 100644
--- a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayDataReader.java
+++ b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayDataReader.java
@@ -13,6 +13,8 @@
* Counterpart to ReplayDataWriter.
*/
public class ReplayDataReader implements AutoCloseable {
+ public static final int DEFAULT_MAX_STRING_BYTES = 1_048_576;
+ public static final int DEFAULT_MAX_BYTE_ARRAY_BYTES = 16 * 1024 * 1024;
private final DataInputStream in;
public ReplayDataReader(byte[] data) {
@@ -83,7 +85,14 @@ public boolean readBoolean() throws IOException {
* Reads a string with length prefix.
*/
public String readString() throws IOException {
- int length = readVarInt();
+ return readString(DEFAULT_MAX_STRING_BYTES);
+ }
+
+ public String readString(int maxBytes) throws IOException {
+ int length = readLength(maxBytes, "string");
+ if (length > available()) {
+ throw new IOException("Invalid string length: " + length);
+ }
byte[] bytes = new byte[length];
in.readFully(bytes);
return new String(bytes, StandardCharsets.UTF_8);
@@ -106,6 +115,9 @@ public int readVarInt() throws IOException {
int shift = 0;
int b;
do {
+ if (shift >= 35) {
+ throw new IOException("VarInt is too large");
+ }
b = in.readUnsignedByte();
result |= (b & 0x7F) << shift;
shift += 7;
@@ -130,6 +142,9 @@ public long readVarLong() throws IOException {
int shift = 0;
int b;
do {
+ if (shift >= 70) {
+ throw new IOException("VarLong is too large");
+ }
b = in.readUnsignedByte();
result |= (long) (b & 0x7F) << shift;
shift += 7;
@@ -192,6 +207,7 @@ public float[] readCompressedLook() throws IOException {
// Convert back from radians * 160 to degrees
float yaw = (float) (yawBits / 160.0 * 180.0 / Math.PI);
float pitch = (float) (pitchBits / 160.0 * 180.0 / Math.PI);
+ if (pitch > 180.0f) pitch -= 360.0f;
return new float[]{yaw, pitch};
}
@@ -200,7 +216,14 @@ public float[] readCompressedLook() throws IOException {
* Reads a byte array with length prefix.
*/
public byte[] readBytes() throws IOException {
- int length = readVarInt();
+ return readBytes(DEFAULT_MAX_BYTE_ARRAY_BYTES);
+ }
+
+ public byte[] readBytes(int maxBytes) throws IOException {
+ int length = readLength(maxBytes, "byte array");
+ if (length > available()) {
+ throw new IOException("Invalid byte array length: " + length);
+ }
byte[] bytes = new byte[length];
in.readFully(bytes);
return bytes;
@@ -210,6 +233,9 @@ public byte[] readBytes() throws IOException {
* Reads raw bytes.
*/
public byte[] readRawBytes(int length) throws IOException {
+ if (length < 0 || length > available()) {
+ throw new IOException("Invalid raw byte length: " + length);
+ }
byte[] bytes = new byte[length];
in.readFully(bytes);
return bytes;
@@ -236,7 +262,23 @@ public int available() throws IOException {
* Skips bytes.
*/
public void skip(int n) throws IOException {
- in.skipBytes(n);
+ if (n < 0 || n > available()) {
+ throw new IOException("Invalid skip length: " + n);
+ }
+ if (in.skipBytes(n) != n) {
+ throw new IOException("Truncated replay payload");
+ }
+ }
+
+ private int readLength(int maxBytes, String kind) throws IOException {
+ if (maxBytes < 0) {
+ throw new IllegalArgumentException("maxBytes must not be negative");
+ }
+ int length = readVarInt();
+ if (length < 0 || length > maxBytes) {
+ throw new IOException("Invalid " + kind + " length: " + Integer.toUnsignedLong(length));
+ }
+ return length;
}
@Override
diff --git a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayFormat.java b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayFormat.java
new file mode 100644
index 0000000000..f226424ec3
--- /dev/null
+++ b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplayFormat.java
@@ -0,0 +1,127 @@
+package net.swofty.commons.replay.protocol;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.CRC32C;
+
+public final class ReplayFormat {
+ public static final int MAGIC = 0x53575250;
+ public static final int MAJOR_VERSION = 4;
+ public static final int MAX_TICKS = 20 * 60 * 60 * 24;
+ public static final int MAX_RECORDS_PER_CHUNK = 1_000_000;
+ public static final int MAX_ENTRY_BYTES = 16 * 1024 * 1024;
+ public static final int MAX_CHUNK_BYTES = 64 * 1024 * 1024;
+
+ private ReplayFormat() {
+ }
+
+ public static ReplayChunk createChunk(
+ ReplaySection section,
+ int sequence,
+ int startTick,
+ int endTick,
+ List entries
+ ) throws IOException {
+ if (entries.size() > MAX_RECORDS_PER_CHUNK) {
+ throw new IOException("Replay chunk contains too many records: " + entries.size());
+ }
+ ReplayDataWriter writer = new ReplayDataWriter();
+ writer.writeInt(MAGIC);
+ writer.writeVarInt(MAJOR_VERSION);
+ writer.writeByte(section.id());
+ writer.writeVarInt(sequence);
+ writer.writeVarInt(startTick);
+ writer.writeVarInt(endTick);
+ writer.writeVarInt(entries.size());
+ for (byte[] entry : entries) {
+ if (entry.length > MAX_ENTRY_BYTES) {
+ throw new IOException("Replay entry is too large: " + entry.length);
+ }
+ writer.writeBytes(entry);
+ }
+ byte[] payload = writer.toByteArray();
+ if (payload.length > MAX_CHUNK_BYTES) {
+ throw new IOException("Replay chunk is too large: " + payload.length);
+ }
+ return new ReplayChunk(
+ section,
+ sequence,
+ startTick,
+ endTick,
+ payload.length,
+ entries.size(),
+ checksum(payload),
+ ReplayCompression.compress(payload)
+ );
+ }
+
+ public static List readChunk(ReplayChunk chunk) throws IOException {
+ validateHeader(chunk);
+ byte[] payload = ReplayCompression.decompress(chunk.compressedPayload(), MAX_CHUNK_BYTES);
+ if (payload.length != chunk.uncompressedLength()) {
+ throw new IOException("Replay chunk length mismatch for sequence " + chunk.sequence());
+ }
+ if (checksum(payload) != chunk.checksum()) {
+ throw new IOException("Replay chunk checksum mismatch for sequence " + chunk.sequence());
+ }
+ try (ReplayDataReader reader = new ReplayDataReader(payload)) {
+ if (reader.readInt() != MAGIC) throw new IOException("Invalid replay magic");
+ int version = reader.readVarInt();
+ if (version != MAJOR_VERSION) throw new IOException("Unsupported replay format version: " + version);
+ ReplaySection payloadSection;
+ try {
+ payloadSection = ReplaySection.fromId(reader.readUnsignedByte());
+ } catch (IllegalArgumentException exception) {
+ throw new IOException(exception.getMessage(), exception);
+ }
+ if (payloadSection != chunk.section()) throw new IOException("Replay section header mismatch");
+ if (reader.readVarInt() != chunk.sequence()) throw new IOException("Replay sequence header mismatch");
+ if (reader.readVarInt() != chunk.startTick() || reader.readVarInt() != chunk.endTick()) {
+ throw new IOException("Replay tick range header mismatch");
+ }
+ int count = reader.readVarInt();
+ if (count != chunk.recordCount() || count > MAX_RECORDS_PER_CHUNK) {
+ throw new IOException("Replay record count mismatch");
+ }
+ List entries = new ArrayList<>(count);
+ for (int index = 0; index < count; index++) {
+ entries.add(reader.readBytes(MAX_ENTRY_BYTES));
+ }
+ if (reader.available() != 0) throw new IOException("Trailing replay chunk data");
+ return List.copyOf(entries);
+ }
+ }
+
+ public static void validateOrdered(List chunks, ReplaySection section) throws IOException {
+ int expectedSequence = 0;
+ int previousEndTick = -1;
+ for (ReplayChunk chunk : chunks.stream().filter(value -> value.section() == section)
+ .sorted(java.util.Comparator.comparingInt(ReplayChunk::sequence)).toList()) {
+ if (chunk.sequence() != expectedSequence++) {
+ throw new IOException("Missing " + section + " replay chunk sequence " + (expectedSequence - 1));
+ }
+ if (chunk.startTick() < previousEndTick) {
+ throw new IOException("Overlapping " + section + " replay chunk at sequence " + chunk.sequence());
+ }
+ readChunk(chunk);
+ previousEndTick = chunk.endTick();
+ }
+ }
+
+ private static void validateHeader(ReplayChunk chunk) throws IOException {
+ if (chunk.startTick() < 0 || chunk.endTick() < chunk.startTick() || chunk.endTick() > MAX_TICKS) {
+ throw new IOException("Invalid replay tick range " + chunk.startTick() + "-" + chunk.endTick());
+ }
+ if (chunk.uncompressedLength() > MAX_CHUNK_BYTES || chunk.recordCount() > MAX_RECORDS_PER_CHUNK
+ || chunk.compressedPayload().length > MAX_CHUNK_BYTES) {
+ throw new IOException("Replay chunk exceeds configured limits");
+ }
+ }
+
+ private static int checksum(byte[] payload) {
+ CRC32C checksum = new CRC32C();
+ checksum.update(payload, 0, payload.length);
+ return (int) checksum.getValue();
+ }
+}
diff --git a/commons/src/main/java/net/swofty/commons/replay/protocol/ReplaySection.java b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplaySection.java
new file mode 100644
index 0000000000..21d0a50829
--- /dev/null
+++ b/commons/src/main/java/net/swofty/commons/replay/protocol/ReplaySection.java
@@ -0,0 +1,26 @@
+package net.swofty.commons.replay.protocol;
+
+public enum ReplaySection {
+ SNAPSHOT(1),
+ DELTA(2),
+ EVENT(3);
+
+ private final int id;
+
+ ReplaySection(int id) {
+ this.id = id;
+ }
+
+ public int id() {
+ return id;
+ }
+
+ public static ReplaySection fromId(int id) {
+ for (ReplaySection section : values()) {
+ if (section.id == id) {
+ return section;
+ }
+ }
+ throw new IllegalArgumentException("Unknown replay section: " + id);
+ }
+}
diff --git a/commons/src/test/java/net/swofty/commons/replay/protocol/ReplayFormatTest.java b/commons/src/test/java/net/swofty/commons/replay/protocol/ReplayFormatTest.java
new file mode 100644
index 0000000000..49295b5b49
--- /dev/null
+++ b/commons/src/test/java/net/swofty/commons/replay/protocol/ReplayFormatTest.java
@@ -0,0 +1,39 @@
+package net.swofty.commons.replay.protocol;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ReplayFormatTest {
+ @Test
+ void roundTripsFramedChunk() throws Exception {
+ List entries = List.of(new byte[]{1, 2, 3}, new byte[]{4, 5});
+ ReplayChunk chunk = ReplayFormat.createChunk(ReplaySection.DELTA, 0, 12, 14, entries);
+
+ List decoded = ReplayFormat.readChunk(chunk);
+
+ assertEquals(entries.size(), decoded.size());
+ assertArrayEquals(entries.get(0), decoded.get(0));
+ assertArrayEquals(entries.get(1), decoded.get(1));
+ }
+
+ @Test
+ void rejectsChecksumMismatch() throws Exception {
+ ReplayChunk valid = ReplayFormat.createChunk(ReplaySection.EVENT, 0, 4, 4, List.of(new byte[]{9}));
+ ReplayChunk corrupt = new ReplayChunk(valid.section(), valid.sequence(), valid.startTick(), valid.endTick(),
+ valid.uncompressedLength(), valid.recordCount(), valid.checksum() + 1, valid.compressedPayload());
+
+ assertThrows(IOException.class, () -> ReplayFormat.readChunk(corrupt));
+ }
+
+ @Test
+ void rejectsMissingSequence() throws Exception {
+ ReplayChunk first = ReplayFormat.createChunk(ReplaySection.SNAPSHOT, 0, 0, 0, List.of(new byte[]{1}));
+ ReplayChunk third = ReplayFormat.createChunk(ReplaySection.SNAPSHOT, 2, 200, 200, List.of(new byte[]{2}));
+
+ assertThrows(IOException.class, () -> ReplayFormat.validateOrdered(List.of(first, third), ReplaySection.SNAPSHOT));
+ }
+}
diff --git a/configuration/bedwars/maps.json b/configuration/bedwars/maps.json
index 545a36f1bd..078b89db9f 100644
--- a/configuration/bedwars/maps.json
+++ b/configuration/bedwars/maps.json
@@ -5,8 +5,8 @@
"name": "Airshow",
"configuration": {
"types": [
- "SOLO",
- "DOUBLES"
+ "ONE_EIGHT",
+ "TWO_EIGHT"
],
"generatorSpeed": "SLOW",
"bounds": {
@@ -462,12 +462,12 @@
}
},
{
- "id": "speedway",
- "name": "Speedway",
+ "id": "lighthouse",
+ "name": "Lighthouse",
"configuration": {
"types": [
- "SOLO",
- "DOUBLES",
+ "ONE_EIGHT",
+ "TWO_EIGHT",
"ULTIMATE_DOUBLES"
],
"generatorSpeed": "SLOW",
@@ -486,354 +486,354 @@
}
},
"teams": {
- "PINK": {
+ "GRAY": {
"shop": {
"item": {
- "x": -82.02040193311008,
- "y": 66.0,
- "z": 26.41980214690541,
- "yaw": -0.3010254,
- "pitch": -0.9002611
+ "x": -85.0108875529608,
+ "y": 65.0,
+ "z": -31.495267847506838,
+ "yaw": 0.014282227,
+ "pitch": -0.74988824
},
"team": {
- "x": -82.03912265565305,
- "y": 66.0,
- "z": 38.52496280339181,
- "yaw": 0.0,
- "pitch": 0.0
+ "x": -85.0596923424721,
+ "y": 65.0,
+ "z": -20.629669566674032,
+ "yaw": -179.98706,
+ "pitch": -0.15006073
}
},
"spawn": {
- "x": -82.45194161144515,
- "y": 66.0,
- "z": 32.51095973557253,
- "yaw": -89.387085,
- "pitch": -0.9000542
+ "x": -85.40322458207508,
+ "y": 65.0,
+ "z": -25.536412033357305,
+ "yaw": -90.13562,
+ "pitch": -1.5000191
},
"bed": {
"feet": {
- "x": -70,
+ "x": -72,
"y": 66,
- "z": 32
+ "z": -26
},
"head": {
- "x": -71,
+ "x": -73,
"y": 66,
- "z": 32
+ "z": -26
}
},
"generator": {
- "x": -86.0,
- "y": 65.5,
- "z": 31.5,
+ "x": -87.5673901168893,
+ "y": 64.5,
+ "z": -25.483414467520394,
"yaw": 0.0,
"pitch": 0.0
}
},
- "WHITE": {
+ "PINK": {
"shop": {
"item": {
- "x": -37.57120528835294,
- "y": 66.0,
- "z": 82.97098866205523,
- "yaw": -90.00214,
- "pitch": -1.200244
+ "x": -85.04315008957276,
+ "y": 65.0,
+ "z": 20.63051632450276,
+ "yaw": -0.001159668,
+ "pitch": -0.6002544
},
"team": {
- "x": -25.504363571226587,
- "y": 66.0,
- "z": 82.96805231054407,
- "yaw": 89.39459,
- "pitch": -1.9502572
+ "x": -85.02157519497271,
+ "y": 65.0,
+ "z": 31.600896188308486,
+ "yaw": -179.70134,
+ "pitch": -0.1502753
}
},
"spawn": {
- "x": -31.489605948109872,
- "y": 66.0,
- "z": 83.4640637242984,
- "yaw": -179.40198,
- "pitch": -0.15010078
+ "x": -85.33047397827768,
+ "y": 65.0,
+ "z": 26.50267595410961,
+ "yaw": -90.59955,
+ "pitch": -1.1999936
},
"bed": {
"feet": {
- "x": -32,
+ "x": -72,
"y": 66,
- "z": 70
+ "z": 26
},
"head": {
- "x": -32,
+ "x": -73,
"y": 66,
- "z": 71
+ "z": 26
}
},
"generator": {
- "x": -32.0,
- "y": 65.5,
- "z": 85.5,
+ "x": -87.49264594588892,
+ "y": 64.5,
+ "z": 26.52547932011008,
"yaw": 0.0,
"pitch": 0.0
}
},
- "BLUE": {
+ "GREEN": {
"shop": {
"item": {
- "x": 38.651112821199156,
- "y": 66.0,
- "z": -82.0636611406802,
- "yaw": 89.842865,
- "pitch": -2.1000006
+ "x": 92.04099251477956,
+ "y": 65.0,
+ "z": -19.512879069070113,
+ "yaw": 179.57922,
+ "pitch": 0.15020467
},
"team": {
- "x": 26.513876353954437,
- "y": 66.0,
- "z": -81.96871672001237,
- "yaw": -90.00635,
- "pitch": -2.0998929
+ "x": 92.03963698940655,
+ "y": 65.0,
+ "z": -30.640048146160893,
+ "yaw": 0.026367188,
+ "pitch": -1.3498296
}
},
"spawn": {
- "x": 32.44825455698304,
- "y": 66.0,
- "z": -82.21619659979275,
- "yaw": -0.28649902,
- "pitch": -1.3502306
+ "x": 92.4755666172137,
+ "y": 65.0,
+ "z": -25.491783290995787,
+ "yaw": 90.17285,
+ "pitch": -1.3500005
},
"bed": {
"feet": {
- "x": 32,
+ "x": 78,
"y": 66,
- "z": -70
+ "z": -26
},
"head": {
- "x": 32,
+ "x": 79,
"y": 66,
- "z": -71
+ "z": -26
}
},
"generator": {
- "x": 32.0,
- "y": 65.5,
- "z": -86.5,
+ "x": 94.50786462929776,
+ "y": 64.5,
+ "z": -25.561788917213132,
"yaw": 0.0,
"pitch": 0.0
}
},
- "GREEN": {
+ "YELLOW": {
"shop": {
"item": {
- "x": 83.02754376288796,
- "y": 66.0,
- "z": -25.50247371161989,
- "yaw": 179.69226,
- "pitch": -0.8998925
+ "x": 92.00019708368568,
+ "y": 65.0,
+ "z": 32.52003900590035,
+ "yaw": 179.56714,
+ "pitch": -1.0499948
},
"team": {
- "x": 83.01808132101671,
- "y": 66.0,
- "z": -37.4449225565394,
- "yaw": 0.89160156,
- "pitch": 0.7500627
+ "x": 92.05260636514082,
+ "y": 65.0,
+ "z": 21.62810314464048,
+ "yaw": 0.01953125,
+ "pitch": -0.90015817
}
},
"spawn": {
- "x": 83.52472511460185,
- "y": 66.0,
- "z": -31.47239674724424,
- "yaw": 90.308716,
- "pitch": -1.9499904
+ "x": 92.5016778646452,
+ "y": 65.0,
+ "z": 26.503177814113776,
+ "yaw": 89.869385,
+ "pitch": -1.0500311
},
"bed": {
"feet": {
- "x": 70,
+ "x": 78,
"y": 66,
- "z": -32
+ "z": 26
},
"head": {
- "x": 71,
+ "x": 79,
"y": 66,
- "z": -32
+ "z": 26
}
},
"generator": {
- "x": 87.07588737864218,
- "y": 65.5,
- "z": -31.54334025712658,
+ "x": 94.52302376614784,
+ "y": 64.5,
+ "z": 26.495665102706702,
"yaw": 0.0,
"pitch": 0.0
}
},
- "GRAY": {
+ "RED": {
"shop": {
"item": {
- "x": -81.97052279318929,
- "y": 66.0,
- "z": -37.314472093522035,
- "yaw": -0.00012207031,
- "pitch": -1.4999375
+ "x": -16.42898002455651,
+ "y": 65.0,
+ "z": -87.95377324913402,
+ "yaw": 90.47034,
+ "pitch": -0.6001133
},
"team": {
- "x": -81.90479994981206,
- "y": 66.0,
- "z": -25.66597099278967,
- "yaw": 179.39453,
- "pitch": -0.6000788
+ "x": -27.56787077510041,
+ "y": 65.0,
+ "z": -88.0152493117479,
+ "yaw": -89.38147,
+ "pitch": -0.15003474
}
},
"spawn": {
- "x": -82.25697683329115,
- "y": 66.0,
- "z": -31.5320875690394,
- "yaw": -89.97522,
- "pitch": -1.2003078
+ "x": -22.519568104899527,
+ "y": 65.0,
+ "z": -88.48850061662141,
+ "yaw": 0.9182129,
+ "pitch": -0.15001334
},
"bed": {
"feet": {
- "x": -70,
+ "x": -23,
"y": 66,
- "z": -32
+ "z": -75
},
"head": {
- "x": -71,
+ "x": -23,
"y": 66,
- "z": -32
+ "z": -76
}
},
"generator": {
- "x": -86.0,
- "y": 65.5,
- "z": -32.5,
+ "x": -22.5312774980518,
+ "y": 64.5,
+ "z": -90.57548230296806,
"yaw": 0.0,
"pitch": 0.0
}
},
- "RED": {
+ "WHITE": {
"shop": {
"item": {
- "x": -25.54262467705194,
- "y": 66.0,
- "z": -82.05912286154171,
- "yaw": 89.54819,
- "pitch": -1.4999728
+ "x": -28.574379786349034,
+ "y": 65.0,
+ "z": 89.02285078530015,
+ "yaw": -89.836914,
+ "pitch": -1.0500664
},
"team": {
- "x": -37.470634976194255,
- "y": 66.0,
- "z": -81.95370501834397,
- "yaw": -90.30185,
- "pitch": -1.3499578
+ "x": -17.461621765421107,
+ "y": 65.0,
+ "z": 88.943122501835,
+ "yaw": 90.763306,
+ "pitch": 2.5499506
}
},
"spawn": {
- "x": -31.429089110829988,
- "y": 66.0,
- "z": -82.53114534212739,
- "yaw": -0.12023926,
- "pitch": -0.90005803
+ "x": -22.471525601515623,
+ "y": 65.0,
+ "z": 89.57296851701679,
+ "yaw": 178.80945,
+ "pitch": -2.8500109
},
"bed": {
"feet": {
- "x": -32,
+ "x": -23,
"y": 66,
- "z": -70
+ "z": 75
},
"head": {
- "x": -32,
+ "x": -23,
"y": 66,
- "z": -71
+ "z": 76
}
},
"generator": {
- "x": -32.0,
- "y": 65.5,
- "z": -86.5,
+ "x": -22.412900889637193,
+ "y": 64.5,
+ "z": 91.23618220055619,
"yaw": 0.0,
"pitch": 0.0
}
},
- "AQUA": {
+ "BLUE": {
"shop": {
"item": {
- "x": 26.505141024953048,
- "y": 66.0,
- "z": 83.00298652272173,
- "yaw": -89.855774,
- "pitch": -1.350118
+ "x": 35.485826946930615,
+ "y": 65.0,
+ "z": -88.04529512429717,
+ "yaw": 89.87683,
+ "pitch": 0.14996125
},
"team": {
- "x": 38.456872802559054,
- "y": 66.0,
- "z": 82.99083246172962,
- "yaw": 89.84564,
- "pitch": -2.2501745
+ "x": 24.622361774925704,
+ "y": 65.0,
+ "z": -88.05656319005925,
+ "yaw": -90.5741,
+ "pitch": -1.3499969
}
},
"spawn": {
- "x": 32.49501313553803,
- "y": 66.0,
- "z": 83.53070551834745,
- "yaw": -179.5393,
- "pitch": -0.9000198
- },
- "bed": {
- "feet": {
- "x": 32,
+ "x": 29.49428195060743,
+ "y": 65.0,
+ "z": -88.48868721971608,
+ "yaw": 0.17382812,
+ "pitch": -0.90002465
+ },
+ "bed": {
+ "feet": {
+ "x": 29,
"y": 66,
- "z": 70
+ "z": -75
},
"head": {
- "x": 32,
+ "x": 29,
"y": 66,
- "z": 71
+ "z": -76
}
},
"generator": {
- "x": 32.0,
- "y": 65.5,
- "z": 85.5,
+ "x": 29.49800786315674,
+ "y": 64.5,
+ "z": -90.49292341421382,
"yaw": 0.0,
"pitch": 0.0
}
},
- "YELLOW": {
+ "AQUA": {
"shop": {
"item": {
- "x": 82.98866742168755,
- "y": 66.0,
- "z": 38.39515375216421,
- "yaw": 179.6955,
- "pitch": -0.9001085
+ "x": 23.46475353590089,
+ "y": 65.0,
+ "z": 89.00416751918755,
+ "yaw": -89.68347,
+ "pitch": -0.90002316
},
"team": {
- "x": 83.0012612940198,
- "y": 66.0,
- "z": 26.688584248556545,
- "yaw": -0.4545288,
- "pitch": -1.6501008
+ "x": 34.48868965579855,
+ "y": 65.0,
+ "z": 88.9687709421603,
+ "yaw": 90.31177,
+ "pitch": -0.45002592
}
},
"spawn": {
- "x": 83.44142018547358,
- "y": 66.0,
- "z": 32.516950785630655,
- "yaw": 89.557495,
- "pitch": -0.29999876
+ "x": 29.51989114105056,
+ "y": 65.0,
+ "z": 89.5076579294666,
+ "yaw": -179.83789,
+ "pitch": -1.5000246
},
"bed": {
"feet": {
- "x": 70,
+ "x": 29,
"y": 66,
- "z": 32
+ "z": 75
},
"head": {
- "x": 71,
+ "x": 29,
"y": 66,
- "z": 32
+ "z": 76
}
},
"generator": {
- "x": 86.0,
- "y": 65.5,
- "z": 31.5,
+ "x": 29.51437547667322,
+ "y": 64.5,
+ "z": 91.54059238014068,
"yaw": 0.0,
"pitch": 0.0
}
@@ -842,14 +842,14 @@
"locations": {
"waiting": {
"x": 0.0,
- "y": 98.0,
+ "y": 118.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 0.0
},
"spectator": {
"x": 0.0,
- "y": 80.0,
+ "y": 103.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 0.0
@@ -859,30 +859,30 @@
"DIAMOND": {
"locations": [
{
- "x": -31.5,
- "y": 65.0,
- "z": -31.5,
+ "x": -48.5,
+ "y": 67.0,
+ "z": -51.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": -31.5,
- "y": 65.0,
- "z": 32.5,
+ "x": -48.5,
+ "y": 67.0,
+ "z": 52.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 32.5,
- "y": 65.0,
- "z": -31.5,
+ "x": 55.5,
+ "y": 67.0,
+ "z": -51.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 32.5,
- "y": 65.0,
- "z": 32.5,
+ "x": 55.5,
+ "y": 67.0,
+ "z": 52.5,
"yaw": 0.0,
"pitch": 0.0
}
@@ -891,30 +891,30 @@
"EMERALD": {
"locations": [
{
- "x": -11.5,
- "y": 66.0,
- "z": 15.5,
+ "x": -6.5,
+ "y": 65.0,
+ "z": 14.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": -2.5,
- "y": 56.0,
- "z": 8.5,
+ "x": 3.5,
+ "y": 87.0,
+ "z": -6.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 3.5,
- "y": 56.0,
- "z": -7.5,
+ "x": 13.5,
+ "y": 65.0,
+ "z": -13.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 12.5,
- "y": 66.0,
- "z": -14.5,
+ "x": 3.5,
+ "y": 87.0,
+ "z": 7.5,
"yaw": 0.0,
"pitch": 0.0
}
@@ -924,752 +924,1026 @@
}
},
{
- "id": "rooftop",
- "name": "Rooftop",
+ "id": "haven",
+ "name": "haven",
"configuration": {
"types": [
- "SOLO",
- "DOUBLES",
- "ULTIMATE_DOUBLES"
+ null,
+ null,
+ "LUCKY_BLOCK_DOUBLES"
],
"generatorSpeed": "SLOW",
"bounds": {
"x": {
- "min": -100.0,
- "max": 100.0
+ "min": -125.0,
+ "max": 125.0
},
"y": {
- "min": -100.0,
+ "min": 0.0,
"max": 100.0
},
"z": {
- "min": -100.0,
- "max": 100.0
+ "min": -125.0,
+ "max": 125.0
}
},
"teams": {
- "GRAY": {
+ "RED": {
"shop": {
"item": {
- "x": -90.01983756947546,
- "y": 66.0,
- "z": -39.42647039169151,
- "yaw": -0.44920057,
- "pitch": -1.650027
+ "x": -5.643081030208206,
+ "y": 48.0,
+ "z": 105.00760245533807,
+ "yaw": -0.45004654,
+ "pitch": -89.55029
},
"team": {
- "x": -89.968787336429,
- "y": 66.0,
- "z": -27.526147971256428,
- "yaw": -179.699,
- "pitch": -1.6500026
+ "x": 6.513037234763775,
+ "y": 48.0,
+ "z": 104.95045523360692,
+ "yaw": -0.60003746,
+ "pitch": 90.29947
}
},
"spawn": {
- "x": -91.50789125537915,
- "y": 66.0,
- "z": -33.4614884673225,
- "yaw": -89.69918,
- "pitch": -2.2500162
+ "x": 0.4566740272757841,
+ "y": 48.0,
+ "z": 104.57865104045052,
+ "yaw": -0.9000152,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": -79,
- "y": 66,
- "z": -34
+ "x": 0,
+ "y": 46,
+ "z": 90
},
"head": {
- "x": -80,
- "y": 66,
- "z": -34
+ "x": 0,
+ "y": 46,
+ "z": 91
}
},
"generator": {
- "x": -94.88180199559939,
- "y": 65.5,
- "z": -33.47895599279666,
+ "x": 0.48311192527610214,
+ "y": 47.5,
+ "z": 109.40563123435935,
"yaw": 0.0,
"pitch": 0.0
}
},
- "PINK": {
+ "BLUE": {
"shop": {
"item": {
- "x": -89.98054541737716,
- "y": 66.0,
- "z": 28.467331158132353,
- "yaw": -0.29211426,
- "pitch": -1.3499774
+ "x": -104.00200548536833,
+ "y": 48.0,
+ "z": -5.511538167515957,
+ "yaw": -0.8999911,
+ "pitch": 0.1472168
},
"team": {
- "x": -90.0204986863301,
- "y": 66.0,
- "z": 40.539796055189804,
- "yaw": -179.84265,
- "pitch": -0.5999382
+ "x": -103.97642442586424,
+ "y": 48.0,
+ "z": 6.530339403426724,
+ "yaw": 0.3000191,
+ "pitch": -179.70227
}
},
"spawn": {
- "x": -91.52177451771917,
- "y": 66.0,
- "z": 34.55702213652238,
- "yaw": -90.14459,
- "pitch": -2.250019
+ "x": -104.00035970966859,
+ "y": 48.0,
+ "z": 0.4982683648858232,
+ "yaw": 0.44997922,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": -79,
- "y": 66,
- "z": 34
+ "x": -90,
+ "y": 46,
+ "z": 0
},
"head": {
- "x": -80,
- "y": 66,
- "z": 34
+ "x": -91,
+ "y": 46,
+ "z": 0
}
},
"generator": {
- "x": -95.00606472183632,
- "y": 65.5,
- "z": 34.472998109442024,
+ "x": -108.44139800163269,
+ "y": 47.5,
+ "z": 0.5066969091555289,
"yaw": 0.0,
"pitch": 0.0
}
},
- "RED": {
+ "GREEN": {
"shop": {
"item": {
- "x": -27.561475984770826,
- "y": 66.0,
- "z": -90.03896114532824,
- "yaw": 90.00113,
- "pitch": -1.650014
+ "x": 6.452209881084259,
+ "y": 48.0,
+ "z": -103.97213185082639,
+ "yaw": 0.14998366,
+ "pitch": 89.99768
},
"team": {
- "x": -39.45869286910505,
- "y": 66.0,
- "z": -90.06382595988917,
- "yaw": -90.449036,
- "pitch": -1.2000538
+ "x": -5.486204346304282,
+ "y": 48.0,
+ "z": -104.06431278356358,
+ "yaw": -0.6000095,
+ "pitch": -89.552734
}
},
"spawn": {
- "x": -33.48309695078257,
- "y": 66.0,
- "z": -91.54055720728049,
- "yaw": 0.30688477,
- "pitch": -1.6500056
- },
- "bed": {
- "feet": {
- "x": -34,
- "y": 66,
- "z": -79
+ "x": 0.4816414347717442,
+ "y": 48.0,
+ "z": -103.96215353598399,
+ "yaw": -0.4500038,
+ "pitch": 0.14782715
+ },
+ "bed": {
+ "feet": {
+ "x": 0,
+ "y": 46,
+ "z": -90
},
"head": {
- "x": -34,
- "y": 66,
- "z": -80
+ "x": 0,
+ "y": 46,
+ "z": -91
}
},
"generator": {
- "x": -34.0,
- "y": 65.5,
- "z": -95.5,
+ "x": 0.47573204880919545,
+ "y": 47.5,
+ "z": -108.50300788140555,
"yaw": 0.0,
"pitch": 0.0
}
},
- "WHITE": {
+ "YELLOW": {
"shop": {
"item": {
- "x": -39.619789596622844,
- "y": 66.0,
- "z": 90.99516710124517,
- "yaw": -90.1427,
- "pitch": -2.400028
+ "x": 104.98711045888756,
+ "y": 48.0,
+ "z": 6.566614067860879,
+ "yaw": -1.0500069,
+ "pitch": 179.09155
},
"team": {
- "x": -27.537757646848167,
- "y": 66.0,
- "z": 90.99331226247274,
- "yaw": 89.258545,
- "pitch": -0.15004088
+ "x": 104.96962792336748,
+ "y": 48.0,
+ "z": -5.542657550120672,
+ "yaw": 0.6000119,
+ "pitch": -0.4584961
}
},
"spawn": {
- "x": -33.41090708421141,
- "y": 66.0,
- "z": 92.54655583931589,
- "yaw": 179.25671,
- "pitch": -1.9500283
+ "x": 104.90221295849302,
+ "y": 48.0,
+ "z": 0.5618568772327801,
+ "yaw": 0.74996793,
+ "pitch": 91.04187
},
"bed": {
"feet": {
- "x": -34,
- "y": 66,
- "z": 79
+ "x": 90,
+ "y": 46,
+ "z": 0
},
"head": {
- "x": -34,
- "y": 66,
- "z": 80
+ "x": 91,
+ "y": 46,
+ "z": 0
}
},
"generator": {
- "x": -34.0,
- "y": 65.5,
- "z": 94.5,
+ "x": 109.46146206656485,
+ "y": 47.5,
+ "z": 0.5320753244557163,
"yaw": 0.0,
"pitch": 0.0
}
+ }
+ },
+ "locations": {
+ "waiting": {
+ "x": 0.45753038265154733,
+ "y": 120.0,
+ "z": 0.49395332083443444,
+ "yaw": 0.0,
+ "pitch": 0.0
},
+ "spectator": {
+ "x": 0.0,
+ "y": 70.0,
+ "z": 0.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ },
+ "globalGenerator": {
+ "EMERALD": {
+ "locations": [
+ {
+ "x": 0.5,
+ "y": 51.0,
+ "z": -8.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 0.5,
+ "y": 51.0,
+ "z": 9.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ ]
+ },
+ "DIAMOND": {
+ "locations": [
+ {
+ "x": -42.5,
+ "y": 48.0,
+ "z": -42.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": -42.5,
+ "y": 48.0,
+ "z": 43.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 43.5,
+ "y": 48.0,
+ "z": -42.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 43.5,
+ "y": 48.0,
+ "z": 43.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "id": "one_block",
+ "name": "One Block",
+ "configuration": {
+ "types": [
+ "ONE_BLOCK"
+ ],
+ "bounds": {
+ "x": {
+ "min": -100.0,
+ "max": 100.0
+ },
+ "y": {
+ "min": 0.0,
+ "max": 150.0
+ },
+ "z": {
+ "min": -100.0,
+ "max": 100.0
+ }
+ },
+ "teams": {
"BLUE": {
- "shop": {
- "item": {
- "x": 40.398926387768824,
- "y": 66.0,
- "z": -89.99768047458974,
- "yaw": 89.55142,
- "pitch": -1.6500026
+ "spawn": {
+ "x": 18.0,
+ "y": 72.0,
+ "z": -9.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "bed": {
+ "feet": {
+ "x": 18,
+ "y": 71,
+ "z": -9
},
- "team": {
- "x": 28.46443708132082,
- "y": 66.0,
- "z": -90.01183225196914,
- "yaw": -89.998535,
- "pitch": -2.8500068
+ "head": {
+ "x": 17,
+ "y": 71,
+ "z": -9
}
+ }
+ },
+ "RED": {
+ "spawn": {
+ "x": 18.0,
+ "y": 72.0,
+ "z": 8.0,
+ "yaw": 0.0,
+ "pitch": 0.0
},
+ "bed": {
+ "feet": {
+ "x": 18,
+ "y": 71,
+ "z": 8
+ },
+ "head": {
+ "x": 17,
+ "y": 71,
+ "z": 8
+ }
+ }
+ },
+ "GRAY": {
"spawn": {
- "x": 34.509823644268536,
- "y": 66.0,
- "z": -91.5133869660805,
- "yaw": 0.30786133,
- "pitch": -2.850025
+ "x": 8.0,
+ "y": 72.0,
+ "z": 18.0,
+ "yaw": 0.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 34,
- "y": 66,
- "z": -79
+ "x": 8,
+ "y": 71,
+ "z": 18
},
"head": {
- "x": 34,
- "y": 66,
- "z": -80
+ "x": 8,
+ "y": 71,
+ "z": 17
}
+ }
+ },
+ "PINK": {
+ "spawn": {
+ "x": -9.0,
+ "y": 72.0,
+ "z": 18.0,
+ "yaw": 0.0,
+ "pitch": 0.0
},
- "generator": {
- "x": 34.0,
- "y": 65.5,
- "z": -95.5,
+ "bed": {
+ "feet": {
+ "x": -9,
+ "y": 71,
+ "z": 18
+ },
+ "head": {
+ "x": -9,
+ "y": 71,
+ "z": 17
+ }
+ }
+ },
+ "WHITE": {
+ "spawn": {
+ "x": -19.0,
+ "y": 72.0,
+ "z": 8.0,
"yaw": 0.0,
"pitch": 0.0
+ },
+ "bed": {
+ "feet": {
+ "x": -19,
+ "y": 71,
+ "z": 8
+ },
+ "head": {
+ "x": -18,
+ "y": 71,
+ "z": 8
+ }
}
},
- "AQUA": {
+ "AQUA": {
+ "spawn": {
+ "x": -19.0,
+ "y": 72.0,
+ "z": -9.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "bed": {
+ "feet": {
+ "x": -19,
+ "y": 71,
+ "z": -9
+ },
+ "head": {
+ "x": -18,
+ "y": 71,
+ "z": -9
+ }
+ }
+ },
+ "YELLOW": {
+ "spawn": {
+ "x": -9.0,
+ "y": 72.0,
+ "z": -19.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "bed": {
+ "feet": {
+ "x": -9,
+ "y": 71,
+ "z": -19
+ },
+ "head": {
+ "x": -9,
+ "y": 71,
+ "z": -18
+ }
+ }
+ },
+ "GREEN": {
+ "spawn": {
+ "x": 8.0,
+ "y": 72.0,
+ "z": -19.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "bed": {
+ "feet": {
+ "x": 8,
+ "y": 71,
+ "z": -19
+ },
+ "head": {
+ "x": 8,
+ "y": 71,
+ "z": -18
+ }
+ }
+ }
+ },
+ "locations": {
+ "waiting": {
+ "x": 0.0,
+ "y": 99.0,
+ "z": 6.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "spectator": {
+ "x": 0.0,
+ "y": 99.0,
+ "z": 6.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ }
+ }
+ },
+ {
+ "id": "speedway",
+ "name": "Speedway",
+ "configuration": {
+ "types": [
+ "ONE_EIGHT",
+ "TWO_EIGHT",
+ "ULTIMATE_DOUBLES"
+ ],
+ "generatorSpeed": "SLOW",
+ "bounds": {
+ "x": {
+ "min": -100.0,
+ "max": 100.0
+ },
+ "y": {
+ "min": -100.0,
+ "max": 100.0
+ },
+ "z": {
+ "min": -100.0,
+ "max": 100.0
+ }
+ },
+ "teams": {
+ "RED": {
"shop": {
"item": {
- "x": 28.41990219468591,
+ "x": -25.54262467705194,
"y": 66.0,
- "z": 91.06331403239552,
- "yaw": -91.04541,
- "pitch": -2.7000225
+ "z": -82.05912286154171,
+ "yaw": 90.0,
+ "pitch": 0.0
},
"team": {
- "x": 40.36172087467049,
+ "x": -37.470634976194255,
"y": 66.0,
- "z": 91.06411210174763,
- "yaw": 90.15213,
- "pitch": -0.90007347
+ "z": -81.95370501834397,
+ "yaw": -90.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": 34.524004250348334,
+ "x": -31.429089110829988,
"y": 66.0,
- "z": 92.45408851220344,
- "yaw": -179.84644,
- "pitch": -1.2000084
+ "z": -82.53114534212739,
+ "yaw": 0.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 34,
+ "x": -32,
"y": 66,
- "z": 79
+ "z": -70
},
"head": {
- "x": 34,
+ "x": -32,
"y": 66,
- "z": 80
+ "z": -71
}
},
"generator": {
- "x": 34.59259801675937,
+ "x": -31.520957492521607,
"y": 65.5,
- "z": 95.53276513823602,
+ "z": -85.99582579744497,
"yaw": 0.0,
"pitch": 0.0
}
},
- "GREEN": {
+ "BLUE": {
"shop": {
"item": {
- "x": 90.97755565005453,
+ "x": 38.651112821199156,
"y": 66.0,
- "z": -27.37446350690706,
- "yaw": 178.95184,
- "pitch": -1.1999909
+ "z": -82.0636611406802,
+ "yaw": 90.0,
+ "pitch": 0.0
},
"team": {
- "x": 91.01148627742812,
+ "x": 26.513876353954437,
"y": 66.0,
- "z": -39.56285225865746,
- "yaw": -0.14828491,
- "pitch": -1.3499583
+ "z": -81.96871672001237,
+ "yaw": -90.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": 92.35244930696713,
+ "x": 32.44825455698304,
"y": 66.0,
- "z": -33.540694954234894,
- "yaw": 89.85184,
- "pitch": -0.9000325
+ "z": -82.21619659979275,
+ "yaw": 0.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 79,
+ "x": 32,
"y": 66,
- "z": -34
+ "z": -70
},
"head": {
- "x": 80,
+ "x": 32,
"y": 66,
- "z": -34
+ "z": -71
}
},
"generator": {
- "x": 95.59669657935473,
+ "x": 32.46699982692364,
"y": 65.5,
- "z": -33.41313094325075,
+ "z": -86.02987474536931,
"yaw": 0.0,
"pitch": 0.0
}
},
- "YELLOW": {
+ "GREEN": {
"shop": {
"item": {
- "x": 90.99918379500014,
+ "x": 83.02754376288796,
"y": 66.0,
- "z": 40.58232810998059,
- "yaw": -179.9967,
- "pitch": -0.45014584
+ "z": -25.50247371161989,
+ "yaw": -180.0,
+ "pitch": 0.0
},
"team": {
- "x": 91.0230495348164,
+ "x": 83.01808132101671,
"y": 66.0,
- "z": 28.463560410301472,
- "yaw": 0.7530823,
- "pitch": -2.4001167
+ "z": -37.4449225565394,
+ "yaw": 0.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": 92.47357850698647,
+ "x": 83.52472511460185,
"y": 66.0,
- "z": 34.47878025929901,
- "yaw": 89.404785,
- "pitch": -2.100014
+ "z": -31.47239674724424,
+ "yaw": 90.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 79,
+ "x": 70,
"y": 66,
- "z": 34
+ "z": -32
},
"head": {
- "x": 80,
+ "x": 71,
"y": 66,
- "z": 34
+ "z": -32
}
},
"generator": {
- "x": 95.45996664371597,
+ "x": 87.07588737864218,
"y": 65.5,
- "z": 34.71001348863422,
+ "z": -31.54334025712658,
"yaw": 0.0,
"pitch": 0.0
}
- }
- },
- "locations": {
- "waiting": {
- "x": 0.0,
- "y": 118.0,
- "z": 0.0,
- "yaw": 0.0,
- "pitch": 0.0
- },
- "spectator": {
- "x": 3.5,
- "y": 81.0,
- "z": 3.5,
- "yaw": 0.0,
- "pitch": 0.0
- }
- },
- "globalGenerator": {
- "DIAMOND": {
- "locations": [
- {
- "x": -38.5,
- "y": 71.0,
- "z": -38.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": -38.5,
- "y": 71.0,
- "z": 39.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 39.5,
- "y": 71.0,
- "z": -38.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 39.5,
- "y": 71.0,
- "z": 39.5,
- "yaw": 0.0,
- "pitch": 0.0
- }
- ]
- },
- "EMERALD": {
- "locations": [
- {
- "x": -10.5,
- "y": 71.0,
- "z": -12.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": -10.5,
- "y": 80.0,
- "z": -10.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 11.5,
- "y": 80.0,
- "z": 11.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 11.5,
- "y": 71.0,
- "z": 13.5,
- "yaw": 0.0,
- "pitch": 0.0
- }
- ]
- }
- }
- }
- },
- {
- "id": "lighthouse",
- "name": "Lighthouse",
- "configuration": {
- "types": [
- "SOLO",
- "DOUBLES",
- "ULTIMATE_DOUBLES"
- ],
- "generatorSpeed": "SLOW",
- "bounds": {
- "x": {
- "min": -100.0,
- "max": 100.0
- },
- "y": {
- "min": -100.0,
- "max": 100.0
},
- "z": {
- "min": -100.0,
- "max": 100.0
- }
- },
- "teams": {
- "GRAY": {
+ "YELLOW": {
"shop": {
"item": {
- "x": -85.0108875529608,
- "y": 65.0,
- "z": -31.495267847506838,
- "yaw": 0.014282227,
- "pitch": -0.74988824
- },
- "team": {
- "x": -85.0596923424721,
- "y": 65.0,
- "z": -20.629669566674032,
- "yaw": -179.98706,
- "pitch": -0.15006073
+ "x": 82.98866742168755,
+ "y": 66.0,
+ "z": 38.39515375216421,
+ "yaw": -180.0,
+ "pitch": 0.0
+ },
+ "team": {
+ "x": 83.0012612940198,
+ "y": 66.0,
+ "z": 26.688584248556545,
+ "yaw": 0.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": -85.40322458207508,
- "y": 65.0,
- "z": -25.536412033357305,
- "yaw": -90.13562,
- "pitch": -1.5000191
+ "x": 83.44142018547358,
+ "y": 66.0,
+ "z": 32.516950785630655,
+ "yaw": 90.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": -72,
+ "x": 70,
"y": 66,
- "z": -26
+ "z": 32
},
"head": {
- "x": -73,
+ "x": 71,
"y": 66,
- "z": -26
+ "z": 32
}
},
"generator": {
- "x": -87.5673901168893,
- "y": 64.5,
- "z": -25.483414467520394,
+ "x": 87.0224573579638,
+ "y": 65.5,
+ "z": 32.497151213648586,
"yaw": 0.0,
"pitch": 0.0
}
},
- "PINK": {
+ "AQUA": {
"shop": {
"item": {
- "x": -85.04315008957276,
- "y": 65.0,
- "z": 20.63051632450276,
- "yaw": -0.001159668,
- "pitch": -0.6002544
+ "x": 26.505141024953048,
+ "y": 66.0,
+ "z": 83.00298652272173,
+ "yaw": -90.0,
+ "pitch": 0.0
},
"team": {
- "x": -85.02157519497271,
- "y": 65.0,
- "z": 31.600896188308486,
- "yaw": -179.70134,
- "pitch": -0.1502753
+ "x": 38.456872802559054,
+ "y": 66.0,
+ "z": 82.99083246172962,
+ "yaw": 90.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": -85.33047397827768,
- "y": 65.0,
- "z": 26.50267595410961,
- "yaw": -90.59955,
- "pitch": -1.1999936
+ "x": 32.49501313553803,
+ "y": 66.0,
+ "z": 83.53070551834745,
+ "yaw": -180.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": -72,
+ "x": 32,
"y": 66,
- "z": 26
+ "z": 70
},
"head": {
- "x": -73,
+ "x": 32,
"y": 66,
- "z": 26
+ "z": 71
}
},
"generator": {
- "x": -87.49264594588892,
- "y": 64.5,
- "z": 26.52547932011008,
+ "x": 32.467421186976416,
+ "y": 65.5,
+ "z": 87.029144287481,
"yaw": 0.0,
"pitch": 0.0
}
},
- "GREEN": {
+ "WHITE": {
"shop": {
"item": {
- "x": 92.04099251477956,
- "y": 65.0,
- "z": -19.512879069070113,
- "yaw": 179.57922,
- "pitch": 0.15020467
+ "x": -37.57120528835294,
+ "y": 66.0,
+ "z": 82.97098866205523,
+ "yaw": -90.0,
+ "pitch": 0.0
},
"team": {
- "x": 92.03963698940655,
- "y": 65.0,
- "z": -30.640048146160893,
- "yaw": 0.026367188,
- "pitch": -1.3498296
+ "x": -25.504363571226587,
+ "y": 66.0,
+ "z": 82.96805231054407,
+ "yaw": 90.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": 92.4755666172137,
- "y": 65.0,
- "z": -25.491783290995787,
- "yaw": 90.17285,
- "pitch": -1.3500005
+ "x": -31.489605948109872,
+ "y": 66.0,
+ "z": 83.4640637242984,
+ "yaw": -180.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 78,
+ "x": -32,
"y": 66,
- "z": -26
+ "z": 70
},
"head": {
- "x": 79,
+ "x": -32,
"y": 66,
- "z": -26
+ "z": 71
}
},
"generator": {
- "x": 94.50786462929776,
- "y": 64.5,
- "z": -25.561788917213132,
+ "x": -31.50514865390738,
+ "y": 65.5,
+ "z": 87.00812894728995,
"yaw": 0.0,
"pitch": 0.0
}
},
- "YELLOW": {
+ "PINK": {
"shop": {
"item": {
- "x": 92.00019708368568,
- "y": 65.0,
- "z": 32.52003900590035,
- "yaw": 179.56714,
- "pitch": -1.0499948
+ "x": -82.02040193311008,
+ "y": 66.0,
+ "z": 26.41980214690541,
+ "yaw": 0.0,
+ "pitch": 0.0
},
"team": {
- "x": 92.05260636514082,
- "y": 65.0,
- "z": 21.62810314464048,
- "yaw": 0.01953125,
- "pitch": -0.90015817
+ "x": -82.04347575101806,
+ "y": 66.0,
+ "z": 38.54916211302723,
+ "yaw": -180.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": 92.5016778646452,
- "y": 65.0,
- "z": 26.503177814113776,
- "yaw": 89.869385,
- "pitch": -1.0500311
+ "x": -82.45485326281899,
+ "y": 66.0,
+ "z": 32.479956986062774,
+ "yaw": -90.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": 78,
+ "x": -70,
"y": 66,
- "z": 26
+ "z": 32
},
"head": {
- "x": 79,
+ "x": -71,
"y": 66,
- "z": 26
+ "z": 32
}
},
"generator": {
- "x": 94.52302376614784,
- "y": 64.5,
- "z": 26.495665102706702,
+ "x": -86.00643932534592,
+ "y": 65.5,
+ "z": 32.489001675528165,
"yaw": 0.0,
"pitch": 0.0
}
},
- "RED": {
+ "GRAY": {
"shop": {
"item": {
- "x": -16.42898002455651,
- "y": 65.0,
- "z": -87.95377324913402,
- "yaw": 90.47034,
- "pitch": -0.6001133
+ "x": -81.97052279318929,
+ "y": 66.0,
+ "z": -37.314472093522035,
+ "yaw": 0.0,
+ "pitch": 0.0
},
"team": {
- "x": -27.56787077510041,
- "y": 65.0,
- "z": -88.0152493117479,
- "yaw": -89.38147,
- "pitch": -0.15003474
+ "x": -81.90479994981206,
+ "y": 66.0,
+ "z": -25.66597099278967,
+ "yaw": -180.0,
+ "pitch": 0.0
}
},
"spawn": {
- "x": -22.519568104899527,
- "y": 65.0,
- "z": -88.48850061662141,
- "yaw": 0.9182129,
- "pitch": -0.15001334
+ "x": -82.25697683329115,
+ "y": 66.0,
+ "z": -31.5320875690394,
+ "yaw": -90.0,
+ "pitch": 0.0
},
"bed": {
"feet": {
- "x": -23,
+ "x": -70,
"y": 66,
- "z": -75
+ "z": -32
+ },
+ "head": {
+ "x": -71,
+ "y": 66,
+ "z": -32
+ }
+ },
+ "generator": {
+ "x": -85.99443930611548,
+ "y": 65.5,
+ "z": -31.496545723417245,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ }
+ },
+ "locations": {
+ "waiting": {
+ "x": 0.0,
+ "y": 98.0,
+ "z": 0.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "spectator": {
+ "x": 0.0,
+ "y": 80.0,
+ "z": 0.0,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ "waitingLobby": {
+ "min": {
+ "x": -15,
+ "y": 90,
+ "z": 14
+ },
+ "max": {
+ "x": 14,
+ "y": 115,
+ "z": -18
+ }
+ }
+ },
+ "globalGenerator": {
+ "EMERALD": {
+ "locations": [
+ {
+ "x": -11.5,
+ "y": 66.0,
+ "z": 15.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": -2.5,
+ "y": 56.0,
+ "z": 8.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 3.5,
+ "y": 56.0,
+ "z": -7.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 12.5,
+ "y": 66.0,
+ "z": -14.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
+ ]
+ },
+ "DIAMOND": {
+ "locations": [
+ {
+ "x": -31.5,
+ "y": 65.0,
+ "z": -31.5,
+ "yaw": 0.0,
+ "pitch": 0.0
},
- "head": {
- "x": -23,
- "y": 66,
- "z": -76
+ {
+ "x": -31.5,
+ "y": 65.0,
+ "z": 32.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 32.5,
+ "y": 65.0,
+ "z": -31.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 32.5,
+ "y": 65.0,
+ "z": 32.5,
+ "yaw": 0.0,
+ "pitch": 0.0
}
- },
- "generator": {
- "x": -22.5312774980518,
- "y": 64.5,
- "z": -90.57548230296806,
- "yaw": 0.0,
- "pitch": 0.0
- }
+ ]
+ }
+ },
+ "sprays": []
+ }
+ },
+ {
+ "id": "rooftop",
+ "name": "Rooftop",
+ "configuration": {
+ "types": [
+ "ONE_EIGHT",
+ "TWO_EIGHT",
+ "ULTIMATE_DOUBLES"
+ ],
+ "generatorSpeed": "SLOW",
+ "bounds": {
+ "x": {
+ "min": -100.0,
+ "max": 100.0
},
- "WHITE": {
+ "y": {
+ "min": -100.0,
+ "max": 100.0
+ },
+ "z": {
+ "min": -100.0,
+ "max": 100.0
+ }
+ },
+ "teams": {
+ "RED": {
"shop": {
"item": {
- "x": -28.574379786349034,
- "y": 65.0,
- "z": 89.02285078530015,
- "yaw": -89.836914,
- "pitch": -1.0500664
+ "x": -27.561475984770826,
+ "y": 66.0,
+ "z": -90.03896114532824,
+ "yaw": 90.00113,
+ "pitch": -1.650014
},
"team": {
- "x": -17.461621765421107,
- "y": 65.0,
- "z": 88.943122501835,
- "yaw": 90.763306,
- "pitch": 2.5499506
+ "x": -39.45869286910505,
+ "y": 66.0,
+ "z": -90.06382595988917,
+ "yaw": -90.449036,
+ "pitch": -1.2000538
}
},
"spawn": {
- "x": -22.471525601515623,
- "y": 65.0,
- "z": 89.57296851701679,
- "yaw": 178.80945,
- "pitch": -2.8500109
+ "x": -33.48309695078257,
+ "y": 66.0,
+ "z": -91.54055720728049,
+ "yaw": 0.30688477,
+ "pitch": -1.6500056
},
"bed": {
"feet": {
- "x": -23,
+ "x": -34,
"y": 66,
- "z": 75
+ "z": -79
},
"head": {
- "x": -23,
+ "x": -34,
"y": 66,
- "z": 76
+ "z": -80
}
},
"generator": {
- "x": -22.412900889637193,
- "y": 64.5,
- "z": 91.23618220055619,
+ "x": -33.485051017717964,
+ "y": 65.5,
+ "z": -95.01473898708973,
"yaw": 0.0,
"pitch": 0.0
}
@@ -1677,373 +1951,307 @@
"BLUE": {
"shop": {
"item": {
- "x": 35.485826946930615,
- "y": 65.0,
- "z": -88.04529512429717,
- "yaw": 89.87683,
- "pitch": 0.14996125
+ "x": 40.398926387768824,
+ "y": 66.0,
+ "z": -89.99768047458974,
+ "yaw": 89.55142,
+ "pitch": -1.6500026
},
"team": {
- "x": 24.622361774925704,
- "y": 65.0,
- "z": -88.05656319005925,
- "yaw": -90.5741,
- "pitch": -1.3499969
+ "x": 28.46443708132082,
+ "y": 66.0,
+ "z": -90.01183225196914,
+ "yaw": -89.998535,
+ "pitch": -2.8500068
}
},
"spawn": {
- "x": 29.49428195060743,
- "y": 65.0,
- "z": -88.48868721971608,
- "yaw": 0.17382812,
- "pitch": -0.90002465
+ "x": 34.509823644268536,
+ "y": 66.0,
+ "z": -91.5133869660805,
+ "yaw": 0.30786133,
+ "pitch": -2.850025
},
"bed": {
"feet": {
- "x": 29,
+ "x": 34,
"y": 66,
- "z": -75
+ "z": -79
},
"head": {
- "x": 29,
+ "x": 34,
"y": 66,
- "z": -76
+ "z": -80
}
},
"generator": {
- "x": 29.49800786315674,
- "y": 64.5,
- "z": -90.49292341421382,
+ "x": 34.47463065480749,
+ "y": 65.5,
+ "z": -95.02582147275443,
"yaw": 0.0,
"pitch": 0.0
}
},
- "AQUA": {
+ "GREEN": {
"shop": {
"item": {
- "x": 23.46475353590089,
- "y": 65.0,
- "z": 89.00416751918755,
- "yaw": -89.68347,
- "pitch": -0.90002316
+ "x": 90.97755565005453,
+ "y": 66.0,
+ "z": -27.37446350690706,
+ "yaw": 178.95184,
+ "pitch": -1.1999909
},
"team": {
- "x": 34.48868965579855,
- "y": 65.0,
- "z": 88.9687709421603,
- "yaw": 90.31177,
- "pitch": -0.45002592
+ "x": 91.01148627742812,
+ "y": 66.0,
+ "z": -39.56285225865746,
+ "yaw": -0.14828491,
+ "pitch": -1.3499583
}
},
"spawn": {
- "x": 29.51989114105056,
- "y": 65.0,
- "z": 89.5076579294666,
- "yaw": -179.83789,
- "pitch": -1.5000246
+ "x": 92.35244930696713,
+ "y": 66.0,
+ "z": -33.540694954234894,
+ "yaw": 89.85184,
+ "pitch": -0.9000325
},
"bed": {
"feet": {
- "x": 29,
+ "x": 79,
"y": 66,
- "z": 75
+ "z": -34
},
"head": {
- "x": 29,
+ "x": 80,
"y": 66,
- "z": 76
+ "z": -34
}
},
"generator": {
- "x": 29.51437547667322,
- "y": 64.5,
- "z": 91.54059238014068,
+ "x": 96.00864187672953,
+ "y": 65.5,
+ "z": -33.500482460514114,
"yaw": 0.0,
"pitch": 0.0
}
- }
- },
- "locations": {
- "waiting": {
- "x": 0.0,
- "y": 118.0,
- "z": 0.0,
- "yaw": 0.0,
- "pitch": 0.0
- },
- "spectator": {
- "x": 0.0,
- "y": 103.0,
- "z": 0.0,
- "yaw": 0.0,
- "pitch": 0.0
- }
- },
- "globalGenerator": {
- "DIAMOND": {
- "locations": [
- {
- "x": -48.5,
- "y": 67.0,
- "z": -51.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": -48.5,
- "y": 67.0,
- "z": 52.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 55.5,
- "y": 67.0,
- "z": -51.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 55.5,
- "y": 67.0,
- "z": 52.5,
- "yaw": 0.0,
- "pitch": 0.0
- }
- ]
},
- "EMERALD": {
- "locations": [
- {
- "x": -6.5,
- "y": 65.0,
- "z": 14.5,
- "yaw": 0.0,
- "pitch": 0.0
- },
- {
- "x": 3.5,
- "y": 87.0,
- "z": -6.5,
- "yaw": 0.0,
- "pitch": 0.0
+ "YELLOW": {
+ "shop": {
+ "item": {
+ "x": 90.99918379500014,
+ "y": 66.0,
+ "z": 40.58232810998059,
+ "yaw": -179.9967,
+ "pitch": -0.45014584
},
- {
- "x": 13.5,
- "y": 65.0,
- "z": -13.5,
- "yaw": 0.0,
- "pitch": 0.0
+ "team": {
+ "x": 91.0230495348164,
+ "y": 66.0,
+ "z": 28.463560410301472,
+ "yaw": 0.7530823,
+ "pitch": -2.4001167
+ }
+ },
+ "spawn": {
+ "x": 92.47357850698647,
+ "y": 66.0,
+ "z": 34.47878025929901,
+ "yaw": 89.404785,
+ "pitch": -2.100014
+ },
+ "bed": {
+ "feet": {
+ "x": 79,
+ "y": 66,
+ "z": 34
},
- {
- "x": 3.5,
- "y": 87.0,
- "z": 7.5,
- "yaw": 0.0,
- "pitch": 0.0
+ "head": {
+ "x": 80,
+ "y": 66,
+ "z": 34
}
- ]
- }
- }
- }
- },
- {
- "id": "haven",
- "name": "haven",
- "configuration": {
- "types": [
- "THREE_THREE_THREE_THREE",
- "FOUR_FOUR_FOUR_FOUR",
- "LUCKY_BLOCK_DOUBLES"
- ],
- "generatorSpeed": "SLOW",
- "bounds": {
- "x": {
- "min": -125.0,
- "max": 125.0
- },
- "y": {
- "min": 0.0,
- "max": 100.0
+ },
+ "generator": {
+ "x": 96.02934179770598,
+ "y": 65.5,
+ "z": 34.455781204997784,
+ "yaw": 0.0,
+ "pitch": 0.0
+ }
},
- "z": {
- "min": -125.0,
- "max": 125.0
- }
- },
- "teams": {
- "RED": {
+ "AQUA": {
"shop": {
"item": {
- "x": -5.643081030208206,
- "y": 48.0,
- "z": 105.00760245533807,
- "yaw": -0.45004654,
- "pitch": -89.55029
+ "x": 28.41990219468591,
+ "y": 66.0,
+ "z": 91.06331403239552,
+ "yaw": -91.04541,
+ "pitch": -2.7000225
},
"team": {
- "x": 6.513037234763775,
- "y": 48.0,
- "z": 104.95045523360692,
- "yaw": -0.60003746,
- "pitch": 90.29947
+ "x": 40.36172087467049,
+ "y": 66.0,
+ "z": 91.06411210174763,
+ "yaw": 90.15213,
+ "pitch": -0.90007347
}
},
"spawn": {
- "x": 0.4566740272757841,
- "y": 48.0,
- "z": 104.57865104045052,
- "yaw": -0.9000152,
- "pitch": 0
+ "x": 34.524004250348334,
+ "y": 66.0,
+ "z": 92.45408851220344,
+ "yaw": -179.84644,
+ "pitch": -1.2000084
},
"bed": {
"feet": {
- "x": 0,
- "y": 46,
- "z": 90
+ "x": 34,
+ "y": 66,
+ "z": 79
},
"head": {
- "x": 0,
- "y": 46,
- "z": 91
+ "x": 34,
+ "y": 66,
+ "z": 80
}
},
"generator": {
- "x": 0.48311192527610214,
- "y": 47.5,
- "z": 109.40563123435935,
+ "x": 34.5195493015554,
+ "y": 65.5,
+ "z": 96.01884606329925,
"yaw": 0.0,
"pitch": 0.0
}
},
- "BLUE": {
+ "WHITE": {
"shop": {
"item": {
- "x": -104.00200548536833,
- "y": 48.0,
- "z": -5.511538167515957,
- "yaw": -0.8999911,
- "pitch": 0.1472168
+ "x": -39.619789596622844,
+ "y": 66.0,
+ "z": 90.99516710124517,
+ "yaw": -90.1427,
+ "pitch": -2.400028
},
"team": {
- "x": -103.97642442586424,
- "y": 48.0,
- "z": 6.530339403426724,
- "yaw": 0.3000191,
- "pitch": -179.70227
+ "x": -27.537757646848167,
+ "y": 66.0,
+ "z": 90.99331226247274,
+ "yaw": 89.258545,
+ "pitch": -0.15004088
}
},
"spawn": {
- "x": -104.00035970966859,
- "y": 48.0,
- "z": 0.4982683648858232,
- "yaw": 0.44997922,
- "pitch": 0
+ "x": -33.41090708421141,
+ "y": 66.0,
+ "z": 92.54655583931589,
+ "yaw": 179.25671,
+ "pitch": -1.9500283
},
"bed": {
"feet": {
- "x": -90,
- "y": 46,
- "z": 0
+ "x": -34,
+ "y": 66,
+ "z": 79
},
"head": {
- "x": -91,
- "y": 46,
- "z": 0
+ "x": -34,
+ "y": 66,
+ "z": 80
}
},
"generator": {
- "x": -108.44139800163269,
- "y": 47.5,
- "z": 0.5066969091555289,
+ "x": -33.50603971043999,
+ "y": 65.5,
+ "z": 96.0181903162085,
"yaw": 0.0,
"pitch": 0.0
}
},
- "GREEN": {
+ "PINK": {
"shop": {
"item": {
- "x": 6.452209881084259,
- "y": 48.0,
- "z": -103.97213185082639,
- "yaw": 0.14998366,
- "pitch": 89.99768
+ "x": -89.98054541737716,
+ "y": 66.0,
+ "z": 28.467331158132353,
+ "yaw": -0.29211426,
+ "pitch": -1.3499774
},
"team": {
- "x": -5.486204346304282,
- "y": 48.0,
- "z": -104.06431278356358,
- "yaw": -0.6000095,
- "pitch": -89.552734
+ "x": -90.0204986863301,
+ "y": 66.0,
+ "z": 40.539796055189804,
+ "yaw": -179.84265,
+ "pitch": -0.5999382
}
},
"spawn": {
- "x": 0.4816414347717442,
- "y": 48.0,
- "z": -103.96215353598399,
- "yaw": -0.4500038,
- "pitch": 0.14782715
+ "x": -91.52177451771917,
+ "y": 66.0,
+ "z": 34.55702213652238,
+ "yaw": -90.14459,
+ "pitch": -2.250019
},
"bed": {
"feet": {
- "x": 0,
- "y": 46,
- "z": -90
+ "x": -79,
+ "y": 66,
+ "z": 34
},
"head": {
- "x": 0,
- "y": 46,
- "z": -91
+ "x": -80,
+ "y": 66,
+ "z": 34
}
},
"generator": {
- "x": 0.47573204880919545,
- "y": 47.5,
- "z": -108.50300788140555,
+ "x": -95.00606472183632,
+ "y": 65.5,
+ "z": 34.472998109442024,
"yaw": 0.0,
"pitch": 0.0
}
},
- "YELLOW": {
+ "GRAY": {
"shop": {
"item": {
- "x": 104.98711045888756,
- "y": 48.0,
- "z": 6.566614067860879,
- "yaw": -1.0500069,
- "pitch": 179.09155
+ "x": -90.01983756947546,
+ "y": 66.0,
+ "z": -39.42647039169151,
+ "yaw": -0.44920057,
+ "pitch": -1.650027
},
"team": {
- "x": 104.96962792336748,
- "y": 48.0,
- "z": -5.542657550120672,
- "yaw": 0.6000119,
- "pitch": -0.4584961
+ "x": -89.968787336429,
+ "y": 66.0,
+ "z": -27.526147971256428,
+ "yaw": -179.699,
+ "pitch": -1.6500026
}
},
"spawn": {
- "x": 104.90221295849302,
- "y": 48.0,
- "z": 0.5618568772327801,
- "yaw": 0.74996793,
- "pitch": 91.04187
+ "x": -91.50789125537915,
+ "y": 66.0,
+ "z": -33.4614884673225,
+ "yaw": -89.69918,
+ "pitch": -2.2500162
},
"bed": {
"feet": {
- "x": 90,
- "y": 46,
- "z": 0
+ "x": -79,
+ "y": 66,
+ "z": -34
},
"head": {
- "x": 91,
- "y": 46,
- "z": 0
+ "x": -80,
+ "y": 66,
+ "z": -34
}
},
"generator": {
- "x": 109.46146206656485,
- "y": 47.5,
- "z": 0.5320753244557163,
+ "x": -94.88180199559939,
+ "y": 65.5,
+ "z": -33.47895599279666,
"yaw": 0.0,
"pitch": 0.0
}
@@ -2051,34 +2259,60 @@
},
"locations": {
"waiting": {
- "x": 0.45753038265154733,
- "y": 120.0,
- "z": 0.49395332083443444,
+ "x": 0.0,
+ "y": 118.0,
+ "z": 0.0,
"yaw": 0.0,
"pitch": 0.0
},
"spectator": {
- "x": 0.0,
- "y": 70.0,
- "z": 0.0,
+ "x": 3.5,
+ "y": 81.0,
+ "z": 3.5,
"yaw": 0.0,
"pitch": 0.0
+ },
+ "waitingLobby": {
+ "min": {
+ "x": -16,
+ "y": 110,
+ "z": -15
+ },
+ "max": {
+ "x": 19,
+ "y": 134,
+ "z": 15
+ }
}
},
"globalGenerator": {
"EMERALD": {
"locations": [
{
- "x": 0.5,
- "y": 51.0,
- "z": -8.5,
+ "x": -10.5,
+ "y": 71.0,
+ "z": -12.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 0.5,
- "y": 51.0,
- "z": 9.5,
+ "x": -10.5,
+ "y": 80.0,
+ "z": -10.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 11.5,
+ "y": 80.0,
+ "z": 11.5,
+ "yaw": 0.0,
+ "pitch": 0.0
+ },
+ {
+ "x": 11.5,
+ "y": 71.0,
+ "z": 13.5,
"yaw": 0.0,
"pitch": 0.0
}
@@ -2087,226 +2321,38 @@
"DIAMOND": {
"locations": [
{
- "x": -42.5,
- "y": 48.0,
- "z": -42.5,
+ "x": -38.5,
+ "y": 71.0,
+ "z": -38.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": -42.5,
- "y": 48.0,
- "z": 43.5,
+ "x": -38.5,
+ "y": 71.0,
+ "z": 39.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 43.5,
- "y": 48.0,
- "z": -42.5,
+ "x": 39.5,
+ "y": 71.0,
+ "z": -38.5,
"yaw": 0.0,
"pitch": 0.0
},
{
- "x": 43.5,
- "y": 48.0,
- "z": 43.5,
+ "x": 39.5,
+ "y": 71.0,
+ "z": 39.5,
"yaw": 0.0,
"pitch": 0.0
}
]
}
- }
- }
- },
- {
- "id": "one_block",
- "name": "One Block",
- "configuration": {
- "types": [
- "ONE_BLOCK"
- ],
- "bounds": {
- "x": {
- "min": -100.0,
- "max": 100.0
- },
- "y": {
- "min": 0.0,
- "max": 150.0
- },
- "z": {
- "min": -100.0,
- "max": 100.0
- }
- },
- "teams": {
- "BLUE": {
- "spawn": {
- "x": 18.0,
- "y": 72.0,
- "z": -9.0
- },
- "bed": {
- "feet": {
- "x": 18,
- "y": 71,
- "z": -9
- },
- "head": {
- "x": 17,
- "y": 71,
- "z": -9
- }
- }
- },
- "RED": {
- "spawn": {
- "x": 18.0,
- "y": 72.0,
- "z": 8.0
- },
- "bed": {
- "feet": {
- "x": 18,
- "y": 71,
- "z": 8
- },
- "head": {
- "x": 17,
- "y": 71,
- "z": 8
- }
- }
- },
- "GRAY": {
- "spawn": {
- "x": 8.0,
- "y": 72.0,
- "z": 18.0
- },
- "bed": {
- "feet": {
- "x": 8,
- "y": 71,
- "z": 18
- },
- "head": {
- "x": 8,
- "y": 71,
- "z": 17
- }
- }
- },
- "PINK": {
- "spawn": {
- "x": -9.0,
- "y": 72.0,
- "z": 18.0
- },
- "bed": {
- "feet": {
- "x": -9,
- "y": 71,
- "z": 18
- },
- "head": {
- "x": -9,
- "y": 71,
- "z": 17
- }
- }
- },
- "WHITE": {
- "spawn": {
- "x": -19.0,
- "y": 72.0,
- "z": 8.0
- },
- "bed": {
- "feet": {
- "x": -19,
- "y": 71,
- "z": 8
- },
- "head": {
- "x": -18,
- "y": 71,
- "z": 8
- }
- }
- },
- "AQUA": {
- "spawn": {
- "x": -19.0,
- "y": 72.0,
- "z": -9.0
- },
- "bed": {
- "feet": {
- "x": -19,
- "y": 71,
- "z": -9
- },
- "head": {
- "x": -18,
- "y": 71,
- "z": -9
- }
- }
- },
- "YELLOW": {
- "spawn": {
- "x": -9.0,
- "y": 72.0,
- "z": -19.0
- },
- "bed": {
- "feet": {
- "x": -9,
- "y": 71,
- "z": -19
- },
- "head": {
- "x": -9,
- "y": 71,
- "z": -18
- }
- }
- },
- "GREEN": {
- "spawn": {
- "x": 8.0,
- "y": 72.0,
- "z": -19.0
- },
- "bed": {
- "feet": {
- "x": 8,
- "y": 71,
- "z": -19
- },
- "head": {
- "x": 8,
- "y": 71,
- "z": -18
- }
- }
- }
},
- "locations": {
- "waiting": {
- "x": 0.0,
- "y": 99.0,
- "z": 6.0
- },
- "spectator": {
- "x": 0.0,
- "y": 99.0,
- "z": 6.0
- }
- }
+ "sprays": []
}
}
]
-}
+}
\ No newline at end of file
diff --git a/configuration/i18n/en_US/official/replays.properties b/configuration/i18n/en_US/official/replays.properties
index 4486f5b31b..12cf71ea81 100644
--- a/configuration/i18n/en_US/official/replays.properties
+++ b/configuration/i18n/en_US/official/replays.properties
@@ -1,123 +1,217 @@
-replays.0="You are already viewing that replay!"
-replays.1="Ran by %%player%%"
-replays.2="Cinematic Cameras (BETA)"
-replays.3="Click to report!"
-replays.4="Play Recording Again"
-replays.5="Left Click to go to this time!"
-replays.6="You can't decrease the speed any lower!"
-replays.7="Report %%name%%"
-replays.8="This replay is too short to render a timeline"
-replays.9="%%value%%s Backwards"
-replays.10="%%name%% disabled!"
-replays.11="No replayer found?!"
-replays.12="Click to leave!"
-replays.13="You can't increase the speed any higher!"
-replays.14="Click to read more about the Replay Viewer"
-replays.15="Teleport to Player"
-replays.16="Manage your settings for viewing replays."
-replays.17="Settings"
-replays.18="you"
-replays.19="Replay Viewer"
-replays.20="%%value%%s Forward"
-replays.21="Click to put in chat!"
-replays.22="Click to Stop"
-replays.23="More"
-replays.24="The Replay you were in has been shut down!"
-replays.25="Currently Selected: %%option%%"
-replays.26="You can't report yourself!"
-replays.27="Click here to put share command in chat!"
-replays.28="Click to Resume"
-replays.29="Click to share!"
-replays.30="Report Player"
-replays.31="You were kicked for inactivity! "
-replays.32="That player has despawned!"
-replays.33="Usage: /tp [target player]"
-replays.34="Click to Pause"
-replays.35="Time: %%time%% seconds"
-replays.36="You cannot share this replay!"
-replays.37="Unable to submit the report right now, please try again shortly!"
-replays.38="Viewer Settings"
-replays.39="This instance doesn't have a replay for you. If this keeps happening please report this."
-replays.40="Report this player for %%type%%."
-replays.41="You will be afk-ed in 10 seconds!"
-replays.42="No bookmarks!"
-replays.43="View bookmarks for this recording."
-replays.44="No bookmarks found!"
-replays.45="Left Click to teleport!"
-replays.46="You were kicked due to having a replay open for too long! "
-replays.47="Hypixel Replay Viewer"
-replays.48=" READ MORE"
-replays.49="Share this replay along with your current timestamp and location."
-replays.50="Reporting via replays is currently disabled, please try again later!"
-replays.51="You do not have permission to watch replays."
-replays.52="No players found!"
-replays.53="Decrease Speed"
-replays.54="Hypixel Replay is in BETA! Please report bugs at https://hypixel.net/bugs"
-replays.55="Right Click to share!"
-replays.56="%%player%% ran command /%%command%%"
-replays.57="Right Click for first person!"
-replays.58="Bookmarks"
-replays.59="Thank you for your report against %%name%%! This replay will be submitted along with the report."
-replays.60="Click to set %%setting%% to %%option%%"
-replays.61="Player: %%player%%"
-replays.62="No replayer!"
-replays.63="Bookmark created!"
-replays.64="Please wait a little before using that!"
-replays.65="You went too far away from the map!"
-replays.66="Share"
-replays.67="You have been kicked as the replay was open for too long!"
-replays.68="Increase Speed"
-replays.69="Teleporting %%name%% to %%destination%%"
-replays.70="%%color%%%%name%%"
-replays.71="Leave Replay"
-replays.72="%%name%% enabled!"
-replays.73="No replayer?!"
-replays.74="I don't know where you want to teleport to!"
-replays.75="You cannot create bookmarks for this replay!"
-replays.76="Report this player for breaking the rules. This replay will be saved along with the report to be reviewed."
-replays.77="Waiting"
-replays.78="Playing"
-replays.79="Paused"
-replays.80="Finished"
-replays.81="You have hit the limit of active highlights! Please try again another time!"
-replays.82="Highlight submitted!"
-replays.83="Submit Highlight"
-replays.84="Did something cool? Share your current timestamp and location with us for a chance to be showcased on Hypixel social media!"
-replays.85="By submitting this highlight, you agree to the Hypixel Server potentially using this content on the Hypixel Twitter, TikTok, Instagram, or other social media platform. Make sure you are in the right location and time to showcase your highlight!"
-replays.86="Click to submit!"
-replays.87="Left click to change the duration."
-replays.88="Date: "
-replays.89="Time: "
-replays.90="Failed to do that, please try again shortly.!"
-replays.91="Loading replay ..."
-replays.92="Map: "
-replays.93="Game: "
-replays.94="You need to be playing Minecraft with protocol version %%version%% or higher to view this replay."
-replays.95="The replay is currently paused."
-replays.96="Longest Tick: "
-replays.97="The replay is currently stopped."
-replays.98="Middle Click to put UUID in chat!"
-replays.99="Submit Verdict"
-replays.100="Replay"
-replays.101="You need to be playing Minecraft version %%version%% or higher to view this replay."
-replays.102="Detection: %%detection%%"
-replays.103="Mode: "
-replays.104="Found bookmark matching player... skipping to %%ticks%% ticks!"
-replays.105="Players"
-replays.106="Replay from "
-replays.107="Chat Messages"
-replays.108="Toggle chat messages such as kills and other actions in the game."
-replays.109="Chat Timeline"
-replays.110="Toggle a timeline of the replay which is displayed via the chat."
-replays.111="Show Spectators"
-replays.112="Toggle the ability to see spectators from the replay."
-replays.113="Night Vision"
-replays.114="Toggle having night vision when watching a replay."
-replays.115="Fly Speed"
-replays.116="Skip Intervals"
-replays.117="Food Level: %%level%%"
-replays.118="Show Particles"
-replays.119="Toggle showing particles when watching a replay."
-replays.120="Change the speed you fly at in the replay."
-replays.121="Change the interval used when using the forward & backward buttons. Can also be toggled by left clicking the buttons themselves."
-replays.122="Toggle the time on the scoreboard advancing while the replay is being played."
\ No newline at end of file
+replays.already_viewing="You are already viewing that replay!"
+replays.ran_by="Ran by "
+replays.cinematic_cameras="Cinematic Cameras (BETA)"
+replays.click_to_report="Click to report!"
+replays.play_recording_again="Play Recording Again"
+replays.click_to_seek="Left Click to go to this time!"
+replays.speed_minimum="You can't decrease the speed any lower!"
+replays.report_named_player="Report "
+replays.timeline_too_short="This replay is too short to render a timeline"
+replays.skip_backward="s Backwards"
+replays.feature_disabled=" disabled!"
+replays.no_replayer_found="No replayer found?!"
+replays.click_to_leave="Click to leave!"
+replays.speed_maximum="You can't increase the speed any higher!"
+replays.replay_viewer_learn_more="Click to read more about the Replay Viewer"
+replays.teleport_to_player="Teleport to Player"
+replays.settings_description="Manage your settings for viewing replays."
+replays.settings="Settings"
+replays.you="you"
+replays.replay_viewer="Replay Viewer"
+replays.skip_forward="s Forward"
+replays.click_to_put_in_chat="Click to put in chat!"
+replays.click_to_stop="Click to Stop"
+replays.more="More"
+replays.replay_shutdown="The Replay you were in has been shut down!"
+replays.currently_selected="Currently Selected: