diff --git a/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboClient.java b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboClient.java
new file mode 100644
index 000000000..ab0f31060
--- /dev/null
+++ b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboClient.java
@@ -0,0 +1,56 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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 .
+ */
+
+package com.volmit.iris.core.pregenerator.turbo;
+
+import com.volmit.iris.core.pregenerator.turbo.command.TurboCommand;
+import com.volmit.iris.util.collection.GBiset;
+import com.volmit.iris.util.function.Consumer2;
+import com.volmit.iris.util.scheduling.J;
+import lombok.Builder;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+@Builder
+public class TurboClient {
+ private String address;
+ private int port;
+ private TurboCommand command;
+ private Consumer output;
+
+ public void go(Consumer2 handler) throws Throwable {
+ Socket socket = new Socket(address, port);
+ DataInputStream i = new DataInputStream(socket.getInputStream());
+ DataOutputStream o = new DataOutputStream(socket.getOutputStream());
+ TurboCommander.write(command, o);
+
+ if(output != null)
+ {
+ output.accept(o);
+ }
+
+ o.flush();
+ handler.accept(TurboCommander.read(i), i);
+ socket.close();
+ }
+}
diff --git a/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboCommander.java b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboCommander.java
new file mode 100644
index 000000000..5e0438c57
--- /dev/null
+++ b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboCommander.java
@@ -0,0 +1,40 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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 .
+ */
+
+package com.volmit.iris.core.pregenerator.turbo;
+
+import com.google.gson.Gson;
+import com.volmit.iris.core.pregenerator.turbo.command.TurboCommand;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class TurboCommander {
+ private static final Gson gson = new Gson();
+
+ public static TurboCommand read(DataInputStream in) throws IOException, ClassNotFoundException {
+ String clazz = in.readUTF();
+ return (TurboCommand) gson.fromJson(in.readUTF(), Class.forName(clazz));
+ }
+
+ public static void write(TurboCommand c, DataOutputStream out) throws IOException {
+ out.writeUTF(c.getClass().getCanonicalName());
+ out.writeUTF(gson.toJson(c));
+ }
+}
diff --git a/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboServer.java b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboServer.java
new file mode 100644
index 000000000..85e5e4f74
--- /dev/null
+++ b/src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboServer.java
@@ -0,0 +1,247 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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 .
+ */
+
+package com.volmit.iris.core.pregenerator.turbo;
+
+import com.volmit.iris.core.pregenerator.PregenListener;
+import com.volmit.iris.core.pregenerator.turbo.command.*;
+import com.volmit.iris.engine.headless.HeadlessGenerator;
+import com.volmit.iris.engine.headless.HeadlessWorld;
+import com.volmit.iris.util.io.IO;
+import com.volmit.iris.util.scheduling.J;
+import org.apache.logging.log4j.core.tools.Generate;
+import org.zeroturnaround.zip.ZTFileUtil;
+import org.zeroturnaround.zip.ZipUtil;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TurboServer extends Thread implements PregenListener {
+ private int port;
+ private String password;
+ private boolean busy;
+ private int tc;
+ private HeadlessGenerator generator;
+ private ServerSocket server;
+ private File cache;
+ private UUID currentId = null;
+ private AtomicInteger g = new AtomicInteger(0);
+ private File lastGeneratedRegion = null;
+
+ public TurboServer(File cache, int port, String password, int tc) throws IOException {
+ this.port = port;
+ this.cache = cache;
+ this.password = password;
+ this.tc = tc;
+ start();
+ server = new ServerSocket(port);
+ server.setSoTimeout(1000);
+ }
+
+ public void run()
+ {
+ while(!interrupted())
+ {
+ try {
+ Socket client = server.accept();
+ DataInputStream i = new DataInputStream(client.getInputStream());
+ DataOutputStream o = new DataOutputStream(client.getOutputStream());
+ try {
+ handle(client, i, o);
+ o.flush();
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ client.close();
+ } catch (SocketTimeoutException ignored) {
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void handle(Socket client, DataInputStream i, DataOutputStream o) throws Throwable
+ {
+ TurboCommand cmd = handle(TurboCommander.read(i), i, o);
+
+ if(cmd != null)
+ {
+ TurboCommander.write(cmd, o);
+ }
+
+ o.flush();
+ }
+
+ private File getCachedDim(UUID id)
+ {
+ return new File(cache, id.toString().charAt(2) +"/" + id.toString().substring(0, 4)+ "/" + id);
+ }
+
+ private TurboCommand handle(TurboCommand command, DataInputStream i, DataOutputStream o) throws Throwable {
+ if(command instanceof TurboInstallPack)
+ {
+ if(busy)
+ {
+ return new TurboBusy();
+ }
+
+ if(generator != null)
+ {
+ generator.close();
+ IO.delete(generator.getWorld().getWorld().worldFolder());
+ generator = null;
+ }
+
+ UUID id = ((TurboInstallPack) command).getPack();
+ File cacheload = new File(cache, id.toString().charAt(2) +"/" + id.toString().substring(0, 4)+ "/" + id + ".zip");
+ File cachestore = getCachedDim(id);
+ IO.delete(cachestore);
+ int len = i.readInt();
+ cacheload.getParentFile().mkdirs();
+ byte[] buf = new byte[8192];
+ FileOutputStream fos = new FileOutputStream(cacheload);
+ IO.transfer(i, fos, buf, len);
+ fos.close();
+ ZipUtil.unpack(cacheload, cachestore);
+ cacheload.deleteOnExit();
+ HeadlessWorld w = new HeadlessWorld("turbo/" + id.toString(), ((TurboInstallPack) command).getDimension(), ((TurboInstallPack) command).getSeed());
+ w.setStudio(true);
+ generator = w.generate();
+ return new TurboOK();
+ }
+
+ if(command instanceof TurboGenerate)
+ {
+ if(busy)
+ {
+ return new TurboBusy();
+ }
+
+ if(generator == null || !Objects.equals(currentId, ((TurboGenerate) command).getPack())) {
+ return new TurboInstallFirst();
+ }
+
+ g.set(0);
+ busy = true;
+ J.a(() -> {
+ busy = false;
+ lastGeneratedRegion = generator.generateRegionToFile(((TurboGenerate) command).getX(), ((TurboGenerate) command).getZ(), this);
+ });
+ return new TurboOK();
+ }
+
+ if(command instanceof TurboClose)
+ {
+ if(generator != null && Objects.equals(currentId, ((TurboClose) command).getPack()) && !busy)
+ {
+ generator.close();
+ IO.delete(generator.getWorld().getWorld().worldFolder());
+ generator = null;
+ currentId = null;
+ }
+ }
+
+ if(command instanceof TurboGetProgress)
+ {
+ if(generator != null && busy && Objects.equals(currentId, ((TurboGetProgress) command).getPack()))
+ {
+ return TurboSendProgress.builder().progress((double)g.get() / 1024D).build();
+ }
+
+ else if(generator != null && !busy && Objects.equals(currentId, ((TurboGetProgress) command).getPack()) && lastGeneratedRegion != null && lastGeneratedRegion.exists())
+ {
+ TurboCommander.write(TurboSendProgress
+ .builder()
+ .progress(1).available(true)
+ .build(), o);
+ o.writeLong(lastGeneratedRegion.length());
+ IO.writeAll(lastGeneratedRegion, o);
+ return null;
+ }
+
+ else if(generator == null)
+ {
+ return new TurboInstallFirst();
+ }
+
+ else
+ {
+ return new TurboBusy();
+ }
+ }
+
+ throw new IllegalStateException("Unexpected value: " + command.getClass());
+ }
+
+ public void close() throws IOException {
+ interrupt();
+ generator.close();
+ server.close();
+ }
+
+ @Override
+ public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
+
+ }
+
+ @Override
+ public void onChunkGenerating(int x, int z) {
+
+ }
+
+ @Override
+ public void onChunkGenerated(int x, int z) {
+ g.incrementAndGet();
+ }
+
+ @Override
+ public void onRegionGenerated(int x, int z) {
+
+ }
+
+ @Override
+ public void onRegionGenerating(int x, int z) {
+
+ }
+
+ @Override
+ public void onRegionSkipped(int x, int z) {
+
+ }
+
+ @Override
+ public void onClose() {
+
+ }
+
+ @Override
+ public void onSaving() {
+
+ }
+
+ @Override
+ public void onChunkExistsInRegionGen(int x, int z) {
+
+ }
+}