From de7bc9870d03049603d524bcc31855fa1c82bbf1 Mon Sep 17 00:00:00 2001 From: Daniel Mills Date: Tue, 20 Jul 2021 04:56:37 -0400 Subject: [PATCH] Turbo connectivity --- .../core/pregenerator/turbo/TurboClient.java | 56 ++++ .../pregenerator/turbo/TurboCommander.java | 40 +++ .../core/pregenerator/turbo/TurboServer.java | 247 ++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboClient.java create mode 100644 src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboCommander.java create mode 100644 src/main/java/com/volmit/iris/core/pregenerator/turbo/TurboServer.java 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) { + + } +}