mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
Dont ask
This commit is contained in:
1 parent
d1fec88769
commit
0a7a531646
259 files changed
+11055
-884
No files matched your search
@@ -34,6 +34,10 @@ public final class IrisPlatforms {
|
||||
platform = p;
|
||||
}
|
||||
|
||||
public static synchronized void unbind() {
|
||||
platform = null;
|
||||
}
|
||||
|
||||
public static IrisPlatform get() {
|
||||
IrisPlatform bound = platform;
|
||||
if (bound == null) {
|
||||
|
||||
@@ -38,6 +38,15 @@ public final class IrisServices {
|
||||
return type.cast(implementation);
|
||||
}
|
||||
|
||||
public static <T> T getOrNull(Class<T> type) {
|
||||
Object implementation = SERVICES.get(type);
|
||||
return implementation == null ? null : type.cast(implementation);
|
||||
}
|
||||
|
||||
public static void remove(Class<?> type) {
|
||||
SERVICES.remove(type);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
SERVICES.clear();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PlatformBlockProperty(String name, String jsonType, Object defaultValue, List<Object> allowedValues, PlatformNumericRange numericRange) {
|
||||
public boolean hasNumericRange() {
|
||||
return numericRange != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi;
|
||||
|
||||
public record PlatformNumericRange(double minimum, double maximum, boolean exclusiveMinimum, boolean exclusiveMaximum) {
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.spi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Resolves namespaced string keys against the platform's live registries into interned neutral handles.
|
||||
@@ -45,4 +46,16 @@ public interface PlatformRegistries {
|
||||
List<String> biomeKeys();
|
||||
|
||||
List<String> structureKeys();
|
||||
|
||||
List<String> itemKeys();
|
||||
|
||||
List<String> entityKeys();
|
||||
|
||||
List<String> blockTypeKeys();
|
||||
|
||||
List<String> enchantmentKeys();
|
||||
|
||||
List<String> potionEffectKeys();
|
||||
|
||||
Map<String, List<PlatformBlockProperty>> blockStateProperties();
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public sealed interface IrisMessage {
|
||||
int messageTypeId();
|
||||
|
||||
record ClientHello(int protocolVersion, long capabilities) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_CLIENT_HELLO;
|
||||
}
|
||||
}
|
||||
|
||||
record ServerHello(int protocolVersion, long capabilities, String serverBrand, boolean irisActive) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_SERVER_HELLO;
|
||||
}
|
||||
}
|
||||
|
||||
record PregenProgress(long jobId, long chunksDone, long chunksTotal, double chunksPerSecond, long etaMillis, int state) implements IrisMessage {
|
||||
public static final int STATE_RUNNING = 0;
|
||||
public static final int STATE_PAUSED = 1;
|
||||
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_PREGEN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
record PregenEnd(long jobId, boolean completed) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_PREGEN_END;
|
||||
}
|
||||
}
|
||||
|
||||
record DimensionStatus(String dimensionKey, String packKey, long seed, int minY, int maxY, boolean irisWorld) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_DIMENSION_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
record CursorInfoRequest(int blockX, int blockZ) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_CURSOR_INFO_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
record CursorInfo(int blockX, int blockZ, String biomeKey, String regionKey, String caveBiomeKey, int height, String dimensionKey) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_CURSOR_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
record VisionTileRequest(int tileX, int tileZ, int zoomLevel) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_VISION_TILE_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
record VisionTile(int tileX, int tileZ, int zoomLevel, int sequence, int chunkIndex, int chunkCount, byte[] data) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_VISION_TILE;
|
||||
}
|
||||
}
|
||||
|
||||
record VisionMarkers(int tileX, int tileZ, int zoomLevel, List<Marker> markers) implements IrisMessage {
|
||||
public record Marker(int blockX, int blockZ, int kind, String label) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_VISION_MARKERS;
|
||||
}
|
||||
}
|
||||
|
||||
record PregenRegionDelta(long jobId, int regionX, int regionZ, int state) implements IrisMessage {
|
||||
public static final int STATE_PENDING = 0;
|
||||
public static final int STATE_GENERATING = 1;
|
||||
public static final int STATE_DONE = 2;
|
||||
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_PREGEN_REGION_DELTA;
|
||||
}
|
||||
}
|
||||
|
||||
record StudioHotload(String packKey, int changedFiles, boolean failed, String message) implements IrisMessage {
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_STUDIO_HOTLOAD;
|
||||
}
|
||||
}
|
||||
|
||||
record Toast(int kind, String title, String body) implements IrisMessage {
|
||||
public static final int KIND_INFO = 0;
|
||||
public static final int KIND_SUCCESS = 1;
|
||||
public static final int KIND_WARNING = 2;
|
||||
public static final int KIND_ERROR = 3;
|
||||
|
||||
@Override
|
||||
public int messageTypeId() {
|
||||
return IrisProtocol.TYPE_TOAST;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class IrisMessageCodec {
|
||||
private IrisMessageCodec() {
|
||||
}
|
||||
|
||||
public static byte[] encode(IrisMessage message) {
|
||||
IrisWireWriter writer = new IrisWireWriter();
|
||||
writer.writeVarInt(message.messageTypeId());
|
||||
switch (message) {
|
||||
case IrisMessage.ClientHello clientHello -> {
|
||||
writer.writeInt(clientHello.protocolVersion());
|
||||
writer.writeLong(clientHello.capabilities());
|
||||
}
|
||||
case IrisMessage.ServerHello serverHello -> {
|
||||
writer.writeInt(serverHello.protocolVersion());
|
||||
writer.writeLong(serverHello.capabilities());
|
||||
writer.writeString(serverHello.serverBrand());
|
||||
writer.writeBoolean(serverHello.irisActive());
|
||||
}
|
||||
case IrisMessage.PregenProgress pregenProgress -> {
|
||||
writer.writeLong(pregenProgress.jobId());
|
||||
writer.writeLong(pregenProgress.chunksDone());
|
||||
writer.writeLong(pregenProgress.chunksTotal());
|
||||
writer.writeDouble(pregenProgress.chunksPerSecond());
|
||||
writer.writeLong(pregenProgress.etaMillis());
|
||||
writer.writeInt(pregenProgress.state());
|
||||
}
|
||||
case IrisMessage.PregenEnd pregenEnd -> {
|
||||
writer.writeLong(pregenEnd.jobId());
|
||||
writer.writeBoolean(pregenEnd.completed());
|
||||
}
|
||||
case IrisMessage.DimensionStatus dimensionStatus -> {
|
||||
writer.writeString(dimensionStatus.dimensionKey());
|
||||
writer.writeString(dimensionStatus.packKey());
|
||||
writer.writeLong(dimensionStatus.seed());
|
||||
writer.writeInt(dimensionStatus.minY());
|
||||
writer.writeInt(dimensionStatus.maxY());
|
||||
writer.writeBoolean(dimensionStatus.irisWorld());
|
||||
}
|
||||
case IrisMessage.CursorInfoRequest cursorInfoRequest -> {
|
||||
writer.writeInt(cursorInfoRequest.blockX());
|
||||
writer.writeInt(cursorInfoRequest.blockZ());
|
||||
}
|
||||
case IrisMessage.CursorInfo cursorInfo -> {
|
||||
writer.writeInt(cursorInfo.blockX());
|
||||
writer.writeInt(cursorInfo.blockZ());
|
||||
writer.writeString(cursorInfo.biomeKey());
|
||||
writer.writeString(cursorInfo.regionKey());
|
||||
writer.writeString(cursorInfo.caveBiomeKey());
|
||||
writer.writeInt(cursorInfo.height());
|
||||
writer.writeString(cursorInfo.dimensionKey());
|
||||
}
|
||||
case IrisMessage.VisionTileRequest visionTileRequest -> {
|
||||
writer.writeInt(visionTileRequest.tileX());
|
||||
writer.writeInt(visionTileRequest.tileZ());
|
||||
writer.writeInt(visionTileRequest.zoomLevel());
|
||||
}
|
||||
case IrisMessage.VisionTile visionTile -> {
|
||||
writer.writeInt(visionTile.tileX());
|
||||
writer.writeInt(visionTile.tileZ());
|
||||
writer.writeInt(visionTile.zoomLevel());
|
||||
writer.writeInt(visionTile.sequence());
|
||||
writer.writeInt(visionTile.chunkIndex());
|
||||
writer.writeInt(visionTile.chunkCount());
|
||||
writer.writeBytes(visionTile.data());
|
||||
}
|
||||
case IrisMessage.VisionMarkers visionMarkers -> {
|
||||
writer.writeInt(visionMarkers.tileX());
|
||||
writer.writeInt(visionMarkers.tileZ());
|
||||
writer.writeInt(visionMarkers.zoomLevel());
|
||||
List<IrisMessage.VisionMarkers.Marker> markers = visionMarkers.markers();
|
||||
writer.writeVarInt(markers.size());
|
||||
for (IrisMessage.VisionMarkers.Marker marker : markers) {
|
||||
writer.writeInt(marker.blockX());
|
||||
writer.writeInt(marker.blockZ());
|
||||
writer.writeInt(marker.kind());
|
||||
writer.writeString(marker.label());
|
||||
}
|
||||
}
|
||||
case IrisMessage.PregenRegionDelta pregenRegionDelta -> {
|
||||
writer.writeLong(pregenRegionDelta.jobId());
|
||||
writer.writeInt(pregenRegionDelta.regionX());
|
||||
writer.writeInt(pregenRegionDelta.regionZ());
|
||||
writer.writeInt(pregenRegionDelta.state());
|
||||
}
|
||||
case IrisMessage.StudioHotload studioHotload -> {
|
||||
writer.writeString(studioHotload.packKey());
|
||||
writer.writeInt(studioHotload.changedFiles());
|
||||
writer.writeBoolean(studioHotload.failed());
|
||||
writer.writeString(studioHotload.message());
|
||||
}
|
||||
case IrisMessage.Toast toast -> {
|
||||
writer.writeInt(toast.kind());
|
||||
writer.writeString(toast.title());
|
||||
writer.writeString(toast.body());
|
||||
}
|
||||
}
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
public static IrisMessage decode(byte[] frame) throws ProtocolException {
|
||||
if (frame == null) {
|
||||
throw new ProtocolException("null frame");
|
||||
}
|
||||
if (frame.length > IrisProtocol.MAX_FRAME_BYTES) {
|
||||
throw new ProtocolException("frame exceeds " + IrisProtocol.MAX_FRAME_BYTES + " byte cap");
|
||||
}
|
||||
IrisWireReader reader = new IrisWireReader(frame);
|
||||
int messageTypeId = reader.readVarInt();
|
||||
return switch (messageTypeId) {
|
||||
case IrisProtocol.TYPE_CLIENT_HELLO -> new IrisMessage.ClientHello(reader.readInt(), reader.readLong());
|
||||
case IrisProtocol.TYPE_SERVER_HELLO -> new IrisMessage.ServerHello(reader.readInt(), reader.readLong(), reader.readString(), reader.readBoolean());
|
||||
case IrisProtocol.TYPE_PREGEN_PROGRESS -> new IrisMessage.PregenProgress(reader.readLong(), reader.readLong(), reader.readLong(), reader.readDouble(), reader.readLong(), reader.readInt());
|
||||
case IrisProtocol.TYPE_PREGEN_END -> new IrisMessage.PregenEnd(reader.readLong(), reader.readBoolean());
|
||||
case IrisProtocol.TYPE_DIMENSION_STATUS -> new IrisMessage.DimensionStatus(reader.readString(), reader.readString(), reader.readLong(), reader.readInt(), reader.readInt(), reader.readBoolean());
|
||||
case IrisProtocol.TYPE_CURSOR_INFO_REQUEST -> new IrisMessage.CursorInfoRequest(reader.readInt(), reader.readInt());
|
||||
case IrisProtocol.TYPE_CURSOR_INFO -> new IrisMessage.CursorInfo(reader.readInt(), reader.readInt(), reader.readString(), reader.readString(), reader.readString(), reader.readInt(), reader.readString());
|
||||
case IrisProtocol.TYPE_VISION_TILE_REQUEST -> new IrisMessage.VisionTileRequest(reader.readInt(), reader.readInt(), reader.readInt());
|
||||
case IrisProtocol.TYPE_VISION_TILE -> new IrisMessage.VisionTile(reader.readInt(), reader.readInt(), reader.readInt(), reader.readInt(), reader.readInt(), reader.readInt(), reader.readBytes());
|
||||
case IrisProtocol.TYPE_VISION_MARKERS -> decodeVisionMarkers(reader);
|
||||
case IrisProtocol.TYPE_PREGEN_REGION_DELTA -> new IrisMessage.PregenRegionDelta(reader.readLong(), reader.readInt(), reader.readInt(), reader.readInt());
|
||||
case IrisProtocol.TYPE_STUDIO_HOTLOAD -> new IrisMessage.StudioHotload(reader.readString(), reader.readInt(), reader.readBoolean(), reader.readString());
|
||||
case IrisProtocol.TYPE_TOAST -> new IrisMessage.Toast(reader.readInt(), reader.readString(), reader.readString());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private static IrisMessage.VisionMarkers decodeVisionMarkers(IrisWireReader reader) throws ProtocolException {
|
||||
int tileX = reader.readInt();
|
||||
int tileZ = reader.readInt();
|
||||
int zoomLevel = reader.readInt();
|
||||
int count = reader.readVarInt();
|
||||
if (count < 0) {
|
||||
throw new ProtocolException("negative marker count");
|
||||
}
|
||||
List<IrisMessage.VisionMarkers.Marker> markers = new ArrayList<>(Math.min(count, IrisProtocol.MAX_VISION_MARKERS));
|
||||
for (int index = 0; index < count; index++) {
|
||||
markers.add(new IrisMessage.VisionMarkers.Marker(reader.readInt(), reader.readInt(), reader.readInt(), reader.readString()));
|
||||
}
|
||||
return new IrisMessage.VisionMarkers(tileX, tileZ, zoomLevel, markers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
public final class IrisProtocol {
|
||||
public static final int PROTOCOL_VERSION = 1;
|
||||
public static final String CHANNEL = "irisworldgen:main";
|
||||
public static final int MAX_FRAME_BYTES = 24576;
|
||||
public static final int MAX_INBOUND_FRAMES_PER_SECOND = 32;
|
||||
public static final int MAX_VISION_TILE_REQUESTS_PER_SECOND = 8;
|
||||
public static final int VISION_TILE_HEADER_BYTES = 25;
|
||||
public static final int VISION_TILE_MAX_CHUNK_BYTES = 24000;
|
||||
public static final int MAX_VISION_MARKERS = 256;
|
||||
public static final long CAPABILITY_PREGEN = 1L << 0;
|
||||
public static final long CAPABILITY_VISION = 1L << 1;
|
||||
public static final long CAPABILITY_CURSOR = 1L << 2;
|
||||
public static final long CAPABILITY_STUDIO = 1L << 3;
|
||||
public static final int TYPE_CLIENT_HELLO = 1;
|
||||
public static final int TYPE_SERVER_HELLO = 2;
|
||||
public static final int TYPE_PREGEN_PROGRESS = 3;
|
||||
public static final int TYPE_PREGEN_END = 4;
|
||||
public static final int TYPE_DIMENSION_STATUS = 5;
|
||||
public static final int TYPE_CURSOR_INFO_REQUEST = 6;
|
||||
public static final int TYPE_CURSOR_INFO = 7;
|
||||
public static final int TYPE_VISION_TILE_REQUEST = 8;
|
||||
public static final int TYPE_VISION_TILE = 9;
|
||||
public static final int TYPE_VISION_MARKERS = 10;
|
||||
public static final int TYPE_PREGEN_REGION_DELTA = 11;
|
||||
public static final int TYPE_STUDIO_HOTLOAD = 12;
|
||||
public static final int TYPE_TOAST = 13;
|
||||
|
||||
private IrisProtocol() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public final class IrisWireReader {
|
||||
private final byte[] frame;
|
||||
private final int limit;
|
||||
private int position;
|
||||
|
||||
public IrisWireReader(byte[] frame) {
|
||||
this.frame = frame;
|
||||
this.limit = frame.length;
|
||||
this.position = 0;
|
||||
}
|
||||
|
||||
public int readVarInt() throws ProtocolException {
|
||||
int result = 0;
|
||||
int shift = 0;
|
||||
for (int index = 0; index < 5; index++) {
|
||||
requireRemaining(1);
|
||||
int current = frame[position++] & 0xFF;
|
||||
result |= (current & 0x7F) << shift;
|
||||
if ((current & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
throw new ProtocolException("varint exceeds 5 bytes");
|
||||
}
|
||||
|
||||
public int readInt() throws ProtocolException {
|
||||
requireRemaining(4);
|
||||
int value = ((frame[position] & 0xFF) << 24)
|
||||
| ((frame[position + 1] & 0xFF) << 16)
|
||||
| ((frame[position + 2] & 0xFF) << 8)
|
||||
| (frame[position + 3] & 0xFF);
|
||||
position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
public long readLong() throws ProtocolException {
|
||||
requireRemaining(8);
|
||||
long value = ((long) (frame[position] & 0xFF) << 56)
|
||||
| ((long) (frame[position + 1] & 0xFF) << 48)
|
||||
| ((long) (frame[position + 2] & 0xFF) << 40)
|
||||
| ((long) (frame[position + 3] & 0xFF) << 32)
|
||||
| ((long) (frame[position + 4] & 0xFF) << 24)
|
||||
| ((long) (frame[position + 5] & 0xFF) << 16)
|
||||
| ((long) (frame[position + 6] & 0xFF) << 8)
|
||||
| (frame[position + 7] & 0xFF);
|
||||
position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
public double readDouble() throws ProtocolException {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
public boolean readBoolean() throws ProtocolException {
|
||||
requireRemaining(1);
|
||||
return frame[position++] != 0;
|
||||
}
|
||||
|
||||
public String readString() throws ProtocolException {
|
||||
int declaredLength = readVarInt();
|
||||
if (declaredLength < 0) {
|
||||
throw new ProtocolException("negative string length");
|
||||
}
|
||||
if (declaredLength > remaining()) {
|
||||
throw new ProtocolException("string length exceeds remaining frame bytes");
|
||||
}
|
||||
String value = new String(frame, position, declaredLength, StandardCharsets.UTF_8);
|
||||
position += declaredLength;
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] readBytes() throws ProtocolException {
|
||||
int declaredLength = readVarInt();
|
||||
if (declaredLength < 0) {
|
||||
throw new ProtocolException("negative byte array length");
|
||||
}
|
||||
if (declaredLength > remaining()) {
|
||||
throw new ProtocolException("byte array length exceeds remaining frame bytes");
|
||||
}
|
||||
byte[] value = new byte[declaredLength];
|
||||
System.arraycopy(frame, position, value, 0, declaredLength);
|
||||
position += declaredLength;
|
||||
return value;
|
||||
}
|
||||
|
||||
private int remaining() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
private void requireRemaining(int count) throws ProtocolException {
|
||||
if (position + count > limit) {
|
||||
throw new ProtocolException("truncated frame: needed " + count + " bytes, had " + remaining());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class IrisWireWriter {
|
||||
private byte[] buffer;
|
||||
private int length;
|
||||
|
||||
public IrisWireWriter() {
|
||||
this.buffer = new byte[64];
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
public void writeVarInt(int value) {
|
||||
int remaining = value;
|
||||
while (true) {
|
||||
int chunk = remaining & 0x7F;
|
||||
remaining >>>= 7;
|
||||
if (remaining != 0) {
|
||||
writeByte(chunk | 0x80);
|
||||
} else {
|
||||
writeByte(chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeInt(int value) {
|
||||
ensure(4);
|
||||
buffer[length++] = (byte) (value >>> 24);
|
||||
buffer[length++] = (byte) (value >>> 16);
|
||||
buffer[length++] = (byte) (value >>> 8);
|
||||
buffer[length++] = (byte) value;
|
||||
}
|
||||
|
||||
public void writeLong(long value) {
|
||||
ensure(8);
|
||||
buffer[length++] = (byte) (value >>> 56);
|
||||
buffer[length++] = (byte) (value >>> 48);
|
||||
buffer[length++] = (byte) (value >>> 40);
|
||||
buffer[length++] = (byte) (value >>> 32);
|
||||
buffer[length++] = (byte) (value >>> 24);
|
||||
buffer[length++] = (byte) (value >>> 16);
|
||||
buffer[length++] = (byte) (value >>> 8);
|
||||
buffer[length++] = (byte) value;
|
||||
}
|
||||
|
||||
public void writeDouble(double value) {
|
||||
writeLong(Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
public void writeBoolean(boolean value) {
|
||||
writeByte(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public void writeString(String value) {
|
||||
byte[] encoded = value.getBytes(StandardCharsets.UTF_8);
|
||||
writeVarInt(encoded.length);
|
||||
ensure(encoded.length);
|
||||
System.arraycopy(encoded, 0, buffer, length, encoded.length);
|
||||
length += encoded.length;
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] value) {
|
||||
writeVarInt(value.length);
|
||||
ensure(value.length);
|
||||
System.arraycopy(value, 0, buffer, length, value.length);
|
||||
length += value.length;
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
return Arrays.copyOf(buffer, length);
|
||||
}
|
||||
|
||||
private void writeByte(int value) {
|
||||
ensure(1);
|
||||
buffer[length++] = (byte) value;
|
||||
}
|
||||
|
||||
private void ensure(int extra) {
|
||||
if ((long) length + extra > IrisProtocol.MAX_FRAME_BYTES) {
|
||||
throw new IllegalStateException("Iris protocol frame exceeds " + IrisProtocol.MAX_FRAME_BYTES + " byte cap");
|
||||
}
|
||||
int required = length + extra;
|
||||
if (required <= buffer.length) {
|
||||
return;
|
||||
}
|
||||
int grown = buffer.length;
|
||||
while (grown < required) {
|
||||
grown <<= 1;
|
||||
}
|
||||
if (grown > IrisProtocol.MAX_FRAME_BYTES) {
|
||||
grown = IrisProtocol.MAX_FRAME_BYTES;
|
||||
}
|
||||
buffer = Arrays.copyOf(buffer, grown);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi.protocol;
|
||||
|
||||
public class ProtocolException extends Exception {
|
||||
public ProtocolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user