Merge remote-tracking branch 'upstream/master' into saplingOverrides

This commit is contained in:
CocoTheOwner 2021-07-21 16:48:22 +02:00
commit 25bcd0f2a9
141 changed files with 4158 additions and 4141 deletions

71
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View File

@ -0,0 +1,71 @@
name: Iris Bug Report
description: File a bug report for Iris
labels: [bug]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill this out!
If this does not work for you, feel free to use the [blank](https://github.com/VolmitSoftware/Iris/issues/new) format.
- type: textarea
id: how
attributes:
label: Problem
description: Please give a text description of how you reached the problem
value: |
1. Install Iris...
2. Do this...
3. Do that...
4. Observe the error...
render: txt
validations:
required: true
- type: textarea
id: what
attributes:
label: Solution
description: Explain where you think the problem comes from (optional)
placeholder: The code to place a is missing b and c...
validations:
required: false
- type: dropdown
id: mcversion
attributes:
label: Minecraft Version
description: What version of Minecraft is the server on?
options:
- 1.14 to 1.16.5
- 1.17.x
- 1.18.x
validations:
required: true
- type: input
id: irisversion
attributes:
label: Iris Version
description: What version of Iris are you running? (see console)
placeholder: DO NOT SAY "LATEST"
validations:
required: true
- type: input
id: logs
attributes:
label: Log
description: Paste a full log. Always use [mclogs](https://mclo.gs) Or [Pastebin](https://pastebin.com/). Must not be a crash report. Must be a full log. Must not be a screenshot of a log.
placeholder: https://mslog.gs/...
validations:
required: true
- type: checkboxes
id: checksum
attributes:
label: Checklist
description: Please ensure you meet each of the requirements below
options:
- label: I am using an unmodified version of Iris. (If you modified the plugin and see an issue, make sure it is reproducable on the latest spigot version or contact [support](discord.gg/volmit))
required: true
- label: I am using Spigot, Paper, Tuinity, or Purpur. (If you are not, and still think it is a valid issue, contact [support](discord.gg/volmit))
required: true
- type: markdown
id: thanks
attributes:
value: "Thank you for filling out the form! We will be with you soon. Please do not ask support to review your report."

View File

@ -1,34 +0,0 @@
---
name: Bug report about: Create a report to help us improve title: ''
labels: Bug assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots or Video Recordings**
If applicable, add screenshots or video recordings to help explain your problem.
**Server and Plugin Information**
- Installed plugins:
- Iris Version:
- Server Platform and Version [eg: PaperSpigot 1.16.3 #240]:
- Operating System (if applicable):
- Server Logs:
**Additional context**
Add any other context about the problem here, server timings reports, Iris dump information, complete console log etc.
Please do not make Pastebin dumps or screenshot expire.

46
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: Iris Feature Request
description: File a feature request for Iris. If you want to report a bug this is not the place.
labels: [feature]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill this out!
If this does not work for you, feel free to use the [blank](https://github.com/VolmitSoftware/Iris/issues/new) format.
- type: dropdown
id: arc
attributes:
label: Adding, Removing, or Changing
description: What are you doing
options:
- Adding
- Removing
- Changing
validations:
required: true
- type: input
id: atype
attributes:
label: Type of Modification
description: What is it for?
value: I want to ...
validations:
required: true
- type: textarea
id: desc
attributes:
label: What are you trying to modify
description: Give as detailed of a description as you can for the modification that you want done (include pictures if applicable)
value: The way I would implement this is ...
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Alternatives
description: What alternatives have you considered?
value: If this could not be implemented I would ...
- type: markdown
id: thanks
attributes:
value: "Thank you for filling out the form! We will be with you soon. Please do not ask support to review your report."

View File

@ -1,17 +0,0 @@
---
name: Feature request about: Suggest an idea for this project title: ''
labels: Enhancement, Addition assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -3,7 +3,39 @@
For 1.16 and below, see the 1.14-1.16 branch. The master branch is for the latest version of minecraft.
# [Support](https://discord.gg/3xxPTpT) **|** [Documentation](https://docs.volmit.com/iris/) **
|** [Git](https://github.com/IrisDimensions)
![Iris Image](https://raw.githubusercontent.com/VolmitSoftware/Iris/master/IRIS.png)
## Iris Toolbelt
Everyone needs a toolbelt.
```java
package com.volmit.iris.core.tools
// Get IrisDataManager from a world
IrisToolbelt.access(anyWorld).getCompound().getData();
// Get Default Engine from world
IrisToolbelt.access(anyWorld).getCompound().getDefaultEngine();
// Get the engine at the given height
IrisToolbelt.access(anyWorld).getCompound().getEngineForHeight(68);
// IS THIS THING ON?
boolean yes = IrisToolbelt.isIrisWorld(world);
// GTFO for worlds (moves players to any other world, just not this one)
IrisToolbelt.evacuate(world);
IrisAccess access = IrisToolbelt.createWorld() // If you like builders...
.name("myWorld") // The world name
.dimension("terrifyinghands")
.seed(69133742) // The world seed
.headless(true) // Headless make gen go fast
.pregen(PregenTask // Define a pregen job to run
.builder()
.center(new Position2(0,0)) // REGION coords (1 region = 32x32 chunks)
.radius(4) // Radius in REGIONS. Rad of 4 means a 9x9 Region map.
.build())
.create();
```

View File

@ -5,7 +5,7 @@ plugins {
}
group 'com.volmit.iris'
version '1.5.2'
version '1.5.6'
def apiVersion = '1.17'
def name = 'Iris'
def main = 'com.volmit.iris.Iris'
@ -81,6 +81,8 @@ shadowJar
}
}
manifest()
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'

View File

@ -26,12 +26,13 @@ import com.volmit.iris.core.link.BKLink;
import com.volmit.iris.core.link.MultiverseCoreLink;
import com.volmit.iris.core.link.MythicMobsLink;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisCompat;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
@ -79,9 +80,6 @@ public class Iris extends VolmitPlugin implements Listener {
public static MythicMobsLink linkMythicMobs;
public static TreeManager saplingManager;
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
public static boolean customModels = doesSupportCustomModels();
public static boolean awareEntities = doesSupportAwareness();
public static boolean lowMemoryMode = false;
public static IrisCompat compat;
public static FileWatcher configWatcher;
@ -95,7 +93,6 @@ public class Iris extends VolmitPlugin implements Listener {
instance = this;
INMS.get();
IO.delete(new File("iris"));
lowMemoryMode = Runtime.getRuntime().maxMemory() < 4000000000L; // 4 * 1000 * 1000 * 1000 // 4;
installDataPacks();
}
@ -156,54 +153,6 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.info("Data Packs Setup!");
}
public static int getThreadCount() {
int tc = IrisSettings.get().getConcurrency().getThreadCount();
if (tc <= 0) {
int p = Runtime.getRuntime().availableProcessors();
return p > 16 ? 16 : Math.max(p, 4);
}
return tc;
}
private static boolean doesSupport3DBiomes() {
try {
int v = Integer.parseInt(Bukkit.getBukkitVersion().split("\\Q-\\E")[0].split("\\Q.\\E")[1]);
return v >= 15;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
private static boolean doesSupportCustomModels() {
try {
int v = Integer.parseInt(Bukkit.getBukkitVersion().split("\\Q-\\E")[0].split("\\Q.\\E")[1]);
return v >= 14;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
private static boolean doesSupportAwareness() {
try {
int v = Integer.parseInt(Bukkit.getBukkitVersion().split("\\Q-\\E")[0].split("\\Q.\\E")[1]);
return v >= 15;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
@Override
public void start() {
@ -276,6 +225,7 @@ public class Iris extends VolmitPlugin implements Listener {
board.disable();
Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this);
MultiBurst.burst.shutdown();
super.onDisable();
}
@ -571,18 +521,6 @@ public class Iris extends VolmitPlugin implements Listener {
}
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n");
if (lowMemoryMode) {
Iris.verbose("* Low Memory mode Activated! For better performance, allocate 4gb or more to this server.");
}
if (!customModels) {
Iris.verbose("* This version of minecraft does not support custom model data in loot items (1.14 and up). Iris will generate as normal, but loot will not have custom models.");
}
if (!doesSupportAwareness()) {
Iris.verbose("* This version of minecraft does not support entity awareness.");
}
}
@SuppressWarnings("deprecation")

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.util.board.BoardManager;

View File

@ -23,7 +23,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.report.Report;
import com.volmit.iris.core.report.ReportType;
import com.volmit.iris.engine.IrisWorldCreator;
import com.volmit.iris.core.tools.IrisWorldCreator;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.*;
@ -273,8 +273,9 @@ public class IrisProject {
break;
}
}
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generation Complete"));
if (sender.isPlayer()) {
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generation Complete"));
}
});
//@builder
@ -307,9 +308,9 @@ public class IrisProject {
public void close() {
activeProvider.close();
File folder = activeProvider.getTarget().getWorld().getWorldFolder();
Iris.linkMultiverseCore.removeFromConfig(activeProvider.getTarget().getWorld().getName());
Bukkit.unloadWorld(activeProvider.getTarget().getWorld().getName(), false);
File folder = activeProvider.getTarget().getWorld().worldFolder();
Iris.linkMultiverseCore.removeFromConfig(activeProvider.getTarget().getWorld().name());
Bukkit.unloadWorld(activeProvider.getTarget().getWorld().name(), false);
J.attemptAsync(() -> IO.delete(folder));
activeProvider = null;
}

View File

@ -56,14 +56,27 @@ public class IrisSettings {
return getParallax().getParallaxRegionEvictionMS();
}
public static int getThreadCount(int c) {
if (c < 2 && c >= 0) {
return 2;
}
return Math.max(2, c < 0 ? Runtime.getRuntime().availableProcessors() / -c : c);
}
@Data
public static class IrisSettingsCache {
public int streamingCacheSize = 8192;
public int complexCacheSize = 131072;
}
@Data
public static class IrisSettingsConcurrency {
public int threadCount = -1;
public int engineThreadCount = -1;
public int engineThreadPriority = 6;
public int pregenThreadCount = -1;
public int pregenThreadPriority = 8;
public int miscThreadCount = -4;
public int miscThreadPriority = 3;
}
@Data
@ -99,8 +112,7 @@ public class IrisSettings {
public boolean systemEffects = true;
public boolean systemEntitySpawnOverrides = true;
public boolean systemEntityInitialSpawns = true;
public int maxBiomeChildDepth = 5;
public int maxBiomeChildDepth = 4;
}
@Data

View File

@ -33,6 +33,9 @@ public class CommandIris extends MortarCommand {
@Command
private CommandIrisCreate create;
@Command
private CommandIrisVerify verify;
@Command
private CommandIrisFix fix;

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand;

View File

@ -56,7 +56,7 @@ public class CommandIrisStudioClose extends MortarCommand {
World f = null;
for (World i : Bukkit.getWorlds()) {
if (i.getWorldFolder().getAbsolutePath().equals(Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().getWorldFolder().getAbsolutePath())) {
if (i.getWorldFolder().getAbsolutePath().equals(Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().worldFolder().getAbsolutePath())) {
continue;
}

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.IrisExplorer;
import com.volmit.iris.core.gui.NoiseExplorerGUI;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.Command;
import com.volmit.iris.util.plugin.MortarCommand;
@ -57,7 +57,7 @@ public class CommandIrisStudioExplorer extends MortarCommand {
return true;
}
IrisExplorer.launch();
NoiseExplorerGUI.launch();
sender.sendMessage("Opening Noise Explorer!");
}
return true;

View File

@ -21,7 +21,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.IrisExplorer;
import com.volmit.iris.core.gui.NoiseExplorerGUI;
import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.RNG;
@ -63,14 +63,14 @@ public class CommandIrisStudioExplorerGenerator extends MortarCommand {
if (Iris.proj.isProjectOpen()) {
generator = Iris.proj.getActiveProject().getActiveProvider().getData().getGeneratorLoader().load(args[0]);
seed = Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().getSeed();
seed = Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().seed();
} else {
generator = IrisDataManager.loadAnyGenerator(args[0]);
}
if (generator != null) {
long finalSeed = seed;
IrisExplorer.launch((x, z) ->
NoiseExplorerGUI.launch((x, z) ->
generator.getHeight(x, z, new RNG(finalSeed).nextParallelRNG(3245).lmax()), "Gen: " + generator.getLoadKey());
sender.sendMessage("Opening Noise Explorer for gen " + generator.getLoadKey() + " (" + generator.getLoader().getDataFolder().getName() + ")");

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender;

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.InventorySlotType;
import com.volmit.iris.engine.object.IrisLootTable;

View File

@ -20,8 +20,8 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.IrisVision;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.gui.VisionGUI;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.util.collection.KList;
@ -57,12 +57,12 @@ public class CommandIrisStudioMap extends MortarCommand {
try {
IrisAccess g = Iris.proj.getActiveProject().getActiveProvider();
IrisVision.launch(g, 0);
VisionGUI.launch(g, 0);
sender.sendMessage("Opening Map!");
} catch (Throwable e) {
Iris.reportError(e);
IrisAccess g = IrisWorlds.access(sender.player().getWorld());
IrisVision.launch(g, 0);
VisionGUI.launch(g, 0);
sender.sendMessage("Opening Map!");
}
return true;

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisEntity;

View File

@ -57,7 +57,7 @@ public class CommandIrisStudioTPStudio extends MortarCommand {
try {
sender.sendMessage("Teleporting you to the active studio world.");
sender.player().teleport(Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().getSpawnLocation());
sender.player().teleport(Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
sender.player().setGameMode(GameMode.SPECTATOR);
} catch (Throwable e) {
Iris.reportError(e);

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.what;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList;

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command.what;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisObject;

View File

@ -21,10 +21,9 @@ package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.Pregenerator;
import com.volmit.iris.core.link.MultiverseCoreLink;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.IrisWorldCreator;
import com.volmit.iris.core.tools.IrisWorldCreator;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList;
@ -161,8 +160,7 @@ public class CommandIrisCreate extends MortarCommand {
sender.sendMessage("Pregenerating " + worldName + " " + size + " x " + size);
sender.sendMessage("Expect server lag during this time. Use '/iris pregen stop' to cancel");
new Pregenerator(world.get(), size, () ->
b.set(true));
}
World ww = world.get();
@ -223,7 +221,6 @@ public class CommandIrisCreate extends MortarCommand {
.productionMode().seed(seed).create();
J.s(() -> {
sender.sendMessage("Generating with " + Iris.getThreadCount() + " threads per chunk");
O<Boolean> done = new O<>();
done.set(false);
@ -249,15 +246,6 @@ public class CommandIrisCreate extends MortarCommand {
World w = INMS.get().createWorld(wc);
world.set(w);
try {
if (pregen.get() > 0) {
new Pregenerator(w, pregen.get());
}
} catch (Throwable e) {
Iris.reportError(e);
}
done.set(true);
});
}

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form;

View File

@ -19,8 +19,12 @@
package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris;
import com.volmit.iris.core.gui.Pregenerator;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
@ -69,17 +73,17 @@ public class CommandIrisPregen extends MortarCommand {
}
if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("x")) {
if (Pregenerator.shutdownInstance()) {
sender.sendMessage("Stopped Pregen.");
if (PregeneratorJob.shutdownInstance()) {
sender.sendMessage("Stopped Pregen. Finishing last region file before shutting down...");
} else {
sender.sendMessage("No Active Pregens.");
}
return true;
} else if (args[0].equalsIgnoreCase("pause") || args[0].equalsIgnoreCase("resume")) {
if (Pregenerator.getInstance() != null) {
Pregenerator.pauseResume();
if (PregeneratorJob.getInstance() != null) {
PregeneratorJob.pauseResume();
if (Pregenerator.isPaused()) {
if (PregeneratorJob.isPaused()) {
sender.sendMessage("Pregen Paused");
} else {
sender.sendMessage("Pregen Resumed");
@ -105,7 +109,11 @@ public class CommandIrisPregen extends MortarCommand {
}
}
try {
new Pregenerator(world, getVal(args[0]) * 2);
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(0, 0))
.radius(((getVal(args[0]) >> 4) >> 5) + 1)
.build(), world);
} catch (NumberFormatException e) {
Iris.reportError(e);
sender.sendMessage("Invalid argument in command");
@ -131,7 +139,12 @@ public class CommandIrisPregen extends MortarCommand {
}
World world = Bukkit.getWorld(args[1]);
try {
new Pregenerator(world, getVal(args[0]) * 2);
new PregeneratorJob(PregenTask
.builder()
.center(new Position2(0, 0))
.radius(((getVal(args[0]) >> 4) >> 5) + 1)
.build(),
new HybridPregenMethod(world, Runtime.getRuntime().availableProcessors()));
} catch (NumberFormatException e) {
Iris.reportError(e);
sender.sendMessage("Invalid argument in command");

View File

@ -0,0 +1,104 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.data.mca.Chunk;
import com.volmit.iris.engine.data.mca.MCAFile;
import com.volmit.iris.engine.data.mca.MCAUtil;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
public class CommandIrisVerify extends MortarCommand {
public CommandIrisVerify() {
super("verifymca");
requiresPermission(Iris.perm.studio);
setDescription("Fix nearby chunks");
setCategory("Studio");
}
@Override
public void addTabOptions(VolmitSender sender, String[] args, KList<String> list) {
}
@Override
public boolean handle(VolmitSender sender, String[] args) {
try {
IrisAccess a = IrisWorlds.access(sender.player().getWorld());
File folder = a.getTarget().getWorld().worldFolder();
File r = new File(folder, "region");
BurstExecutor e = MultiBurst.burst.burst(r.listFiles().length);
AtomicInteger f = new AtomicInteger(0);
for(File i : r.listFiles())
{
e.queue(() -> {
MCAFile file = null;
try {
file = MCAUtil.read(i);
int rx = Integer.valueOf(i.getName().split("\\Q.\\E")[1]);
int rz = Integer.valueOf(i.getName().split("\\Q.\\E")[2]);
for(int j = 0; j < 32; j++)
{
for(int k = 0; k < 32; k++)
{
f.incrementAndGet();
Chunk c = file.getChunk(j, k);
if(c == null)
{
sender.sendMessage("Found Missing Chunk " + i.getName() + ", chunk #" + j + "," + k + " (see " + (((rx << 5)<<4)+(j<<4)) + "," + (((rz << 5)<<4)+(k<<4)));
}
}
}
} catch (IOException ioException) {
ioException.printStackTrace();
sender.sendMessage("Error loading region " + i.getName());
}
});
}
e.complete();
sender.sendMessage("Done! Checked " + f.get() + " chunks");
} catch (Throwable e) {
Iris.reportError(e);
sender.sendMessage("Not a valid Iris World (or bad argument)");
}
return true;
}
@Override
protected String getArgsUsage() {
return "[view-distance]";
}
}

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender;

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.edit;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.parallax.ParallaxAccess;
import com.volmit.iris.util.collection.KList;

View File

@ -38,7 +38,7 @@ import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;
public class IrisExplorer extends JPanel implements MouseWheelListener {
public class NoiseExplorerGUI extends JPanel implements MouseWheelListener {
private static final long serialVersionUID = 2094606939770332040L;
@ -74,7 +74,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
double t;
double tz;
public IrisExplorer() {
public NoiseExplorerGUI() {
addMouseWheelListener(this);
addMouseMotionListener(new MouseMotionListener() {
@Override
@ -237,7 +237,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
private static void createAndShowGUI(Function2<Double, Double, Double> gen, String genName) {
JFrame frame = new JFrame("Noise Explorer: " + genName);
IrisExplorer nv = new IrisExplorer();
NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
JLayeredPane pane = new JLayeredPane();
nv.setSize(new Dimension(1440, 820));
@ -259,7 +259,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Noise Explorer");
IrisExplorer nv = new IrisExplorer();
NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
KList<String> li = new KList<>(NoiseStyle.values()).toStringList();
combo = new JComboBox<>(li.toArray(new String[0]));
@ -296,7 +296,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
}
public static void launch() {
EventQueue.invokeLater(IrisExplorer::createAndShowGUI);
EventQueue.invokeLater(NoiseExplorerGUI::createAndShowGUI);
}
static class HandScrollListener extends MouseAdapter {

View File

@ -1,639 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.engine.data.mca.MCAFile;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Consumer2;
import com.volmit.iris.util.function.Consumer3;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.math.ChunkPosition;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.SR;
import io.papermc.lib.PaperLib;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.Listener;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
@Data
public class Pregenerator implements Listener {
private static Pregenerator instance;
private static final Color COLOR_ERROR = Color.decode("#E34113");
private static final Color COLOR_MCA_PREPARE = Color.decode("#3CAAB5");
private static final Color COLOR_MCA_RELOAD = Color.decode("#41FF61");
private static final Color COLOR_MCA_GENERATE = Color.decode("#33FF8F");
private static final Color COLOR_MCA_GENERATE_SLOW = Color.decode("#13BAE3");
private static final Color COLOR_MCA_GENERATE_SLOW_ASYNC = Color.decode("#13BAE3");
private static final Color COLOR_MCA_GENERATED = Color.decode("#33FF8F");
private static final Color COLOR_MCA_GENERATED_MCA = Color.decode("#13E3C9");
private static final Color COLOR_MCA_SEALED = Color.decode("#33FF8F");
private static final Color COLOR_MCA_DEFERRED = Color.decode("#3CB57A");
private final World world;
private int lowestBedrock;
private final NBTWorld directWriter;
private final AtomicBoolean active;
private final AtomicBoolean running;
private final KList<ChunkPosition> errors;
private final KList<Runnable> onComplete;
private final ChunkPosition max;
private final ChunkPosition min;
private final MCAPregenGui gui;
private final KList<ChunkPosition> mcaDefer;
private final AtomicInteger generated;
private final AtomicInteger generatedLast;
private final RollingSequence perSecond;
private final RollingSequence perMinute;
private final AtomicInteger totalChunks;
private final AtomicLong memory;
private final AtomicReference<String> memoryMetric;
private final AtomicReference<String> method;
private final AtomicInteger vmcax;
private final AtomicInteger vmcaz;
private final AtomicInteger vcax;
private final AtomicInteger vcaz;
private final long elapsed;
private final ChronoLatch latch;
private IrisAccess access;
private final KList<ChunkPosition> regionReload;
private KList<ChunkPosition> wait = new KList<>();
public Pregenerator(World world, int blockSize, Runnable onComplete) {
this(world, blockSize);
this.onComplete.add(onComplete);
}
public Pregenerator(World world, int blockSize) throws HeadlessException {
this(world, blockSize, true);
}
public Pregenerator(World world, int blockSize, boolean dogui) throws HeadlessException {
instance();
regionReload = new KList<>();
latch = new ChronoLatch(5000);
memoryMetric = new AtomicReference<>("...");
method = new AtomicReference<>("STARTUP");
memory = new AtomicLong(0);
this.world = world;
errors = new KList<>();
vmcax = new AtomicInteger();
vmcaz = new AtomicInteger();
vcax = new AtomicInteger();
vcaz = new AtomicInteger();
perMinute = new RollingSequence(200);
perSecond = new RollingSequence(20);
generatedLast = new AtomicInteger(0);
totalChunks = new AtomicInteger(0);
generated = new AtomicInteger(0);
mcaDefer = new KList<>();
access = IrisWorlds.access(world);
this.directWriter = new NBTWorld(world.getWorldFolder());
this.running = new AtomicBoolean(true);
this.active = new AtomicBoolean(true);
MultiBurst burst = new MultiBurst("Iris Pregenerator", 9, Runtime.getRuntime().availableProcessors());
int mcaSize = (((blockSize >> 4) + 2) >> 5) + 1;
onComplete = new KList<>();
max = new ChunkPosition(0, 0);
min = new ChunkPosition(0, 0);
KList<Runnable> draw = new KList<>();
new Spiraler(mcaSize, mcaSize, (xx, zz) -> {
min.setX(Math.min(xx << 5, min.getX()));
min.setZ(Math.min(zz << 5, min.getZ()));
max.setX(Math.max((xx << 5) + 31, max.getX()));
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
totalChunks.getAndAdd(1024);
draw.add(() -> drawMCA(xx, zz, COLOR_MCA_PREPARE));
}).drain();
if (access != null) {
lowestBedrock = access.getCompound().getLowestBedrock();
}
gui = dogui ? (IrisSettings.get().getGui().isLocalPregenGui() && IrisSettings.get().getGui().isUseServerLaunchedGuis() ? MCAPregenGui.createAndShowGUI(this) : null) : null;
flushWorld();
KList<ChunkPosition> order = computeChunkOrder();
Consumer3<Integer, Integer, Consumer2<Integer, Integer>> mcaIteration =
(ox, oz, r) -> order.forEach((i)
-> r.accept(i.getX() + ox, i.getZ() + oz));
draw.forEach(Runnable::run);
Spiraler spiraler = new Spiraler(mcaSize, mcaSize, (xx, zz) -> {
vmcax.set(xx);
vmcaz.set(zz);
flushWorld();
drawMCA(xx, zz, COLOR_MCA_PREPARE);
if (access != null && generateMCARegion(xx, zz, burst, access, mcaIteration)) {
flushWorld();
}
});
elapsed = M.ms();
new Thread(() -> {
flushWorld();
J.sleep(2000);
flushWorld();
while (running.get() && spiraler.hasNext()) {
if (active.get()) {
spiraler.next();
}
}
mcaDefer.removeDuplicates();
while (running.get() && mcaDefer.isNotEmpty()) {
ChunkPosition p = mcaDefer.popLast();
vmcax.set(p.getX());
vmcaz.set(p.getZ());
generateDeferedMCARegion(p.getX(), p.getZ(), burst, mcaIteration);
flushWorld();
}
while (wait.isNotEmpty()) {
J.sleep(50);
}
burst.shutdownNow();
directWriter.close();
flushWorld();
onComplete.forEach(Runnable::run);
running.set(false);
active.set(false);
if (gui != null) {
gui.close();
}
}).start();
new Thread(() -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
while (running.get() && active.get()) {
int m = generated.get();
int w = generatedLast.get();
int up = m - w;
double dur = p.getMilliseconds();
perSecond.put((int) (up / (dur / 1000D)));
perSecond.put((int) (up / (dur / 60000D)));
p.reset();
p.begin();
updateProgress();
generatedLast.set(m);
J.sleep(100);
long lmem = memory.get();
memory.set(Runtime.getRuntime().freeMemory());
if (memory.get() > lmem) {
long free = memory.get();
long max = Runtime.getRuntime().maxMemory();
long total = Runtime.getRuntime().totalMemory();
long use = total - free;
memoryMetric.set(Form.memSize(use, 2) + " (" + Form.pc((double) use / (double) max, 0) + ")");
}
}
}).start();
}
private boolean generateMCARegion(int x, int z, MultiBurst burst, IrisAccess access, Consumer3<Integer, Integer, Consumer2<Integer, Integer>> mcaIteration) {
if (!Iris.instance.isMCA()) {
generateDeferedMCARegion(x, z, burst, mcaIteration);
return false;
}
File mca = directWriter.getRegionFile(x, z);
BurstExecutor e = burst.burst(1024);
int mcaox = x << 5;
int mcaoz = z << 5;
if (isMCAWritable(x, z) && !mca.exists()) {
method.set("Direct (Fast)");
mcaIteration.accept(mcaox, mcaoz, (ii, jj) -> e.queue(() -> {
draw(ii, jj, COLOR_MCA_GENERATE);
access.directWriteChunk(world, ii, jj, directWriter);
draw(ii, jj, COLOR_MCA_GENERATED_MCA);
generated.getAndIncrement();
vcax.set(ii);
vcaz.set(jj);
}));
e.complete();
//verifyMCA(x, z, burst);
directWriter.save();
} else {
totalChunks.getAndAdd(1024);
mcaDefer.add(new ChunkPosition(x, z));
e.complete();
return false;
}
return true;
}
private void verifyMCA(int x, int z, MultiBurst burst) {
MCAFile rg = directWriter.getMCA(x, z);
KList<Runnable> requeue = new KList<>();
for (int i = 0; i < 32; i++)
{
for(int j = 0; j < 32; j++)
{
com.volmit.iris.engine.data.mca.Chunk c = rg.getChunk(i, j);
if(c == null)
{
draw(((x << 5) + i), ((z << 5) + j), COLOR_ERROR);
int finalI = i;
int finalJ = j;
requeue.add(() -> {
draw(((x << 5) + finalI), ((z << 5) + finalJ), COLOR_MCA_GENERATE);
access.directWriteChunk(world, ((x << 5) + finalI), ((z << 5) + finalJ), directWriter);
draw(((x << 5) + finalI), ((z << 5) + finalJ), COLOR_MCA_GENERATED_MCA);
});
}
}
}
if(requeue.isNotEmpty())
{
burst.burst(requeue);
verifyMCA(x, z, burst);
}
}
public void updateProgress() {
if (!latch.flip()) {
return;
}
String[] v = getProgress();
Iris.info("Pregeneration " + v[0] + " | " + v[1] + " | " + v[2] + " | " + v[3]);
}
private void generateDeferedMCARegion(int x, int z, MultiBurst burst, Consumer3<Integer, Integer, Consumer2<Integer, Integer>> mcaIteration) {
int mcaox = x << 5;
int mcaoz = z << 5;
if (PaperLib.isPaper()) {
method.set("PaperAsync (Slow)");
while (wait.size() > 16) {
J.sleep(5);
}
mcaIteration.accept(mcaox, mcaoz, (ii, jj) -> {
ChunkPosition cx = new ChunkPosition(ii, jj);
PaperLib.getChunkAtAsync(world, ii, jj).thenAccept((c) -> {
draw(ii, jj, COLOR_MCA_GENERATE_SLOW_ASYNC);
draw(ii, jj, COLOR_MCA_GENERATED);
generated.getAndIncrement();
vcax.set(ii);
vcaz.set(jj);
synchronized (wait) {
wait.remove(cx);
}
});
wait.add(cx);
});
} else {
AtomicInteger m = new AtomicInteger();
method.set("Spigot (Very Slow)");
KList<Runnable> q = new KList<>();
mcaIteration.accept(mcaox, mcaoz, (ii, jj) -> q.add(() -> {
draw(ii, jj, COLOR_MCA_GENERATE_SLOW);
world.getChunkAt(ii, jj).load(true);
Chunk c = world.getChunkAt(ii, jj);
draw(ii, jj, COLOR_MCA_GENERATED);
m.getAndIncrement();
generated.getAndIncrement();
vcax.set(ii);
vcaz.set(jj);
}));
ChronoLatch tick = new ChronoLatch(1000);
new SR(0) {
@Override
public void run() {
if (tick.flip()) {
return;
}
if (q.isEmpty()) {
cancel();
return;
}
try {
q.pop().run();
} catch (Throwable e) {
Iris.reportError(e);
}
}
};
while (m.get() < 1024) {
J.sleep(25);
}
}
}
private KList<ChunkPosition> computeChunkOrder() {
ChunkPosition center = new ChunkPosition(15, 15);
KList<ChunkPosition> p = new KList<>();
new Spiraler(33, 33, (x, z) -> {
int xx = x + 15;
int zz = z + 15;
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new ChunkPosition(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(center)));
return p;
}
public static Pregenerator getInstance() {
return instance;
}
public static boolean shutdownInstance() {
if (instance != null) {
instance.shutdown();
instance = null;
return true;
}
return false;
}
public static void pauseResume() {
instance.active.set(!instance.active.get());
}
public static boolean isPaused() {
return instance.paused();
}
private void instance() {
if (instance != null) {
instance.shutdown();
}
instance = this;
}
public void shutdown() {
running.set(false);
active.set(false);
}
private void draw(int cx, int cz, Color color) {
if (gui != null) {
gui.func.accept(new ChunkPosition(cx, cz), color);
}
}
private void drawMCA(int cx, int cz, Color color) {
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 32; j++) {
draw((cx << 5) + i, (cz << 5) + j, color);
}
}
}
private void flushWorld() {
if (Bukkit.isPrimaryThread()) {
flushWorldSync();
return;
}
AtomicBoolean b = new AtomicBoolean(false);
J.s(() -> {
flushWorldSync();
b.set(true);
});
while (!b.get()) {
J.sleep(1);
}
}
private void flushWorldSync() {
for (Chunk i : world.getLoadedChunks()) {
i.unload(true);
}
world.save();
}
private boolean isMCAWritable(int x, int z) {
File mca = new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca");
if (mca.exists()) {
return false;
}
for (Chunk i : world.getLoadedChunks()) {
if (i.getX() >> 5 == x && i.getZ() >> 5 == z) {
return false;
}
}
return true;
}
public String[] getProgress() {
long eta = (long) ((totalChunks.get() - generated.get()) * ((double) (M.ms() - elapsed) / (double) generated.get()));
return new String[]{
"Progress: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ")",
"ETA: " + Form.duration(eta, 0),
"Chunks/s: " + Form.f((int) perSecond.getAverage()) + " (" + Form.f((int)perSecond.getMax()) + " Peak)",
"Chunks/min: " + Form.f((int) perMinute.getAverage())+ " (" + Form.f((int)perMinute.getMax()) + " Peak)",
"Memory: " + memoryMetric.get(),
"Cursor: " + "MCA(" + vmcax.get() + ", " + vmcaz.get() + ") @ (" + vcax.get() + ", " + vcaz.get() + ")",
"Gen Mode: " + method.get(),
};
}
public boolean paused() {
return !active.get();
}
public static class MCAPregenGui extends JPanel implements KeyListener {
private Pregenerator job;
private static final long serialVersionUID = 2094606939770332040L;
private final KList<Runnable> order = new KList<>();
private final int res = 512;
Graphics2D bg;
private ReentrantLock l;
private final BufferedImage image = new BufferedImage(res, res, BufferedImage.TYPE_INT_RGB);
private Consumer2<ChunkPosition, Color> func;
private JFrame frame;
public MCAPregenGui() {
}
public void paint(int x, int z, Color c) {
func.accept(new ChunkPosition(x, z), c);
}
@Override
public void paint(Graphics gx) {
Graphics2D g = (Graphics2D) gx;
bg = (Graphics2D) image.getGraphics();
l.lock();
while (order.isNotEmpty()) {
try {
order.pop().run();
} catch (Throwable e) {
Iris.reportError(e);
}
}
l.unlock();
g.drawImage(image, 0, 0, getParent().getWidth(), getParent().getHeight(), (img, infoflags, x, y, width, height) -> true);
g.setColor(Color.WHITE);
g.setFont(new Font("Hevetica", Font.BOLD, 28));
String[] prog = job.getProgress();
int h = g.getFontMetrics().getHeight() + 5;
int hh = 20;
if (job.paused()) {
g.drawString("PAUSED", 20, hh += h);
g.drawString("Press P to Resume", 20, hh += h);
} else {
for (String i : prog) {
g.drawString(i, 20, hh += h);
}
g.drawString("Press P to Pause", 20, hh += h);
}
J.sleep(IrisSettings.get().getGui().isMaximumPregenGuiFPS() ? 4 : 250);
repaint();
}
private void draw(ChunkPosition p, Color c, Graphics2D bg) {
double pw = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX());
double ph = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ());
double pwa = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX() + 1);
double pha = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ() + 1);
int x = (int) M.lerp(0, res, pw);
int z = (int) M.lerp(0, res, ph);
int xa = (int) M.lerp(0, res, pwa);
int za = (int) M.lerp(0, res, pha);
bg.setColor(c);
bg.fillRect(x, z, xa - x, za - z);
}
@SuppressWarnings("deprecation")
private static MCAPregenGui createAndShowGUI(Pregenerator j) throws HeadlessException {
JFrame frame;
frame = new JFrame("Pregen View");
MCAPregenGui nv = new MCAPregenGui();
frame.addKeyListener(nv);
nv.l = new ReentrantLock();
nv.frame = frame;
nv.job = j;
nv.func = (c, b) ->
{
if (b.equals(Color.pink) && c.equals(new ChunkPosition(Integer.MAX_VALUE, Integer.MAX_VALUE))) {
frame.hide();
}
nv.l.lock();
nv.order.add(() -> nv.draw(c, b, nv.bg));
nv.l.unlock();
};
frame.add(nv);
frame.setSize(1000, 1000);
frame.setVisible(true);
File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png");
if (file != null) {
try {
frame.setIconImage(ImageIO.read(file));
} catch (IOException ignored) {
Iris.reportError(ignored);
}
}
return nv;
}
public static void launch(Pregenerator g) {
J.a(() ->
{
createAndShowGUI(g);
});
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_P) {
Pregenerator.pauseResume();
}
}
public void close() {
frame.setVisible(false);
}
}
}

View File

@ -0,0 +1,389 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.IrisPregenerator;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Consumer2;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.scheduling.J;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
public class PregeneratorJob implements PregenListener {
public static PregeneratorJob instance;
private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
private static final Color COLOR_GENERATING = parseColor("#0062ff");
private static final Color COLOR_NETWORK = parseColor("#a863c2");
private static final Color COLOR_NETWORK_GENERATING = parseColor("#836b8c");
private static final Color COLOR_GENERATED = parseColor("#34eb93");
private JFrame frame;
private final PregenTask task;
private boolean saving;
private KList<Consumer<Double>> onProgress = new KList<>();
private KList<Runnable> whenDone = new KList<>();
private final IrisPregenerator pregenerator;
private PregenRenderer renderer;
private String[] info;
private Position2 min;
private Position2 max;
public PregeneratorJob(PregenTask task, PregeneratorMethod method) {
instance = this;
saving = false;
info = new String[]{"Initializing..."};
this.task = task;
this.pregenerator = new IrisPregenerator(task, method, this);
max = new Position2(0, 0);
min = new Position2(0, 0);
KList<Runnable> draw = new KList<>();
task.iterateRegions((xx, zz) -> {
min.setX(Math.min(xx << 5, min.getX()));
min.setZ(Math.min(zz << 5, min.getZ()));
max.setX(Math.max((xx << 5) + 31, max.getX()));
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
});
if (IrisSettings.get().getGui().isUseServerLaunchedGuis()) {
open();
}
J.a(this.pregenerator::start, 20);
}
public PregeneratorJob onProgress(Consumer<Double> c) {
onProgress.add(c);
return this;
}
public PregeneratorJob whenDone(Runnable r) {
whenDone.add(r);
return this;
}
public static boolean shutdownInstance() {
if (instance == null) {
return false;
}
J.a(() -> instance.pregenerator.close());
return true;
}
public static PregeneratorJob getInstance() {
return instance;
}
public static void pauseResume() {
if (instance == null) {
return;
}
if (isPaused()) {
instance.pregenerator.resume();
} else {
instance.pregenerator.pause();
}
}
public static boolean isPaused() {
if (instance == null) {
return true;
}
return instance.paused();
}
public void drawRegion(int x, int z, Color color) {
J.a(() -> {
PregenTask.iterateRegion(x, z, (xx, zz) -> {
draw(xx, zz, color);
J.sleep(3);
});
});
}
public void draw(int x, int z, Color color) {
try {
if (renderer != null && frame != null && frame.isVisible()) {
renderer.func.accept(new Position2(x, z), color);
}
} catch (Throwable ignored) {
}
}
public void stop() {
J.a(() -> {
pregenerator.close();
close();
instance = null;
});
}
public void close() {
J.a(() -> {
try {
J.sleep(3000);
frame.setVisible(false);
} catch (Throwable e) {
}
});
}
public void open() {
J.a(() -> {
try {
frame = new JFrame("Pregen View");
renderer = new PregenRenderer();
frame.addKeyListener(renderer);
renderer.l = new ReentrantLock();
renderer.frame = frame;
renderer.job = this;
renderer.func = (c, b) ->
{
renderer.l.lock();
renderer.order.add(() -> renderer.draw(c, b, renderer.bg));
renderer.l.unlock();
};
frame.add(renderer);
frame.setSize(1000, 1000);
frame.setVisible(true);
} catch (Throwable e) {
}
});
}
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
info = new String[]{
(paused() ? "PAUSED" : (saving ? "Saving... " : "Generating")) + " " + Form.f(generated) + " of " + Form.f(totalChunks) + " (" + Form.pc(percent, 0) + " Complete)",
"Speed: " + Form.f(chunksPerSecond, 0) + " Chunks/s, " + Form.f(regionsPerMinute, 1) + " Regions/m, " + Form.f(chunksPerMinute, 0) + " Chunks/m",
Form.duration(eta, 2) + " Remaining " + " (" + Form.duration(elapsed, 2) + " Elapsed)",
"Generation Method: " + method,
};
for (Consumer<Double> i : onProgress) {
i.accept(percent);
}
}
@Override
public void onChunkGenerating(int x, int z) {
draw(x, z, COLOR_GENERATING);
}
@Override
public void onChunkGenerated(int x, int z) {
draw(x, z, COLOR_GENERATED);
}
@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 onNetworkStarted(int x, int z) {
drawRegion(x, z, COLOR_NETWORK);
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
draw(x, z, COLOR_NETWORK_GENERATING);
}
@Override
public void onNetworkDownloaded(int x, int z) {
drawRegion(x, z, COLOR_NETWORK);
}
@Override
public void onClose() {
close();
instance = null;
whenDone.forEach(Runnable::run);
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
draw(x, z, COLOR_EXISTS);
}
private Position2 getMax() {
return max;
}
private Position2 getMin() {
return min;
}
private boolean paused() {
return pregenerator.paused();
}
private String[] getProgress() {
return info;
}
public static class PregenRenderer extends JPanel implements KeyListener {
private PregeneratorJob job;
private static final long serialVersionUID = 2094606939770332040L;
private final KList<Runnable> order = new KList<>();
private final int res = 512;
Graphics2D bg;
private ReentrantLock l;
private final BufferedImage image = new BufferedImage(res, res, BufferedImage.TYPE_INT_RGB);
private Consumer2<Position2, Color> func;
private JFrame frame;
public PregenRenderer() {
}
public void paint(int x, int z, Color c) {
func.accept(new Position2(x, z), c);
}
@Override
public void paint(Graphics gx) {
Graphics2D g = (Graphics2D) gx;
bg = (Graphics2D) image.getGraphics();
l.lock();
while (order.isNotEmpty()) {
try {
order.pop().run();
} catch (Throwable e) {
Iris.reportError(e);
}
}
l.unlock();
g.drawImage(image, 0, 0, getParent().getWidth(), getParent().getHeight(), (img, infoflags, x, y, width, height) -> true);
g.setColor(Color.WHITE);
g.setFont(new Font("Hevetica", Font.BOLD, 28));
String[] prog = job.getProgress();
int h = g.getFontMetrics().getHeight() + 5;
int hh = 20;
if (job.paused()) {
g.drawString("PAUSED", 20, hh += h);
g.drawString("Press P to Resume", 20, hh += h);
} else {
for (String i : prog) {
g.drawString(i, 20, hh += h);
}
g.drawString("Press P to Pause", 20, hh += h);
}
J.sleep(IrisSettings.get().getGui().isMaximumPregenGuiFPS() ? 4 : 250);
repaint();
}
private void draw(Position2 p, Color c, Graphics2D bg) {
double pw = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX());
double ph = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ());
double pwa = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX() + 1);
double pha = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ() + 1);
int x = (int) M.lerp(0, res, pw);
int z = (int) M.lerp(0, res, ph);
int xa = (int) M.lerp(0, res, pwa);
int za = (int) M.lerp(0, res, pha);
bg.setColor(c);
bg.fillRect(x, z, xa - x, za - z);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_P) {
PregeneratorJob.pauseResume();
}
}
public void close() {
frame.setVisible(false);
}
}
private static Color parseColor(String c) {
String v = (c.startsWith("#") ? c : "#" + c).trim();
try {
return Color.decode(v);
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("Error Parsing 'color', (" + c + ")");
}
return Color.RED;
}
}

View File

@ -19,11 +19,14 @@
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.gui.components.IrisRenderer;
import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
@ -36,7 +39,6 @@ import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -54,7 +56,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
public class IrisVision extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
private static final long serialVersionUID = 2094606939770332040L;
private RenderType currentType = RenderType.BIOME;
@ -70,7 +72,7 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
private boolean alt = false;
private int posX = 0;
private IrisRenderer renderer;
private World world;
private IrisWorld world;
private double velocity = 0;
private int lowq = 12;
private int posZ = 0;
@ -128,7 +130,7 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
});
private BufferedImage texture;
public IrisVision(JFrame frame) {
public VisionGUI(JFrame frame) {
m.set(8);
rs.put(1);
addMouseWheelListener(this);
@ -142,6 +144,13 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
help = false;
}
});
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
e.shutdown();
eh.shutdown();
}
});
}
@Override
@ -726,9 +735,9 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
}
}
private static void createAndShowGUI(Engine r, int s, World world) {
private static void createAndShowGUI(Engine r, int s, IrisWorld world) {
JFrame frame = new JFrame("Vision");
IrisVision nv = new IrisVision(frame);
VisionGUI nv = new VisionGUI(frame);
nv.world = world;
nv.engine = r;
nv.renderer = new IrisRenderer(r);

View File

@ -16,11 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
package com.volmit.iris.core.gui.components;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.interpolation.IrisInterpolation;
import org.bukkit.Material;
import java.awt.*;
import java.awt.image.BufferedImage;
@ -60,8 +59,4 @@ public class IrisRenderer {
return image;
}
public void set(double worldX, double worldZ) {
renderer.getWorld().getBlockAt((int) worldX, 20, (int) worldZ).setType(Material.DIAMOND_BLOCK);
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
package com.volmit.iris.core.gui.components;
public enum RenderType {
BIOME, BIOME_LAND, BIOME_SEA, REGION, CAVE_LAND, HEIGHT, OBJECT_LOAD, DECORATOR_LOAD, LAYER_LOAD

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
package com.volmit.iris.core.gui.components;
import java.awt.*;

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
package com.volmit.iris.core.gui.components;
import lombok.Builder;
import lombok.Data;

View File

@ -0,0 +1,267 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
public class IrisPregenerator {
private final PregenTask task;
private final PregeneratorMethod generator;
private final PregenListener listener;
private final Looper ticker;
private final AtomicBoolean paused;
private final AtomicBoolean shutdown;
private final RollingSequence chunksPerSecond;
private final RollingSequence chunksPerMinute;
private final RollingSequence regionsPerMinute;
private final AtomicInteger generated;
private final AtomicInteger generatedLast;
private final AtomicInteger generatedLastMinute;
private final AtomicInteger totalChunks;
private final AtomicLong startTime;
private final ChronoLatch minuteLatch;
private final AtomicReference<String> currentGeneratorMethod;
private final KSet<Position2> generatedRegions;
private final KSet<Position2> retry;
private final KSet<Position2> net;
public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) {
this.listener = listenify(listener);
generatedRegions = new KSet<>();
this.shutdown = new AtomicBoolean(false);
this.paused = new AtomicBoolean(false);
this.task = task;
this.generator = generator;
retry = new KSet<>();
net = new KSet<>();
currentGeneratorMethod = new AtomicReference<>("Void");
minuteLatch = new ChronoLatch(60000, false);
chunksPerSecond = new RollingSequence(10);
chunksPerMinute = new RollingSequence(10);
regionsPerMinute = new RollingSequence(10);
generated = new AtomicInteger(0);
generatedLast = new AtomicInteger(0);
generatedLastMinute = new AtomicInteger(0);
totalChunks = new AtomicInteger(0);
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024));
startTime = new AtomicLong(M.ms());
ticker = new Looper() {
@Override
protected long loop() {
long eta = computeETA();
int secondGenerated = generated.get() - generatedLast.get();
generatedLast.set(generated.get());
chunksPerSecond.put(secondGenerated);
if (minuteLatch.flip()) {
int minuteGenerated = generated.get() - generatedLastMinute.get();
generatedLastMinute.set(generated.get());
chunksPerMinute.put(minuteGenerated);
regionsPerMinute.put((double) minuteGenerated / 1024D);
}
listener.onTick(chunksPerSecond.getAverage(), chunksPerMinute.getAverage(),
regionsPerMinute.getAverage(),
(double) generated.get() / (double) totalChunks.get(),
generated.get(), totalChunks.get(),
totalChunks.get() - generated.get(),
eta, M.ms() - startTime.get(), currentGeneratorMethod.get());
return 1000;
}
};
}
private long computeETA() {
return (long) ((totalChunks.get() - generated.get()) *
((double) (M.ms() - startTime.get()) / (double) generated.get()));
}
public void close() {
shutdown.set(true);
}
public void start() {
init();
ticker.start();
checkRegions();
task.iterateRegions((x, z) -> visitRegion(x, z, true));
task.iterateRegions((x, z) -> visitRegion(x, z, false));
shutdown();
}
private void checkRegions() {
task.iterateRegions(this::checkRegion);
}
private void init() {
generator.init();
generator.save();
}
private void shutdown() {
listener.onSaving();
generator.close();
ticker.interrupt();
listener.onClose();
}
private void visitRegion(int x, int z, boolean regions) {
while (paused.get() && !shutdown.get()) {
J.sleep(50);
}
if (shutdown.get()) {
listener.onRegionSkipped(x, z);
return;
}
Position2 pos = new Position2(x, z);
if (generatedRegions.contains(pos)) {
return;
}
currentGeneratorMethod.set(generator.getMethod(x, z));
boolean hit = false;
if (generator.supportsRegions(x, z, listener) && regions) {
hit = true;
listener.onRegionGenerating(x, z);
generator.generateRegion(x, z, listener);
} else if (!regions) {
hit = true;
listener.onRegionGenerating(x, z);
PregenTask.iterateRegion(x, z, (xx, zz) -> generator.generateChunk(xx, zz, listener));
}
if (hit) {
listener.onRegionGenerated(x, z);
listener.onSaving();
generator.save();
generatedRegions.add(pos);
checkRegions();
}
}
private void checkRegion(int x, int z) {
if (generatedRegions.contains(new Position2(x, z))) {
return;
}
generator.supportsRegions(x, z, listener);
}
public void pause() {
paused.set(true);
}
public void resume() {
paused.set(false);
}
private PregenListener listenify(PregenListener listener) {
return new PregenListener() {
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
listener.onTick(chunksPerSecond, chunksPerMinute, regionsPerMinute, percent, generated, totalChunks, chunksRemaining, eta, elapsed, method);
}
@Override
public void onChunkGenerating(int x, int z) {
listener.onChunkGenerating(x, z);
}
@Override
public void onChunkGenerated(int x, int z) {
listener.onChunkGenerated(x, z);
generated.addAndGet(1);
}
@Override
public void onRegionGenerated(int x, int z) {
listener.onRegionGenerated(x, z);
}
@Override
public void onRegionGenerating(int x, int z) {
listener.onRegionGenerating(x, z);
}
@Override
public void onRegionSkipped(int x, int z) {
listener.onRegionSkipped(x, z);
}
@Override
public void onNetworkStarted(int x, int z) {
net.add(new Position2(x, z));
}
@Override
public void onNetworkFailed(int x, int z) {
retry.add(new Position2(x, z));
}
@Override
public void onNetworkReclaim(int revert) {
generated.addAndGet(-revert);
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
generated.addAndGet(1);
}
@Override
public void onNetworkDownloaded(int x, int z) {
net.remove(new Position2(x, z));
}
@Override
public void onClose() {
listener.onClose();
}
@Override
public void onSaving() {
listener.onSaving();
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
listener.onChunkExistsInRegionGen(x, z);
}
};
}
public boolean paused() {
return paused.get();
}
}

View File

@ -0,0 +1,49 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
public interface PregenListener {
void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method);
void onChunkGenerating(int x, int z);
void onChunkGenerated(int x, int z);
void onRegionGenerated(int x, int z);
void onRegionGenerating(int x, int z);
void onRegionSkipped(int x, int z);
void onNetworkStarted(int x, int z);
void onNetworkFailed(int x, int z);
void onNetworkReclaim(int revert);
void onNetworkGeneratedChunk(int x, int z);
void onNetworkDownloaded(int x, int z);
void onClose();
void onSaving();
void onChunkExistsInRegionGen(int x, int z);
}

View File

@ -0,0 +1,72 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiraled;
import com.volmit.iris.util.math.Spiraler;
import lombok.Builder;
import lombok.Data;
import java.util.Comparator;
@Builder
@Data
public class PregenTask {
@Builder.Default
private Position2 center = new Position2(0, 0);
@Builder.Default
private int radius = 1;
private static final KList<Position2> order = computeChunkOrder();
public void iterateRegions(Spiraled s) {
new Spiraler(radius * 2, radius * 2, s)
.setOffset(center.getX(), center.getZ()).drain();
}
public static void iterateRegion(int xr, int zr, Spiraled s) {
for (Position2 i : order) {
s.on(i.getX() + (xr << 5), i.getZ() + (zr << 5));
}
}
public void iterateAllChunks(Spiraled s) {
new Spiraler(radius * 2, radius * 2, (x, z) -> iterateRegion(x, z, s))
.setOffset(center.getX(), center.getZ()).drain();
}
private static KList<Position2> computeChunkOrder() {
Position2 center = new Position2(15, 15);
KList<Position2> p = new KList<>();
new Spiraler(33, 33, (x, z) -> {
int xx = x + 15;
int zz = z + 15;
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new Position2(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(center)));
return p;
}
}

View File

@ -0,0 +1,77 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
/**
* Represents something that is capable of generating in chunks or regions, or both
*/
public interface PregeneratorMethod {
/**
* This is called before any generate methods are called. Setup your generator here
*/
void init();
/**
* This is called after the pregenerator is done. Save your work and stop threads
*/
void close();
/**
* This is called every X amount of chunks or regions. Save work,
* but no need to save all of it. At the end, close() will still be called.
*/
void save();
/**
* Return true if regions can be generated
*
* @param x the x region
* @param z the z region
* @return true if they can be
*/
boolean supportsRegions(int x, int z, PregenListener listener);
/**
* Return the name of the method being used
*
* @param x the x region
* @param z the z region
* @return the name
*/
String getMethod(int x, int z);
/**
* Called to generate a region. Execute sync, if multicore internally, wait
* for the task to complete
*
* @param x the x
* @param z the z
* @param listener signal chunks generating & generated. Parallel capable.
*/
void generateRegion(int x, int z, PregenListener listener);
/**
* Called to generate a chunk. You can go async so long as save will wait on the threads to finish
*
* @param x the x
* @param z the z
* @param listener
*/
void generateChunk(int x, int z, PregenListener listener);
}

View File

@ -0,0 +1,67 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import io.papermc.lib.PaperLib;
import org.bukkit.World;
public class AsyncOrMedievalPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod method;
public AsyncOrMedievalPregenMethod(World world, int threads) {
method = PaperLib.isPaper() ? new AsyncPregenMethod(world, threads) : new MedievalPregenMethod(world);
}
@Override
public void init() {
method.init();
}
@Override
public void close() {
method.close();
}
@Override
public void save() {
method.save();
}
@Override
public String getMethod(int x, int z) {
return method.getMethod(x, z);
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
method.generateChunk(x, z, listener);
}
}

View File

@ -0,0 +1,124 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.util.concurrent.CompletableFuture;
public class AsyncPregenMethod implements PregeneratorMethod {
private final World world;
private final MultiBurst burst;
private final KList<CompletableFuture<?>> future;
public AsyncPregenMethod(World world, int threads) {
if (!PaperLib.isPaper()) {
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
}
this.world = world;
burst = new MultiBurst("Iris Async Pregenerator", IrisSettings.get().getConcurrency().getPregenThreadPriority(), threads);
future = new KList<>(1024);
}
private void unloadAndSaveAllChunks() {
try {
J.sfut(() -> {
for (Chunk i : world.getLoadedChunks()) {
i.unload(true);
}
world.save();
}).get();
} catch (Throwable e) {
e.printStackTrace();
}
}
private void completeChunk(int x, int z, PregenListener listener) {
try {
PaperLib.getChunkAtAsync(world, x, z, true).get();
listener.onChunkGenerated(x, z);
} catch (Throwable e) {
e.printStackTrace();
}
}
private void waitForChunks() {
for (CompletableFuture<?> i : future) {
try {
i.get();
} catch (Throwable e) {
e.printStackTrace();
}
}
future.clear();
}
@Override
public void init() {
unloadAndSaveAllChunks();
}
@Override
public String getMethod(int x, int z) {
return "Async";
}
@Override
public void close() {
waitForChunks();
burst.shutdownAndAwait();
unloadAndSaveAllChunks();
}
@Override
public void save() {
waitForChunks();
unloadAndSaveAllChunks();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if (future.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) {
waitForChunks();
}
listener.onChunkGenerating(x, z);
future.add(burst.complete(() -> completeChunk(x, z, listener)));
}
}

View File

@ -0,0 +1,59 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
public class DummyPregenMethod implements PregeneratorMethod {
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public String getMethod(int x, int z) {
return "Dummy";
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
}
}

View File

@ -0,0 +1,76 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.headless.HeadlessGenerator;
import com.volmit.iris.engine.headless.HeadlessWorld;
import lombok.Getter;
public class HeadlessPregenMethod implements PregeneratorMethod {
private final HeadlessWorld world;
@Getter
private final HeadlessGenerator generator;
public HeadlessPregenMethod(HeadlessWorld world) {
this(world, world.generate());
}
public HeadlessPregenMethod(HeadlessWorld world, HeadlessGenerator generator) {
this.world = world;
this.generator = generator;
}
@Override
public void init() {
}
@Override
public void close() {
generator.close();
}
@Override
public void save() {
generator.save();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return true;
}
@Override
public String getMethod(int x, int z) {
return "Headless";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
generator.generateRegion(x, z, listener);
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,101 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.headless.HeadlessWorld;
import com.volmit.iris.util.math.Position2;
import org.bukkit.World;
import java.io.File;
public class HybridPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod headless;
private final PregeneratorMethod inWorld;
private final World world;
public HybridPregenMethod(World world, int threads) {
this.world = world;
headless = supportsHeadless(world)
? new HeadlessPregenMethod(HeadlessWorld.from(world)) : new DummyPregenMethod();
inWorld = new AsyncOrMedievalPregenMethod(world, threads);
}
private boolean supportsHeadless(World world) {
return IrisWorlds.access(world) != null && IrisSettings.get().getGenerator().isMcaPregenerator();
}
@Override
public String getMethod(int x, int z) {
return "Hybrid<" + ((supportsRegions(x, z, null) ? headless.getMethod(x, z) : inWorld.getMethod(x, z)) + ">");
}
@Override
public void init() {
headless.init();
inWorld.init();
}
@Override
public void close() {
headless.close();
inWorld.close();
}
@Override
public void save() {
headless.save();
inWorld.save();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
if (headless instanceof DummyPregenMethod) {
return false;
}
boolean r = !new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca").exists();
if (!r && listener != null) {
try {
for (Position2 i : ((HeadlessPregenMethod) headless).getGenerator().getChunksInRegion(x, z)) {
listener.onChunkExistsInRegionGen((x << 5) + i.getX(), (z << 5) + i.getZ());
}
} catch (Throwable e) {
Iris.reportError(e);
}
}
return r;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
headless.generateRegion(x, z, listener);
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
inWorld.generateChunk(x, z, listener);
}
}

View File

@ -0,0 +1,108 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.util.concurrent.CompletableFuture;
public class MedievalPregenMethod implements PregeneratorMethod {
private final World world;
private final KList<CompletableFuture<?>> futures;
public MedievalPregenMethod(World world) {
this.world = world;
futures = new KList<>();
}
private void waitForChunks() {
for (CompletableFuture<?> i : futures) {
try {
i.get();
} catch (Throwable e) {
e.printStackTrace();
}
}
futures.clear();
}
private void unloadAndSaveAllChunks() {
waitForChunks();
try {
J.sfut(() -> {
for (Chunk i : world.getLoadedChunks()) {
i.unload(true);
}
world.save();
}).get();
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public void init() {
unloadAndSaveAllChunks();
}
@Override
public void close() {
unloadAndSaveAllChunks();
}
@Override
public void save() {
unloadAndSaveAllChunks();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public String getMethod(int x, int z) {
return "Medieval";
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) {
waitForChunks();
}
listener.onChunkGenerating(x, z);
futures.add(J.sfut(() -> {
world.getChunkAt(x, z);
listener.onChunkGenerated(x, z);
}));
}
}

View File

@ -0,0 +1,261 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.pregenerator.syndicate.SyndicateClient;
import com.volmit.iris.core.pregenerator.syndicate.command.*;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.scheduling.J;
import lombok.Getter;
import org.zeroturnaround.zip.ZipUtil;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
public class SyndicatePregenMethod implements PregeneratorMethod {
@Getter
private String address;
private String nickname;
private int port;
private String password;
private IrisDimension dimension;
private boolean ready = false;
private File worldFolder;
private UUID pack = UUID.randomUUID();
private long seed;
public SyndicatePregenMethod(String nickname, File worldFolder, String address, int port, String password, IrisDimension dimension, long seed) {
this.seed = seed;
this.worldFolder = worldFolder;
this.address = address;
this.port = port;
this.password = password;
this.dimension = dimension;
}
private SyndicateClient.SyndicateClientBuilder connect() {
return SyndicateClient.builder().address(address).port(port);
}
public synchronized void setup() {
if (ready) {
return;
}
ready = false;
try {
connect().command(SyndicateInstallPack
.builder()
.dimension(dimension)
.pack(pack)
.seed(seed)
.build())
.output((o) -> {
File to = new File(Iris.getTemp(), "send-" + pack.toString() + ".zip");
ZipUtil.pack(dimension.getLoader().getDataFolder(), to);
try {
IO.writeAll(to, o);
} catch (IOException e) {
e.printStackTrace();
}
to.deleteOnExit();
})
.build().go((response, data) -> {
if (response instanceof SyndicateBusy) {
throw new RuntimeException("Service is busy, will try later");
}
ready = true;
});
ready = true;
} catch (Throwable throwable) {
if (throwable instanceof RuntimeException) {
ready = false;
return;
}
throwable.printStackTrace();
}
}
public boolean canGenerate() {
if (!ready) {
J.a(this::setup);
}
return ready;
}
@Override
public void init() {
J.a(this::setup);
}
@Override
public void close() {
if (ready) {
try {
connect()
.command(SyndicateClose
.builder()
.pack(pack)
.build())
.build()
.go((__, __b) -> {
});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return true;
}
@Override
public String getMethod(int x, int z) {
return "Syndicate<" + nickname + ">";
}
private double checkProgress(int x, int z) {
AtomicDouble progress = new AtomicDouble(-1);
try {
connect()
.command(SyndicateGetProgress.builder()
.pack(pack).build()).output((i) -> {
}).build().go((response, o) -> {
if (response instanceof SyndicateSendProgress) {
if (((SyndicateSendProgress) response).isAvailable()) {
progress.set(((SyndicateSendProgress) response).getProgress());
File f = new File(worldFolder, "region/r." + x + "." + z + ".mca");
try {
f.getParentFile().mkdirs();
IO.writeAll(f, o);
progress.set(1000);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return progress.get();
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
if (!ready) {
throw new RuntimeException();
}
try {
connect().command(SyndicateGenerate
.builder()
.x(x).z(z).pack(pack)
.build())
.build().go((response, data) -> {
if (response instanceof SyndicateOK) {
listener.onNetworkStarted(x, z);
J.a(() -> {
double lastp = 0;
int calls = 0;
boolean installed = false;
while (true) {
J.sleep(100);
double progress = checkProgress(x, z);
if (progress == 1000) {
installed = true;
AtomicInteger a = new AtomicInteger(calls);
PregenTask.iterateRegion(x, z, (xx, zz) -> {
if (a.decrementAndGet() < 0) {
listener.onNetworkGeneratedChunk(xx, zz);
}
});
calls = 1024;
} else if (progress < 0) {
break;
}
int change = (int) Math.floor((progress - lastp) * 1024D);
change = change == 0 ? 1 : change;
AtomicInteger a = new AtomicInteger(calls);
AtomicInteger b = new AtomicInteger(change);
PregenTask.iterateRegion(x, z, (xx, zz) -> {
if (a.decrementAndGet() < 0) {
if (b.decrementAndGet() >= 0) {
listener.onNetworkGeneratedChunk(xx, zz);
}
}
});
calls += change;
}
if (!installed) {
// TODO RETRY REGION
return;
}
listener.onNetworkDownloaded(x, z);
});
} else if (response instanceof SyndicateInstallFirst) {
ready = false;
throw new RuntimeException();
} else if (response instanceof SyndicateBusy) {
throw new RuntimeException();
} else {
throw new RuntimeException();
}
});
} catch (Throwable throwable) {
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
}
throwable.printStackTrace();
}
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
}
}

View File

@ -0,0 +1,51 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate;
import com.volmit.iris.core.pregenerator.syndicate.command.SyndicateCommand;
import com.volmit.iris.util.function.Consumer2;
import lombok.Builder;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.function.Consumer;
@Builder
public class SyndicateClient {
private String address;
private int port;
private SyndicateCommand command;
private Consumer<DataOutputStream> output;
public void go(Consumer2<SyndicateCommand, DataInputStream> handler) throws Throwable {
Socket socket = new Socket(address, port);
DataInputStream i = new DataInputStream(socket.getInputStream());
DataOutputStream o = new DataOutputStream(socket.getOutputStream());
SyndicateCommandIO.write(command, o);
if (output != null) {
output.accept(o);
}
o.flush();
handler.accept(SyndicateCommandIO.read(i), i);
socket.close();
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate;
import com.google.gson.Gson;
import com.volmit.iris.core.pregenerator.syndicate.command.SyndicateCommand;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class SyndicateCommandIO {
private static final Gson gson = new Gson();
public static SyndicateCommand read(DataInputStream in) throws IOException, ClassNotFoundException {
String clazz = in.readUTF();
return (SyndicateCommand) gson.fromJson(in.readUTF(), Class.forName(clazz));
}
public static void write(SyndicateCommand c, DataOutputStream out) throws IOException {
out.writeUTF(c.getClass().getCanonicalName());
out.writeUTF(gson.toJson(c));
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.syndicate.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.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 SyndicateServer 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 SyndicateServer(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 {
SyndicateCommand cmd = handle(SyndicateCommandIO.read(i), i, o);
if (cmd != null) {
SyndicateCommandIO.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 SyndicateCommand handle(SyndicateCommand command, DataInputStream i, DataOutputStream o) throws Throwable {
if (command instanceof SyndicateInstallPack) {
if (busy) {
return new SyndicateBusy();
}
if (generator != null) {
generator.close();
IO.delete(generator.getWorld().getWorld().worldFolder());
generator = null;
}
UUID id = ((SyndicateInstallPack) 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(), ((SyndicateInstallPack) command).getDimension(), ((SyndicateInstallPack) command).getSeed());
w.setStudio(true);
generator = w.generate();
return new SyndicateOK();
}
if (command instanceof SyndicateGenerate) {
if (busy) {
return new SyndicateBusy();
}
if (generator == null || !Objects.equals(currentId, ((SyndicateGenerate) command).getPack())) {
return new SyndicateInstallFirst();
}
g.set(0);
busy = true;
J.a(() -> {
busy = false;
lastGeneratedRegion = generator.generateRegionToFile(((SyndicateGenerate) command).getX(), ((SyndicateGenerate) command).getZ(), this);
});
return new SyndicateOK();
}
if (command instanceof SyndicateClose) {
if (generator != null && Objects.equals(currentId, ((SyndicateClose) command).getPack()) && !busy) {
generator.close();
IO.delete(generator.getWorld().getWorld().worldFolder());
generator = null;
currentId = null;
}
}
if (command instanceof SyndicateGetProgress) {
if (generator != null && busy && Objects.equals(currentId, ((SyndicateGetProgress) command).getPack())) {
return SyndicateSendProgress.builder().progress((double) g.get() / 1024D).build();
} else if (generator != null && !busy && Objects.equals(currentId, ((SyndicateGetProgress) command).getPack()) && lastGeneratedRegion != null && lastGeneratedRegion.exists()) {
SyndicateCommandIO.write(SyndicateSendProgress
.builder()
.progress(1).available(true)
.build(), o);
o.writeLong(lastGeneratedRegion.length());
IO.writeAll(lastGeneratedRegion, o);
return null;
} else if (generator == null) {
return new SyndicateInstallFirst();
} else {
return new SyndicateBusy();
}
}
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 onNetworkStarted(int x, int z) {
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
}
@Override
public void onNetworkDownloaded(int x, int z) {
}
@Override
public void onClose() {
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
}
}

View File

@ -0,0 +1,22 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
public class SyndicateBusy implements SyndicateCommand {
}

View File

@ -0,0 +1,35 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SyndicateClose implements SyndicateCommand {
@Builder.Default
private UUID pack = UUID.randomUUID();
}

View File

@ -0,0 +1,23 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
public interface SyndicateCommand {
}

View File

@ -0,0 +1,22 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
public class SyndicateError implements SyndicateCommand {
}

View File

@ -0,0 +1,39 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SyndicateGenerate implements SyndicateCommand {
@Builder.Default
private int x = 0;
@Builder.Default
private int z = 0;
@Builder.Default
private UUID pack = UUID.randomUUID();
}

View File

@ -0,0 +1,35 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SyndicateGetProgress implements SyndicateCommand {
@Builder.Default
private UUID pack = UUID.randomUUID();
}

View File

@ -0,0 +1,22 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
public class SyndicateInstallFirst implements SyndicateCommand {
}

View File

@ -0,0 +1,42 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
import com.volmit.iris.engine.object.IrisDimension;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SyndicateInstallPack implements SyndicateCommand {
@Builder.Default
private UUID pack = UUID.randomUUID();
@Builder.Default
private long seed = 1337;
@Builder.Default
private IrisDimension dimension = null;
}

View File

@ -0,0 +1,22 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
public class SyndicateOK implements SyndicateCommand {
}

View File

@ -0,0 +1,35 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.syndicate.command;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SyndicateSendProgress implements SyndicateCommand {
@Builder.Default
private double progress = 0;
@Builder.Default
private boolean available = false;
}

View File

@ -0,0 +1,220 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.tools;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.headless.HeadlessWorld;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.exceptions.MissingDimensionException;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import lombok.Data;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.WorldCreator;
import java.util.function.Consumer;
/**
* Makes it a lot easier to setup an engine, world, studio or whatever
*/
@Data
@Accessors(fluent = true, chain = true)
public class IrisCreator {
/**
* Specify an area to pregenerate during creation
*/
private PregenTask pregen;
/**
* Specify a sender to get updates & progress info + tp when world is created.
*/
private VolmitSender sender;
/**
* The seed to use for this generator
*/
private long seed = RNG.r.nextLong();
/**
* The dimension to use. This can be any online dimension, or a dimension in the
* packs folder
*/
private String dimension = IrisSettings.get().getGenerator().getDefaultWorldType();
/**
* The name of this world.
*/
private String name = "irisworld";
/**
* Headless mode allows Iris to generate / query engine information
* without needing an actual world loaded. This is normally only used
* for pregeneration purposes but it could be used for mapping.
*/
private boolean headless = false;
/**
* Studio mode makes the engine hotloadable and uses the dimension in
* your Iris/packs folder instead of copying the dimension files into
* the world itself. Studio worlds are deleted when they are unloaded.
*/
private boolean studio = false;
/**
* Create the IrisAccess (contains the world)
*
* @return the IrisAccess
* @throws IrisException shit happens
*/
public IrisAccess create() throws IrisException {
IrisDimension d = IrisToolbelt.getDimension(dimension());
IrisAccess access = null;
Consumer<Double> prog = (pxx) -> {
double px = (headless && pregen != null) ? pxx / 2 : pxx;
if (pregen != null && !headless) {
px = (px / 2) + 0.5;
}
if (sender != null) {
if (sender.isPlayer()) {
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generating " + Form.pc(px)));
} else {
sender.sendMessage("Generating " + Form.f(px, 0));
}
}
};
if (d == null) {
throw new MissingDimensionException("Cannot find dimension '" + dimension() + "'");
}
if (headless) {
HeadlessWorld w = new HeadlessWorld(name, d, seed, studio);
access = w.generate().getGenerator();
} else {
O<Boolean> done = new O<>();
done.set(false);
WorldCreator wc = new IrisWorldCreator()
.dimension(dimension)
.name(name)
.seed(seed)
.studio(studio)
.create();
access = (IrisAccess) wc.generator();
IrisAccess finalAccess1 = access;
J.a(() ->
{
int req = 400;
while (finalAccess1.getGenerated() < req && !done.get()) {
double v = (double) finalAccess1.getGenerated() / (double) req;
if (pregen != null) {
v /= 2;
}
if (sender.isPlayer()) {
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - finalAccess1.getGenerated()) + " Left)"))));
J.sleep(50);
} else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - finalAccess1.getGenerated()) + " Left)")));
J.sleep(1000);
}
if (finalAccess1.isFailing()) {
sender.sendMessage("Generation Failed!");
break;
}
}
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generation Complete"));
});
wc.createWorld();
done.set(true);
}
if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
}
IrisAccess finalAccess = access;
Runnable loadup = () -> {
try {
J.sfut(() -> {
if (headless) {
O<Boolean> done = new O<>();
done.set(false);
J.a(() ->
{
int req = 400;
while (finalAccess.getGenerated() < req && !done.get()) {
double v = (double) finalAccess.getGenerated() / (double) req;
v = (v / 2) + 0.5;
if (sender.isPlayer()) {
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - finalAccess.getGenerated()) + " Left)"))));
J.sleep(50);
} else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - finalAccess.getGenerated()) + " Left)")));
J.sleep(1000);
}
if (finalAccess.isFailing()) {
sender.sendMessage("Generation Failed!");
break;
}
}
sender.player().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(C.WHITE + "Generation Complete"));
});
finalAccess.getHeadlessGenerator().getWorld().load();
done.set(true);
}
}).get();
} catch (Throwable e) {
e.printStackTrace();
}
};
if (pregen != null) {
IrisToolbelt.pregenerate(pregen, access).onProgress(prog).whenDone(loadup);
} else {
loadup.run();
}
return access;
}
}

View File

@ -0,0 +1,148 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import java.io.File;
/**
* Something you really want to wear if working on Iris. Shit gets pretty hectic down there.
* Hope you packed snacks & road sodas.
*/
public class IrisToolbelt {
/**
* Will find / download / search for the dimension or return null
* <p>
* - You can provide a dimenson in the packs folder by the folder name
* - You can provide a github repo by using (assumes branch is master unless specified)
* - GithubUsername/repository
* - GithubUsername/repository/branch
*
* @param dimension the dimension id such as overworld or flat
* @return the IrisDimension or null
*/
public static IrisDimension getDimension(String dimension) {
File pack = Iris.instance.getDataFolder("packs", dimension);
if (!pack.exists()) {
Iris.proj.downloadSearch(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), dimension, false, false);
}
if (!pack.exists()) {
return null;
}
return new IrisDataManager(pack).getDimensionLoader().load(dimension);
}
/**
* Create a world with plenty of options
*
* @return the creator builder
*/
public static IrisCreator createWorld() {
return new IrisCreator();
}
/**
* Checks if the given world is an Iris World (same as access(world) != null)
*
* @param world the world
* @return true if it is an Iris Access world
*/
public static boolean isIrisWorld(World world) {
return access(world) != null;
}
/**
* Get the Iris generator for the given world
*
* @param world the given world
* @return the IrisAccess or null if it's not an Iris World
*/
public static IrisAccess access(World world) {
return IrisWorlds.access(world);
}
/**
* Start a pregenerator task
*
* @param task the scheduled task
* @param method the method to execute the task
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method) {
return new PregeneratorJob(task, method);
}
/**
* Start a pregenerator task. If the supplied generator is headless, headless mode is used,
* otherwise Hybrid mode is used.
*
* @param task the scheduled task
* @param access the Iris Generator
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, IrisAccess access) {
if (access.isHeadless()) {
return pregenerate(task, new HeadlessPregenMethod(access.getHeadlessGenerator().getWorld(), access.getHeadlessGenerator()));
}
return pregenerate(task, new HybridPregenMethod(access.getCompound().getWorld().realWorld(), IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())));
}
/**
* Start a pregenerator task. If the supplied generator is headless, headless mode is used,
* otherwise Hybrid mode is used.
*
* @param task the scheduled task
* @param world the World
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, World world) {
if (isIrisWorld(world)) {
return pregenerate(task, access(world));
}
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())));
}
/**
* Evacuate all players from the world into literally any other world.
* If there are no other worlds, kick them! Not the best but what's mine is mine sometimes...
*
* @param world the world to evac
*/
public static void evacuate(World world) {
IrisWorlds.evacuate(world);
}
}

View File

@ -16,12 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
package com.volmit.iris.core.tools;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.fakenews.FakeWorld;
import com.volmit.iris.engine.object.common.IrisWorld;
import org.bukkit.World;
import org.bukkit.WorldCreator;
@ -78,8 +78,14 @@ public class IrisWorldCreator {
public WorldCreator create() {
EngineCompositeGenerator g = new EngineCompositeGenerator(dimensionName, !studio);
g.initialize(new FakeWorld(name, minHeight, maxHeight, seed, new File(name), findEnvironment()));
g.initialize(IrisWorld.builder()
.name(name)
.minHeight(minHeight)
.maxHeight(maxHeight)
.seed(seed)
.worldFolder(new File(name))
.environment(findEnvironment())
.build());
return new WorldCreator(name)
.environment(findEnvironment())
.generateStructures(true)
@ -94,4 +100,9 @@ public class IrisWorldCreator {
return dim.getEnvironment();
}
}
public IrisWorldCreator studio(boolean studio) {
this.studio = studio;
return this;
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.IrisAccess;

View File

@ -107,15 +107,16 @@ public class IrisComplex implements DataProvider {
}
public IrisComplex(Engine engine, boolean simple) {
int cacheSize = 1024 * 128;
this.rng = new RNG(engine.getWorld().getSeed());
int cacheSize = 131072;
IrisBiome emptyBiome = new IrisBiome();
this.rng = new RNG(engine.getWorld().seed());
this.data = engine.getData();
double height = engine.getHeight();
fluidHeight = engine.getDimension().getFluidHeight();
generators = new KList<>();
focus = engine.getFocus();
IrisRegion focusRegion = focus != null ? findRegion(focus, engine) : null;
RNG rng = new RNG(engine.getWorld().getSeed());
RNG rng = new RNG(engine.getWorld().seed());
//@builder
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
.getAllBiomes(this).forEach((b) -> b
@ -124,7 +125,7 @@ public class IrisComplex implements DataProvider {
overlayStream = ProceduralStream.ofDouble((x, z) -> 0D);
engine.getDimension().getOverlayNoise().forEach((i) -> overlayStream.add((x, z) -> i.get(rng, x, z)));
rngStream = ProceduralStream.of((x, z) -> new RNG(((x.longValue()) << 32) | (z.longValue() & 0xffffffffL))
.nextParallelRNG(engine.getWorld().getSeed()), Interpolated.RNG);
.nextParallelRNG(engine.getWorld().seed()), Interpolated.RNG);
chunkRngStream = rngStream.blockToChunkCoords();
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
.select(engine.getDimension().getRockPalette().getBlockData(data));
@ -151,7 +152,7 @@ public class IrisComplex implements DataProvider {
.onNull("")
.convertCached((s) -> {
if (s.isEmpty()) {
return new IrisBiome();
return emptyBiome;
}
return data.getBiomeLoader().load(s)
@ -193,12 +194,11 @@ public class IrisComplex implements DataProvider {
.convertAware2D(this::implode).cache2D(cacheSize);
heightStream = ProceduralStream.of((x, z) -> {
IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z);
return getHeight(engine, b, x, z, engine.getWorld().getSeed());
return getHeight(engine, b, x, z, engine.getWorld().seed());
}, Interpolated.DOUBLE).cache2D(cacheSize);
slopeStream = heightStream.slope(3).interpolate().bilinear(3, 3).cache2D(cacheSize);
slopeStream = heightStream.slope(3).cache2D(cacheSize);
objectChanceStream = ProceduralStream.ofDouble((x, z) -> {
if(engine.getDimension().hasFeatures(engine))
{
if (engine.getDimension().hasFeatures(engine)) {
AtomicDouble str = new AtomicDouble(1D);
engine.getFramework().getEngineParallax().forEachFeature(x, z, (i)
-> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z))));

View File

@ -25,9 +25,9 @@ import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomePaletteLayer;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
@ -41,8 +41,6 @@ import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class IrisEngine extends BlockPopulator implements Engine {
@Getter
@ -88,7 +86,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
private double maxBiomeDecoratorDensity;
public IrisEngine(EngineTarget target, EngineCompound compound, int index) {
Iris.info("Initializing Engine: " + target.getWorld().getName() + "/" + target.getDimension().getLoadKey() + " (" + target.getHeight() + " height)");
Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + target.getHeight() + " height)");
metrics = new EngineMetrics(32);
this.target = target;
this.framework = new IrisEngineFramework(this);
@ -136,6 +134,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
closed = true;
getWorldManager().close();
getFramework().close();
getTarget().close();
}
@Override
@ -158,21 +157,39 @@ public class IrisEngine extends BlockPopulator implements Engine {
return z / getDimension().getTerrainZoom();
}
@ChunkCoordinates
@Override
public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
BurstExecutor b = burst().burst(16);
// This is a very weird optimization, but it works
// Basically we precache multicore the biome stream which effectivley
// makes the biome stream, interpolation & noise engine run in parallel without mca
for(int i = 0; i < vblocks.getWidth(); i++)
{
int finalI = i;
b.queue(() -> {
for(int j = 0; j < vblocks.getDepth(); j++)
{
getFramework().getComplex().getTrueBiomeStream().get(x+ finalI,z+j);
}
});
}
b.complete();
switch (getDimension().getTerrainMode()) {
case NORMAL -> {
getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4);
getFramework().getBiomeActuator().actuate(x, z, vbiomes);
getFramework().getTerrainActuator().actuate(x, z, vblocks);
getFramework().getBiomeActuator().actuate(x, z, vbiomes);
getFramework().getCaveModifier().modify(x, z, vblocks);
getFramework().getRavineModifier().modify(x, z, vblocks);
getFramework().getPostModifier().modify(x, z, vblocks);
getFramework().getDecorantActuator().actuate(x, z, vblocks);
getFramework().getEngineParallax().insertParallax(x, z, vblocks);
getFramework().getEngineParallax().insertParallax(x >> 4, z >> 4, vblocks);
getFramework().getDepositModifier().modify(x, z, vblocks);
}
case ISLANDS -> {
@ -195,6 +212,11 @@ public class IrisEngine extends BlockPopulator implements Engine {
return getData().getBiomeLoader().load(getDimension().getFocus());
}
@Override
public void hotloading() {
close();
}
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk c) {
getWorldManager().spawnInitialEntities(c);

View File

@ -20,6 +20,7 @@ package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineCompound;
import com.volmit.iris.engine.framework.EngineData;
@ -28,6 +29,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisDimensionIndex;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KList;
@ -37,7 +39,6 @@ import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
@ -50,7 +51,7 @@ import java.util.List;
public class IrisEngineCompound implements EngineCompound {
@Getter
private World world;
private IrisWorld world;
private final AtomicRollingSequence wallClock;
@ -77,10 +78,10 @@ public class IrisEngineCompound implements EngineCompound {
@Setter
private boolean studio;
public IrisEngineCompound(World world, IrisDimension rootDimension, IrisDataManager data, int maximumThreads) {
public IrisEngineCompound(IrisWorld world, IrisDimension rootDimension, IrisDataManager data, int maximumThreads) {
wallClock = new AtomicRollingSequence(32);
this.rootDimension = rootDimension;
Iris.info("Initializing Engine Composite for " + world.getName());
Iris.info("Initializing Engine Composite for " + world.name());
this.world = world;
engineMetadata = EngineData.load(getEngineMetadataFile());
engineMetadata.setDimension(rootDimension.getLoadKey());
@ -97,7 +98,7 @@ public class IrisEngineCompound implements EngineCompound {
} else {
double totalWeight = 0D;
engines = new Engine[rootDimension.getDimensionalComposite().size()];
burster = engines.length > 1 ? new MultiBurst(engines.length) : null;
burster = engines.length > 1 ? new MultiBurst("Iris Compound " + rootDimension.getName(), IrisSettings.get().getConcurrency().getEngineThreadPriority(), engines.length) : null;
int threadDist = (Math.max(2, maximumThreads - engines.length)) / engines.length;
if ((threadDist * engines.length) + engines.length > maximumThreads) {
@ -208,7 +209,7 @@ public class IrisEngineCompound implements EngineCompound {
}
private File getEngineMetadataFile() {
return new File(world.getWorldFolder(), "iris/engine-metadata.json");
return new File(world.worldFolder(), "iris/engine-metadata.json");
}
@Override
@ -274,11 +275,6 @@ public class IrisEngineCompound implements EngineCompound {
return defaultEngine;
}
@Override
public void updateWorld(World world) {
this.world = world;
}
@Override
public void hotload() {
for (int i = 0; i < getSize(); i++) {

View File

@ -27,6 +27,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.hunk.view.BiomeGridHunkView;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.block.Biome;
@ -37,9 +38,10 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
public IrisBiomeActuator(Engine engine) {
super(engine, "Biome");
rng = new RNG(engine.getWorld().getSeed() + 243995);
rng = new RNG(engine.getWorld().seed() + 243995);
}
@BlockCoordinates
private boolean injectBiome(Hunk<Biome> h, int x, int y, int z, Object bb) {
try {
if (h instanceof BiomeGridHunkView hh) {
@ -59,6 +61,7 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
return false;
}
@BlockCoordinates
@Override
public void onActuate(int x, int z, Hunk<Biome> h) {
PrecisionStopwatch p = PrecisionStopwatch.start();

View File

@ -24,6 +24,7 @@ import com.volmit.iris.engine.framework.EngineAssignedActuator;
import com.volmit.iris.engine.framework.EngineDecorator;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
@ -50,7 +51,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
public IrisDecorantActuator(Engine engine) {
super(engine, "Decorant");
shouldRay = shouldRayDecorate();
this.rng = new RNG(engine.getTarget().getWorld().getSeed());
this.rng = new RNG(engine.getTarget().getWorld().seed());
surfaceDecorator = new IrisSurfaceDecorator(getEngine());
ceilingDecorator = new IrisCeilingDecorator(getEngine());
seaSurfaceDecorator = new IrisSeaSurfaceDecorator(getEngine());
@ -58,6 +59,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
seaFloorDecorator = new IrisSeaFloorDecorator(getEngine());
}
@BlockCoordinates
@Override
public void onActuate(int x, int z, Hunk<BlockData> output) {
if (!getEngine().getDimension().isDecorate()) {

View File

@ -23,6 +23,7 @@ import com.volmit.iris.engine.framework.EngineAssignedActuator;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
@ -45,11 +46,12 @@ public class IrisTerrainIslandActuator extends EngineAssignedActuator<BlockData>
public IrisTerrainIslandActuator(Engine engine) {
super(engine, "TerrainIsland");
rng = new RNG(engine.getWorld().getSeed());
rng = new RNG(engine.getWorld().seed());
carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty();
hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat();
}
@BlockCoordinates
@Override
public void onActuate(int x, int z, Hunk<BlockData> h) {
PrecisionStopwatch p = PrecisionStopwatch.start();

View File

@ -23,6 +23,7 @@ import com.volmit.iris.engine.framework.EngineAssignedActuator;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
@ -42,11 +43,12 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
public IrisTerrainNormalActuator(Engine engine) {
super(engine, "Terrain");
rng = new RNG(engine.getWorld().getSeed());
rng = new RNG(engine.getWorld().seed());
carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty();
hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat();
}
@BlockCoordinates
@Override
public void onActuate(int x, int z, Hunk<BlockData> h) {
PrecisionStopwatch p = PrecisionStopwatch.start();

View File

@ -25,6 +25,7 @@ import com.volmit.iris.util.collection.KSet;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Leaves;
public class B {
private static final Material AIR_MATERIAL = Material.AIR;
@ -103,7 +104,6 @@ public class B {
public static BlockData getOrNull(String bdxf) {
try {
String bd = bdxf.trim();
BlockData bdx = parseBlockData(bd);
if (bdx == null) {
@ -143,6 +143,12 @@ public class B {
}
BlockData bx = Bukkit.createBlockData(ix);
if(bx instanceof Leaves)
{
((Leaves) bx).setPersistent(true);
}
blockDataCache.put(ix, bx);
return bx;
} catch (Throwable e) {
@ -151,6 +157,7 @@ public class B {
}
String i = ix.toUpperCase().trim();
i = i.equals("GRASS_PATH") ? "DIRT_PATH" : i;
i = i.equals("WOOL") ? "WHITE_WOOL" : i;
i = i.equals("CONCRETE") ? "WHITE_CONCRETE" : i;

View File

@ -18,13 +18,12 @@
package com.volmit.iris.engine.data.chunk;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.fakenews.HeightedFakeWorld;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
@ -38,8 +37,12 @@ public class LinkedTerrainChunk implements TerrainChunk {
private ChunkData rawChunkData;
private final BiomeGrid storage;
public LinkedTerrainChunk(int maxHeight) {
this(null, maxHeight);
public LinkedTerrainChunk(World world) {
this(null, Bukkit.createChunkData(world));
}
public LinkedTerrainChunk(World world, BiomeGrid storage) {
this(storage, Bukkit.createChunkData(world));
}
public LinkedTerrainChunk(BiomeGrid storage, ChunkData data) {
@ -48,23 +51,6 @@ public class LinkedTerrainChunk implements TerrainChunk {
biome3D = storage != null ? null : new IrisBiomeStorage();
}
public LinkedTerrainChunk(BiomeGrid storage, int maxHeight) {
this.storage = storage;
rawChunkData = createChunkData(maxHeight);
biome3D = storage != null ? null : new IrisBiomeStorage();
}
private ChunkData createChunkData(int maxHeight) {
try {
return Bukkit.createChunkData(new HeightedFakeWorld(maxHeight));
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return null;
}
@Override
public BiomeBaseInjector getBiomeBaseInjector() {
return (x, y, z, bb) -> INMS.get().forceBiomeInto(x, y, z, bb, storage);

View File

@ -28,25 +28,17 @@ import org.jetbrains.annotations.NotNull;
public interface TerrainChunk extends BiomeGrid, ChunkData {
static TerrainChunk create(World world) {
return create(world.getMaxHeight());
}
static TerrainChunk create(int maxHeight) {
return new LinkedTerrainChunk(maxHeight);
return new LinkedTerrainChunk(world);
}
static TerrainChunk create(World world, BiomeGrid grid) {
return create(world.getMaxHeight(), grid);
return new LinkedTerrainChunk(world, grid);
}
static TerrainChunk create(ChunkData raw, BiomeGrid grid) {
return new LinkedTerrainChunk(grid, raw);
}
static TerrainChunk create(int maxHeight, BiomeGrid grid) {
return new LinkedTerrainChunk(grid, maxHeight);
}
BiomeBaseInjector getBiomeBaseInjector();
void setRaw(ChunkData data);

View File

@ -19,6 +19,8 @@
package com.volmit.iris.engine.data.mca;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -88,6 +90,27 @@ public class MCAFile {
}
}
public KList<Position2> samplePositions(RandomAccessFile raf) throws IOException {
KList<Position2> p2 = new KList<>();
chunks = new AtomicReferenceArray<>(1024);
int x = 0;
int z = 0;
for (int i = 0; i < 1024; i++) {
x++;
z++;
raf.seek(i * 4);
int offset = raf.read() << 16;
offset |= (raf.read() & 0xFF) << 8;
offset |= raf.read() & 0xFF;
if (raf.readByte() == 0) {
continue;
}
p2.add(new Position2(x & 31, (z / 32) & 31));
}
return p2;
}
public AtomicReferenceArray<Chunk> getChunks() {
return chunks;
}
@ -218,8 +241,7 @@ public class MCAFile {
return getChunk(getChunkIndex(chunkX, chunkZ));
}
public boolean hasChunk(int chunkX, int chunkZ)
{
public boolean hasChunk(int chunkX, int chunkZ) {
return getChunk(chunkX, chunkZ) != null;
}

View File

@ -18,6 +18,9 @@
package com.volmit.iris.engine.data.mca;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -83,6 +86,13 @@ public final class MCAUtil {
}
}
public static KList<Position2> sampleChunkPositions(File file) throws IOException {
MCAFile mcaFile = newMCAFile(file);
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
return mcaFile.samplePositions(raf);
}
}
/**
* Calls {@link MCAUtil#write(MCAFile, File, boolean)} without changing the timestamps.
*

View File

@ -24,21 +24,20 @@ import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
import com.volmit.iris.engine.data.nbt.tag.StringTag;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.IrisLock;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NBTWorld {
private static final BlockData AIR = B.get("AIR");
@ -50,8 +49,7 @@ public class NBTWorld {
private final File worldFolder;
private final ExecutorService saveQueue;
public NBTWorld(File worldFolder)
{
public NBTWorld(File worldFolder) {
this.worldFolder = worldFolder;
this.loadedRegions = new KMap<>();
this.lastUse = new KMap<>();
@ -63,20 +61,17 @@ public class NBTWorld {
});
}
public void close()
{
public void close() {
regionLock.lock();
for(Long i : loadedRegions.k())
{
for (Long i : loadedRegions.k()) {
queueSaveUnload(Cache.keyX(i), Cache.keyZ(i));
}
regionLock.unlock();
saveQueue.shutdown();
try {
while(!saveQueue.awaitTermination(3, TimeUnit.SECONDS))
{
while (!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) {
Iris.info("Still Waiting to save MCA Files...");
}
} catch (InterruptedException e) {
@ -84,37 +79,43 @@ public class NBTWorld {
}
}
public void queueSaveUnload(int x, int z)
{
saveQueue.submit(() -> {
MCAFile f = getMCAOrNull(x, z);
if(f != null)
{
unloadRegion(x, z);
}
public void flushNow() {
regionLock.lock();
saveRegion(x, z, f);
});
for (Long i : loadedRegions.k()) {
doSaveUnload(Cache.keyX(i), Cache.keyZ(i));
}
regionLock.unlock();
}
public void save()
{
public void queueSaveUnload(int x, int z) {
saveQueue.submit(() -> doSaveUnload(x, z));
}
public void doSaveUnload(int x, int z) {
MCAFile f = getMCAOrNull(x, z);
if (f != null) {
unloadRegion(x, z);
}
saveRegion(x, z, f);
}
public void save() {
regionLock.lock();
boolean saving = true;
for(Long i : loadedRegions.k())
{
for (Long i : loadedRegions.k()) {
int x = Cache.keyX(i);
int z = Cache.keyZ(i);
if(!lastUse.containsKey(i))
{
if (!lastUse.containsKey(i)) {
lastUse.put(i, M.ms());
}
if(shouldUnload(x, z))
{
if (shouldUnload(x, z)) {
queueSaveUnload(x, z);
}
}
@ -124,13 +125,11 @@ public class NBTWorld {
regionLock.unlock();
}
public void queueSave()
{
public void queueSave() {
}
public synchronized void unloadRegion(int x, int z)
{
public synchronized void unloadRegion(int x, int z) {
long key = Cache.key(x, z);
regionLock.lock();
loadedRegions.remove(key);
@ -139,8 +138,7 @@ public class NBTWorld {
Iris.debug("Unloaded Region " + C.GOLD + x + " " + z);
}
public void saveRegion(int x, int z)
{
public void saveRegion(int x, int z) {
long k = Cache.key(x, z);
MCAFile mca = getMCAOrNull(x, z);
try {
@ -152,8 +150,7 @@ public class NBTWorld {
}
}
public void saveRegion(int x, int z, MCAFile mca)
{
public void saveRegion(int x, int z, MCAFile mca) {
try {
MCAUtil.write(mca, getRegionFile(x, z), true);
Iris.debug("Saved Region " + C.GOLD + x + " " + z);
@ -163,8 +160,7 @@ public class NBTWorld {
}
}
public boolean shouldUnload(int x, int z)
{
public boolean shouldUnload(int x, int z) {
return getIdleDuration(x, z) > 60000;
}
@ -281,8 +277,7 @@ public class NBTWorld {
return c;
}
public long getIdleDuration(int x, int z)
{
public long getIdleDuration(int x, int z) {
Long l = lastUse.get(Cache.key(x, z));
return l == null ? 0 : (M.ms() - l);
@ -296,17 +291,8 @@ public class NBTWorld {
MCAFile mcaf = loadedRegions.get(key);
regionLock.unlock();
if(mcaf == null)
{
File f = getRegionFile(x, z);
try {
mcaf = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z);
} catch (IOException e) {
Iris.error("Failed to properly read MCA File " + f.getPath() + " Using a blank one.");
e.printStackTrace();
mcaf = new MCAFile(x, z);
}
if (mcaf == null) {
mcaf = new MCAFile(x, z);
regionLock.lock();
loadedRegions.put(key, mcaf);
regionLock.unlock();
@ -320,8 +306,7 @@ public class NBTWorld {
MCAFile ff = null;
regionLock.lock();
if(loadedRegions.containsKey(key))
{
if (loadedRegions.containsKey(key)) {
lastUse.put(key, M.ms());
ff = loadedRegions.get(key);
}

View File

@ -24,6 +24,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData;
public class IrisCeilingDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
super(engine, "Ceiling", DecorationPart.CEILING);
}
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
IrisDecorator decorator = getDecorator(biome, realX, realZ);

View File

@ -24,6 +24,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData;
public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
super(engine, "Sea Floor", DecorationPart.SEA_FLOOR);
}
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
if (height <= getDimension().getFluidHeight()) {

View File

@ -24,6 +24,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData;
public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
super(engine, "Sea Surface", DecorationPart.SEA_SURFACE);
}
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
IrisDecorator decorator = getDecorator(biome, realX, realZ);

View File

@ -24,6 +24,7 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData;
public class IrisShoreLineDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
super(engine, "Shore Line", DecorationPart.SHORE_LINE);
}
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {

View File

@ -26,6 +26,7 @@ import com.volmit.iris.engine.object.DecorationPart;
import com.volmit.iris.engine.object.InferredType;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
@ -34,6 +35,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
super(engine, "Surface", DecorationPart.NONE);
}
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
if (biome.getInferredType().equals(InferredType.SHORE) && height < getDimension().getFluidHeight()) {

View File

@ -20,13 +20,14 @@ package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.gui.RenderType;
import com.volmit.iris.core.gui.Renderer;
import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.core.gui.components.Renderer;
import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallax.ParallaxAccess;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
@ -37,7 +38,6 @@ import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@ -105,7 +105,7 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
return getTarget().getData();
}
default World getWorld() {
default IrisWorld getWorld() {
return getTarget().getWorld();
}
@ -357,8 +357,12 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
return getCompound().isStudio();
}
default MultiBurst burst() {
return getTarget().getBurster();
}
default void clean() {
MultiBurst.burst.lazy(() -> getParallax().cleanup());
burst().lazy(() -> getParallax().cleanup());
}
default IrisBiome getBiome(Location l) {
@ -374,4 +378,6 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
}
IrisBiome getFocus();
void hotloading();
}

View File

@ -19,7 +19,9 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
public interface EngineActuator<O> extends EngineComponent {
@BlockCoordinates
void actuate(int x, int z, Hunk<O> output);
}

View File

@ -19,6 +19,7 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
public abstract class EngineAssignedActuator<T> extends EngineAssignedComponent implements EngineActuator<T> {
public EngineAssignedActuator(Engine engine, String name) {
@ -27,6 +28,7 @@ public abstract class EngineAssignedActuator<T> extends EngineAssignedComponent
public abstract void onActuate(int x, int z, Hunk<T> output);
@BlockCoordinates
@Override
public void actuate(int x, int z, Hunk<T> output) {
onActuate(x, z, output);

View File

@ -69,7 +69,7 @@ public interface EngineComponent {
}
default long getSeed() {
return getTarget().getWorld().getSeed();
return getTarget().getWorld().seed();
}
default EngineFramework getFramework() {

View File

@ -23,21 +23,22 @@ import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.engine.IrisEngineCompound;
import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.headless.HeadlessGenerator;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.fakenews.FakeWorld;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.ReactiveFolder;
@ -48,7 +49,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import io.netty.util.internal.ConcurrentSet;
import io.papermc.lib.PaperLib;
import lombok.Getter;
import org.bukkit.*;
import org.bukkit.block.Biome;
@ -77,11 +77,11 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
private final boolean production;
private final KList<BlockPopulator> populators;
private long mst = 0;
private HeadlessGenerator headlessGenerator;
private NBTWorld nbtWorld;
private int generated = 0;
private int lgenerated = 0;
private final KMap<Long, PregeneratedData> chunkCache;
private final ChronoLatch hotloadcd;
private final AtomicBoolean fake;
@Getter
private double generatedPerSecond = 0;
private final int art;
@ -93,8 +93,6 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
public EngineCompositeGenerator(String query, boolean production) {
super();
chunkCache = new KMap<>();
fake = new AtomicBoolean(true);
hotloadcd = new ChronoLatch(3500);
mst = M.ms();
this.production = production;
@ -113,6 +111,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
});
}
@Override
public void hotload() {
if (isStudio()) {
Iris.proj.updateWorkspace();
@ -128,12 +127,14 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}
});
getComposite().close();
initialized.lazySet(false);
}
}
public void tick() {
if (isClosed()) {
if (getComposite() == null || isClosed()) {
return;
}
@ -158,14 +159,14 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}
}
private synchronized IrisDimension getDimension(World world) {
private synchronized IrisDimension getDimension(IrisWorld world) {
String query = dimensionQuery;
query = Iris.linkMultiverseCore.getWorldNameType(world.getName(), query);
query = Iris.linkMultiverseCore.getWorldNameType(world.name(), query);
IrisDimension dim = null;
if (query == null) {
File iris = new File(world.getWorldFolder(), "iris");
File iris = new File(world.worldFolder(), "iris");
if (iris.exists() && iris.isDirectory()) {
for (File i : iris.listFiles()) {
@ -191,7 +192,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}
if (query == null) {
Iris.error("Cannot find iris dimension data for world: " + world.getName() + "! Assuming " + IrisSettings.get().getGenerator().getDefaultWorldType() + "!");
Iris.error("Cannot find iris dimension data for world: " + world.name() + "! Assuming " + IrisSettings.get().getGenerator().getDefaultWorldType() + "!");
query = IrisSettings.get().getGenerator().getDefaultWorldType();
}
@ -213,8 +214,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
dim = new IrisDataManager(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
Iris.info("Installing Iris pack " + od.getName() + " into world " + world.getName() + "...");
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), world.getWorldFolder());
Iris.info("Installing Iris pack " + od.getName() + " into world " + world.name() + "...");
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), world.worldFolder());
dim = new IrisDataManager(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
@ -294,20 +295,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return dim;
}
public synchronized void initialize(World world) {
if (!(world instanceof FakeWorld) && fake.get() && this.compound.get() != null) {
fake.set(false);
this.compound.get().updateWorld(world);
getTarget().updateWorld(world);
placeStrongholds(world);
for (int i = 0; i < getComposite().getSize(); i++) {
getComposite().getEngine(i).getTarget().updateWorld(world);
}
Iris.info("Attached Real World to Engine Target");
}
public synchronized void initialize(IrisWorld world) {
if (initialized.get()) {
return;
}
@ -316,12 +304,16 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
initialized.set(true);
IrisDimension dim = getDimension(world);
IrisDataManager data = production ? new IrisDataManager(getDataFolder(world)) : dim.getLoader().copy();
compound.set(new IrisEngineCompound(world, dim, data, Iris.getThreadCount()));
compound.set(new IrisEngineCompound(world, dim, data, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getEngineThreadCount())));
compound.get().setStudio(!production);
populators.clear();
populators.addAll(compound.get().getPopulators());
hotloader = new ReactiveFolder(data.getDataFolder(), (a, c, d) -> hotload());
dim.installDataPack(() -> data, Iris.instance.getDatapacksFolder());
if(isStudio())
{
dim.installDataPack(() -> data, Iris.instance.getDatapacksFolder());
}
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
@ -445,8 +437,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
);
}
private File getDataFolder(World world) {
return new File(world.getWorldFolder(), "iris/pack");
private File getDataFolder(IrisWorld world) {
return new File(world.worldFolder(), "iris/pack");
}
private File getDataFolder(String world) {
@ -458,7 +450,13 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
public ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) {
PrecisionStopwatch ps = PrecisionStopwatch.start();
TerrainChunk tc = TerrainChunk.create(world, biome);
generateChunkRawData(world, x, z, tc).run();
IrisWorld ww = (getComposite() == null || getComposite().getWorld() == null) ? IrisWorld.fromWorld(world) : getComposite().getWorld();
generateChunkRawData(ww, x, z, tc).run();
if (!getComposite().getWorld().hasRealWorld()) {
getComposite().getWorld().bind(world);
}
generated++;
ps.end();
@ -469,23 +467,48 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return tc.getRaw();
}
public void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst) {
BurstExecutor e = burst.burst(1024);
int mcaox = x << 5;
int mcaoz = z << 5;
public void assignHeadlessGenerator(HeadlessGenerator headlessGenerator) {
this.headlessGenerator = headlessGenerator;
}
for (int i = 0; i < 32; i++) {
int ii = i;
for (int j = 0; j < 32; j++) {
int jj = j;
e.queue(() -> directWriteChunk(w, ii + mcaox, jj + mcaoz, writer));
@Override
public HeadlessGenerator getHeadlessGenerator() {
return headlessGenerator;
}
public void assignHeadlessNBTWriter(NBTWorld writer) {
this.nbtWorld = writer;
}
@Override
public NBTWorld getHeadlessNBTWriter() {
return nbtWorld;
}
@Override
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst) {
directWriteMCA(w, x, z, writer, burst, null);
}
@Override
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst, PregenListener l) {
BurstExecutor e = burst.burst(1024);
PregenTask.iterateRegion(x, z, (ii, jj) -> e.queue(() -> {
if (l != null) {
l.onChunkGenerating(ii, jj);
}
}
directWriteChunk(w, ii, jj, writer);
if (l != null) {
l.onChunkGenerated(ii, jj);
}
}));
e.complete();
}
public void directWriteChunk(World w, int x, int z, NBTWorld writer) {
@Override
public void directWriteChunk(IrisWorld w, int x, int z, NBTWorld writer) {
int ox = x << 4;
int oz = z << 4;
com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z);
@ -526,12 +549,12 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
@Override
public int getMinHeight() {
return w.getMinHeight();
return w.minHeight();
}
@Override
public int getMaxHeight() {
return w.getMaxHeight();
return w.maxHeight();
}
@Override
@ -614,50 +637,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}).run();
}
public Chunk generatePaper(World world, int x, int z) {
precache(world, x, z);
Chunk c = PaperLib.getChunkAtAsync(world, x, z, true).join();
chunkCache.remove(Cache.key(x, z));
return c;
}
public void precache(World world, int x, int z) {
synchronized (this) {
initialize(world);
}
synchronized (chunkCache) {
if (chunkCache.containsKey(Cache.key(x, z))) {
return;
}
}
PregeneratedData data = new PregeneratedData(getComposite().getHeight() - 1);
compound.get().generate(x * 16, z * 16, data.getBlocks(), data.getPost(), data.getBiomes());
synchronized (chunkCache) {
chunkCache.put(Cache.key(x, z), data);
}
}
@Override
public int getPrecacheSize() {
return chunkCache.size();
}
public int getCachedChunks() {
return chunkCache.size();
}
public Runnable generateChunkRawData(World world, int x, int z, TerrainChunk tc) {
public Runnable generateChunkRawData(IrisWorld world, int x, int z, TerrainChunk tc) {
initialize(world);
synchronized (chunkCache) {
long g = Cache.key(x, z);
if (chunkCache.containsKey(g)) {
return chunkCache.remove(g).inject(tc);
}
}
Hunk<BlockData> blocks = Hunk.view((ChunkData) tc);
Hunk<Biome> biomes = Hunk.view((BiomeGrid) tc);
Hunk<BlockData> post = Hunk.newAtomicHunk(biomes.getWidth(), biomes.getHeight(), biomes.getDepth());
@ -783,146 +764,15 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
// TODO: DO IT
}
@Override
public void clearRegeneratedLists(int x, int z) {
for (int i = 0; i < getComposite().getSize(); i++) {
getComposite().getEngine(i).getParallax().delete(x, z);
}
}
@Override
public void regenerate(int x, int z) {
clearRegeneratedLists(x, z);
int xx = x * 16;
int zz = z * 16;
BiomeBaseInjector inj = (a, b, c, d) -> {
};
//noinspection deprecation
generateChunkRawData(getComposite().getWorld(), x, z, new TerrainChunk() {
@Override
public BiomeBaseInjector getBiomeBaseInjector() {
return inj;
}
@Override
public void setRaw(ChunkData data) {
}
@NotNull
@Override
public Biome getBiome(int x, int z) {
return Biome.THE_VOID;
}
@NotNull
@Override
public Biome getBiome(int x, int y, int z) {
return Biome.THE_VOID;
}
@Override
public void setBiome(int x, int z, Biome bio) {
}
@Override
public void setBiome(int x, int y, int z, Biome bio) {
}
@Override
public int getMinHeight() {
return getComposite().getWorld().getMinHeight();
}
@Override
public int getMaxHeight() {
return getComposite().getWorld().getMaxHeight();
}
@Override
public void setBlock(int x, int y, int z, BlockData blockData) {
if (!getBlockData(x, y, z).matches(blockData)) {
Iris.edit.set(compound.get().getWorld(), x + xx, y, z + zz, blockData);
}
}
@NotNull
@Override
public BlockData getBlockData(int x, int y, int z) {
return Iris.edit.get(compound.get().getWorld(), x + xx, y, z + zz);
}
@Override
public ChunkData getRaw() {
return null;
}
@Override
public void inject(BiomeGrid biome) {
}
@Override
public void setBlock(int i, int i1, int i2, @NotNull Material material) {
setBlock(i, i1, i2, material.createBlockData());
}
@Override
public void setBlock(int i, int i1, int i2, @NotNull MaterialData materialData) {
setBlock(i, i1, i2, materialData.getItemType());
}
@Override
public void setRegion(int i, int i1, int i2, int i3, int i4, int i5, @NotNull Material material) {
}
@Override
public void setRegion(int i, int i1, int i2, int i3, int i4, int i5, @NotNull MaterialData materialData) {
}
@Override
public void setRegion(int i, int i1, int i2, int i3, int i4, int i5, @NotNull BlockData blockData) {
}
@NotNull
@Override
public Material getType(int i, int i1, int i2) {
return getBlockData(i, i1, i2).getMaterial();
}
@NotNull
@Override
public MaterialData getTypeAndData(int i, int i1, int i2) {
return null;
}
@Override
public byte getData(int i, int i1, int i2) {
return 0;
}
});
Iris.edit.flushNow();
}
@Override
public void close() {
J.car(art);
if (getComposite() != null) {
getComposite().close();
if (isStudio()) {
IrisWorlds.evacuate(getComposite().getWorld());
Bukkit.unloadWorld(getComposite().getWorld(), !isStudio());
if (isStudio() && getComposite().getWorld().hasRealWorld()) {
getComposite().getWorld().evacuate();
Bukkit.unloadWorld(getComposite().getWorld().realWorld(), !isStudio());
}
}
}

View File

@ -26,10 +26,10 @@ import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
@ -43,7 +43,7 @@ public interface EngineCompound extends Listener, Hotloadable, DataProvider {
void generate(int x, int z, Hunk<BlockData> blocks, Hunk<BlockData> postblocks, Hunk<Biome> biomes);
World getWorld();
IrisWorld getWorld();
List<IrisPosition> getStrongholdPositions();
@ -149,8 +149,6 @@ public interface EngineCompound extends Listener, Hotloadable, DataProvider {
return v.v();
}
void updateWorld(World world);
default int getLowestBedrock() {
int f = Integer.MAX_VALUE;

View File

@ -21,11 +21,15 @@ package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData;
public interface EngineDecorator extends EngineComponent {
@BlockCoordinates
void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max);
@BlockCoordinates
default void decorate(int x, int z, int realX, int realZ, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
decorate(x, z, realX, realX, realX, realZ, realZ, realZ, data, biome, height, max);
}

View File

@ -19,7 +19,9 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
public interface EngineModifier<T> extends EngineComponent {
@BlockCoordinates
void modify(int x, int z, Hunk<T> t);
}

View File

@ -34,10 +34,10 @@ import com.volmit.iris.engine.object.tile.TileData;
import com.volmit.iris.engine.parallax.ParallaxAccess;
import com.volmit.iris.engine.parallax.ParallaxChunkMeta;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.math.RNG;
@ -165,14 +165,19 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
});
}
@ChunkCoordinates
default void insertParallax(int x, int z, Hunk<BlockData> data) {
if (!getEngine().getDimension().isPlaceObjects()) {
return;
}
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
ParallaxChunkMeta meta = getParallaxAccess().getMetaR(x >> 4, z >> 4);
ParallaxChunkMeta meta = getParallaxAccess().getMetaR(x, z);
if (!meta.isParallaxGenerated()) {
generateParallaxLayer(x, z, true);
meta = getParallaxAccess().getMetaR(x >> 4, z >> 4);
meta = getParallaxAccess().getMetaR(x, z);
}
if (!meta.isObjects()) {
@ -180,7 +185,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
return;
}
getParallaxAccess().getBlocksR(x >> 4, z >> 4).iterateSync((a, b, c, d) -> {
getParallaxAccess().getBlocksR(x, z).iterateSync((a, b, c, d) -> {
if (d != null) {
data.set(a, b, c, d);
}
@ -199,8 +204,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
IrisLock getFeatureLock();
default void forEachFeature(double x, double z, Consumer<IrisFeaturePositional> f) {
if(!getEngine().getDimension().hasFeatures(getEngine()))
{
if (!getEngine().getDimension().hasFeatures(getEngine())) {
return;
}
@ -229,14 +233,18 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
for (j = -s; j <= s; j++) {
ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz);
try {
for (IrisFeaturePositional k : m.getFeatures()) {
if (k.shouldFilter(x, z)) {
pos.add(k);
synchronized (m) {
try {
for (IrisFeaturePositional k : m.getFeatures()) {
if (k.shouldFilter(x, z)) {
pos.add(k);
}
}
} catch (Throwable e) {
Iris.error("FILTER ERROR" + " AT " + (cx + i) + " " + (j + cz));
e.printStackTrace();
Iris.reportError(e);
}
} catch (Throwable e) {
Iris.reportError(e);
}
}
}
@ -261,7 +269,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
int i, j;
KList<Runnable> after = new KList<>();
int bs = (int) Math.pow((s * 2) + 1, 2);
BurstExecutor burst = MultiBurst.burst.burst(bs);
BurstExecutor burst = getEngine().getTarget().getBurster().burst(bs);
for (i = -s; i <= s; i++) {
for (j = -s; j <= s; j++) {
int xx = i + x;
@ -271,7 +279,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
if (!getParallaxAccess().isFeatureGenerated(xx, zz)) {
burst.queue(() -> {
getParallaxAccess().setFeatureGenerated(xx, zz);
RNG rng = new RNG(Cache.key(xx, zz)).nextParallelRNG(getEngine().getTarget().getWorld().getSeed());
RNG rng = new RNG(Cache.key(xx, zz)).nextParallelRNG(getEngine().getTarget().getWorld().seed());
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
IrisBiome biome = getComplex().getTrueBiomeStream().get(xxx, zzz);
generateParallaxFeatures(rng, xx, zz, region, biome);
@ -283,7 +291,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
burst.complete();
if (getEngine().getDimension().isPlaceObjects()) {
burst = MultiBurst.burst.burst(bs);
burst = getEngine().getTarget().getBurster().burst(bs);
for (i = -s; i <= s; i++) {
int ii = i;
@ -299,7 +307,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
}
burst.complete();
burst = MultiBurst.burst.burst(bs);
burst = getEngine().getTarget().getBurster().burst(bs);
for (i = -s; i <= s; i++) {
int ii = i;
@ -312,7 +320,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
burst.complete();
}
MultiBurst.burst.burst(after);
getEngine().getTarget().getBurster().burst(after);
getParallaxAccess().setChunkGenerated(x, z);
p.end();
getEngine().getMetrics().getParallax().put(p.getMilliseconds());
@ -325,14 +333,14 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
default KList<Runnable> generateParallaxVacuumLayer(int x, int z) {
KList<Runnable> after = new KList<>();
if (getParallaxAccess().isParallaxGenerated(x, z)) {
if (getParallaxAccess().isParallaxGenerated(x >> 4, z >> 4)) {
return after;
}
if (getEngine().getDimension().isPlaceObjects()) {
int xx = x << 4;
int zz = z << 4;
RNG rng = new RNG(Cache.key(x, z)).nextParallelRNG(getEngine().getTarget().getWorld().getSeed());
RNG rng = new RNG(Cache.key(x, z)).nextParallelRNG(getEngine().getTarget().getWorld().seed());
IrisRegion region = getComplex().getRegionStream().get(xx + 8, zz + 8);
IrisBiome biome = getComplex().getTrueBiomeStream().get(xx + 8, zz + 8);
after.addAll(generateParallaxJigsaw(rng, x, z, biome, region));
@ -351,7 +359,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
int xx = x << 4;
int zz = z << 4;
getParallaxAccess().setParallaxGenerated(x, z);
RNG rng = new RNG(Cache.key(x, z)).nextParallelRNG(getEngine().getTarget().getWorld().getSeed());
RNG rng = new RNG(Cache.key(x, z)).nextParallelRNG(getEngine().getTarget().getWorld().seed());
IrisBiome biome = getComplex().getTrueBiomeStream().get(xx + 8, zz + 8);
IrisRegion region = getComplex().getRegionStream().get(xx + 8, zz + 8);
generateParallaxSurface(rng, x, z, biome, region, false);
@ -666,7 +674,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
}
Iris.verbose("Checking sizes for " + Form.f(objects.size()) + " referenced objects.");
BurstExecutor e = MultiBurst.burst.burst(objects.size());
BurstExecutor e = getEngine().getTarget().getBurster().burst(objects.size());
KMap<String, BlockVector> sizeCache = new KMap<>();
for (String i : objects) {
e.queue(() -> {

View File

@ -19,11 +19,12 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallax.ParallaxWorld;
import com.volmit.iris.engine.parallel.MultiBurst;
import lombok.Data;
import org.bukkit.World;
import java.io.File;
@ -31,27 +32,27 @@ import java.io.File;
public class EngineTarget {
private final MultiBurst burster;
private final IrisDimension dimension;
private World world;
private IrisWorld world;
private final int height;
private final IrisDataManager data;
private final ParallaxWorld parallaxWorld;
private final boolean inverted;
public EngineTarget(World world, IrisDimension dimension, IrisDataManager data, int height, boolean inverted, int threads) {
public EngineTarget(IrisWorld world, IrisDimension dimension, IrisDataManager data, int height, boolean inverted, int threads) {
this.world = world;
this.height = height;
this.dimension = dimension;
this.data = data;
this.parallaxWorld = new ParallaxWorld(256, new File(world.getWorldFolder(), "iris/" + dimension.getLoadKey() + "/parallax"));
this.inverted = inverted;
this.burster = new MultiBurst(threads);
this.burster = new MultiBurst("Iris Engine " + dimension.getName(), IrisSettings.get().getConcurrency().getEngineThreadPriority(), threads);
this.parallaxWorld = new ParallaxWorld(burster, 256, new File(world.worldFolder(), "iris/" + dimension.getLoadKey() + "/parallax"));
}
public void updateWorld(World world) {
this.world = world;
}
public EngineTarget(World world, IrisDimension dimension, IrisDataManager data, int height, int threads) {
public EngineTarget(IrisWorld world, IrisDimension dimension, IrisDataManager data, int height, int threads) {
this(world, dimension, data, height, false, threads);
}
public void close() {
burster.shutdownAndAwait();
}
}

View File

@ -19,7 +19,7 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.gui.Renderer;
import com.volmit.iris.core.gui.components.Renderer;
import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisObjectPlacement;

View File

@ -20,20 +20,21 @@ package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.headless.HeadlessGenerator;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import java.util.concurrent.atomic.AtomicBoolean;
@ -44,9 +45,19 @@ import java.util.function.Consumer;
@SuppressWarnings("EmptyMethod")
public interface IrisAccess extends Hotloadable, DataProvider {
void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst);
HeadlessGenerator getHeadlessGenerator();
void directWriteChunk(World w, int x, int z, NBTWorld writer);
default boolean isHeadless() {
return getHeadlessGenerator() != null;
}
NBTWorld getHeadlessNBTWriter();
void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst);
void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst, PregenListener listener);
void directWriteChunk(IrisWorld w, int x, int z, NBTWorld writer);
int getGenerated();
@ -72,8 +83,6 @@ public interface IrisAccess extends Hotloadable, DataProvider {
void changeThreadCount(int m);
void regenerate(int x, int z);
void close();
boolean isClosed();
@ -87,6 +96,11 @@ public interface IrisAccess extends Hotloadable, DataProvider {
boolean isStudio();
default Location lookForBiome(IrisBiome biome, long timeout, Consumer<Integer> triesc) {
if (!getCompound().getWorld().hasRealWorld()) {
Iris.error("Cannot GOTO without a bound world (headless mode)");
return null;
}
IrisComplex.cacheLock.set(true);
ChronoLatch cl = new ChronoLatch(250, false);
long s = M.ms();
@ -130,7 +144,7 @@ public interface IrisAccess extends Hotloadable, DataProvider {
if (b != null && b.getLoadKey().equals(biome.getLoadKey())) {
found.lazySet(true);
location.lazySet(new Location(e.getWorld(), x, e.getHeight(x, z), z));
location.lazySet(new Location(e.getWorld().realWorld(), x, e.getHeight(x, z), z));
}
tries.getAndIncrement();
@ -167,6 +181,11 @@ public interface IrisAccess extends Hotloadable, DataProvider {
}
default Location lookForRegion(IrisRegion reg, long timeout, Consumer<Integer> triesc) {
if (!getCompound().getWorld().hasRealWorld()) {
Iris.error("Cannot GOTO without a bound world (headless mode)");
return null;
}
IrisComplex.cacheLock.set(true);
ChronoLatch cl = new ChronoLatch(3000, false);
long s = M.ms();
@ -204,7 +223,7 @@ public interface IrisAccess extends Hotloadable, DataProvider {
if (b != null && b.getLoadKey() != null && b.getLoadKey().equals(reg.getLoadKey())) {
found.lazySet(true);
location.lazySet(new Location(e.getWorld(), x, e.getHeight(x, z) + e.getMinHeight(), z));
location.lazySet(new Location(e.getWorld().realWorld(), x, e.getHeight(x, z) + e.getMinHeight(), z));
}
tries.getAndIncrement();
@ -238,14 +257,6 @@ public interface IrisAccess extends Hotloadable, DataProvider {
return location.get();
}
void clearRegeneratedLists(int x, int z);
void precache(World world, int x, int z);
int getPrecacheSize();
Chunk generatePaper(World world, int cx, int cz);
default int getParallaxChunkCount() {
int v = 0;

View File

@ -0,0 +1,93 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.headless;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.data.mca.MCAUtil;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import lombok.Data;
import java.io.File;
import java.io.IOException;
@Data
public class HeadlessGenerator {
private static KList<Position2> EMPTYPOINTS = new KList<>();
private final HeadlessWorld world;
private final EngineCompositeGenerator generator;
private final NBTWorld writer;
private final MultiBurst burst;
public HeadlessGenerator(HeadlessWorld world) {
this.world = world;
burst = new MultiBurst("Iris Headless Generator", 9, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount()));
writer = new NBTWorld(world.getWorld().worldFolder());
generator = new EngineCompositeGenerator(world.getDimension().getLoadKey(), !world.isStudio());
generator.assignHeadlessGenerator(this);
generator.assignHeadlessNBTWriter(writer);
generator.initialize(world.getWorld());
}
public void generateChunk(int x, int z) {
generator.directWriteChunk(world.getWorld(), x, z, writer);
}
public void generateRegion(int x, int z) {
generator.directWriteMCA(world.getWorld(), x, z, writer, burst);
}
public void generateRegion(int x, int z, PregenListener listener) {
generator.directWriteMCA(world.getWorld(), x, z, writer, burst, listener);
}
public File generateRegionToFile(int x, int z, PregenListener listener) {
generateRegionToFile(x, z, listener);
flush();
return writer.getRegionFile(x, z);
}
public void flush() {
writer.flushNow();
}
public void save() {
writer.save();
}
public void close() {
burst.shutdownAndAwait();
generator.close();
writer.close();
}
public KList<Position2> getChunksInRegion(int x, int z) {
try {
return MCAUtil.sampleChunkPositions(writer.getRegionFile(x, z));
} catch (IOException e) {
e.printStackTrace();
}
return EMPTYPOINTS;
}
}

View File

@ -0,0 +1,86 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.headless;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import java.io.File;
@Data
@SuppressWarnings("ResultOfMethodCallIgnored")
public class HeadlessWorld {
private final IrisDimension dimension;
private final String worldName;
private final IrisWorld world;
private boolean studio = false;
public HeadlessWorld(String worldName, IrisDimension dimension, long seed) {
this(worldName, dimension, seed, false);
}
public HeadlessWorld(String worldName, IrisDimension dimension, long seed, boolean studio) {
this.worldName = worldName;
this.dimension = dimension;
this.studio = studio;
world = IrisWorld.builder()
.environment(dimension.getEnvironment())
.worldFolder(new File(worldName))
.seed(seed)
.maxHeight(256)
.minHeight(0)
.name(worldName)
.build();
world.worldFolder().mkdirs();
new File(world.worldFolder(), "region").mkdirs();
if (!studio && !new File(world.worldFolder(), "iris").exists()) {
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag("Headless")), dimension.getLoadKey(), world.worldFolder());
}
}
public HeadlessGenerator generate() {
return new HeadlessGenerator(this);
}
public World load() {
return new WorldCreator(worldName)
.environment(dimension.getEnvironment())
.seed(world.seed())
.generator(new EngineCompositeGenerator(dimension.getLoadKey(), !studio))
.createWorld();
}
public static HeadlessWorld from(World world) {
return new HeadlessWorld(world.getName(), IrisWorlds.access(world).getTarget().getDimension(), world.getSeed());
}
public static HeadlessWorld from(String name, String dimension, long seed) {
return new HeadlessWorld(name, IrisDataManager.loadAnyDimension(dimension), seed);
}
}

View File

@ -865,18 +865,6 @@ public interface Hunk<T> {
return this;
}
default void enforceBounds(int x, int y, int z) {
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight() || z < 0 || z >= getDepth()) {
//Iris.warn(x + "," + y + "," + z + " does not fit within size " + getWidth() + "," + getHeight() + "," + getDepth() + " (0,0,0 to " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1) + ")");
}
}
default void enforceBounds(int x, int y, int z, int w, int h, int d) {
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight() || z < 0 || z >= getDepth() || x + w < 0 || x + w > getWidth() || y + h < 0 || y + h > getHeight() || z + d < 0 || z + d > getDepth()) {
//Iris.warn("The hunk " + w + "," + h + "," + d + " with an offset of " + x + "," + y + "," + z + " does not fit within the parent hunk " + getWidth() + "," + getHeight() + "," + getDepth() + " (0,0,0 to " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1) + ")");
}
}
/**
* Create a new hunk from a section of this hunk.
*
@ -890,7 +878,6 @@ public interface Hunk<T> {
*/
default ArrayHunk<T> crop(int x1, int y1, int z1, int x2, int y2, int z2) {
ArrayHunk<T> h = new ArrayHunk<T>(x2 - x1, y2 - y1, z2 - z1);
enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1);
for (int i = x1; i < x2; i++) {
for (int j = y1; j < y2; j++) {
@ -916,7 +903,6 @@ public interface Hunk<T> {
* @return the cropped view of this hunk (x2-x1, y2-y1, z2-z1)
*/
default Hunk<T> croppedView(int x1, int y1, int z1, int x2, int y2, int z2) {
enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1);
return new HunkView<T>(this, x2 - x1, y2 - y1, z2 - z1, x1, y1, z1);
}
@ -947,7 +933,6 @@ public interface Hunk<T> {
* @param t the value to set
*/
default void set(int x1, int y1, int z1, int x2, int y2, int z2, T t) {
enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1);
for (int i = x1; i <= x2; i++) {
for (int j = y1; j <= y2; j++) {
for (int k = z1; k <= z2; k++) {
@ -1036,7 +1021,6 @@ public interface Hunk<T> {
* @param t the value
*/
default void set(int x, int y, int z, T t) {
enforceBounds(x, y, z);
setRaw(x, y, z, t);
}
@ -1089,12 +1073,10 @@ public interface Hunk<T> {
* @return the value or null
*/
default T get(int x, int y, int z) {
enforceBounds(x, y, z);
return getRaw(x, y, z);
}
default T getOr(int x, int y, int z, T t) {
enforceBounds(x, y, z);
T v = getRaw(x, y, z);
if (v == null) {
@ -1161,8 +1143,6 @@ public interface Hunk<T> {
* @param invertY should the inserted hunk be inverted
*/
default void insert(int offX, int offY, int offZ, Hunk<T> hunk, boolean invertY) {
enforceBounds(offX, offY, offZ, hunk.getWidth(), hunk.getHeight(), hunk.getDepth());
for (int i = offX; i < offX + hunk.getWidth(); i++) {
for (int j = offY; j < offY + hunk.getHeight(); j++) {
for (int k = offZ; k < offZ + hunk.getDepth(); k++) {
@ -1183,8 +1163,6 @@ public interface Hunk<T> {
* @param invertY should the inserted hunk be inverted
*/
default void insertSoftly(int offX, int offY, int offZ, Hunk<T> hunk, boolean invertY, Predicate<T> shouldOverwrite) {
enforceBounds(offX, offY, offZ, hunk.getWidth(), hunk.getHeight(), hunk.getDepth());
for (int i = offX; i < offX + hunk.getWidth(); i++) {
for (int j = offY; j < offY + hunk.getHeight(); j++) {
for (int k = offZ; k < offZ + hunk.getDepth(); k++) {

View File

@ -22,19 +22,17 @@ import com.volmit.iris.Iris;
import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.tile.TileData;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.GridLock;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.function.Function3;
import com.volmit.iris.util.math.ChunkPosition;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.oldnbt.ByteArrayTag;
import com.volmit.iris.util.oldnbt.CompoundTag;
import com.volmit.iris.util.oldnbt.Tag;
import io.papermc.lib.PaperLib;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
@ -42,22 +40,20 @@ import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
public class HunkRegionSlice<T> {
public static final Function2<Integer, CompoundTag, HunkRegionSlice<BlockData>> BLOCKDATA = (h, c) -> new HunkRegionSlice<>(h, Hunk::newMappedHunkSynced, new BlockDataHunkIOAdapter(), c, "blockdata");
public static final Function2<Integer, CompoundTag, HunkRegionSlice<TileData<? extends TileState>>> TILE = (h, c) -> new HunkRegionSlice<>(h, Hunk::newMappedHunkSynced, new TileDataHunkIOAdapter(), c, "tile");
public static final Function3<Integer, CompoundTag, String, HunkRegionSlice<String>> STRING = (h, c, t) -> new HunkRegionSlice<>(h, Hunk::newMappedHunkSynced, new StringHunkIOAdapter(), c, t);
public static final Function3<Integer, CompoundTag, String, HunkRegionSlice<Boolean>> BOOLEAN = (h, c, t) -> new HunkRegionSlice<>(h, Hunk::newMappedHunkSynced, new BooleanHunkIOAdapter(), c, t);
public static final Function2<Integer, CompoundTag, HunkRegionSlice<BlockData>> BLOCKDATA = (h, c) -> new HunkRegionSlice<>(h, Hunk::newMappedHunk, new BlockDataHunkIOAdapter(), c, "blockdata");
public static final Function2<Integer, CompoundTag, HunkRegionSlice<TileData<? extends TileState>>> TILE = (h, c) -> new HunkRegionSlice<>(h, Hunk::newMappedHunk, new TileDataHunkIOAdapter(), c, "tile");
public static final Function3<Integer, CompoundTag, String, HunkRegionSlice<String>> STRING = (h, c, t) -> new HunkRegionSlice<>(h, Hunk::newMappedHunk, new StringHunkIOAdapter(), c, t);
public static final Function3<Integer, CompoundTag, String, HunkRegionSlice<Boolean>> BOOLEAN = (h, c, t) -> new HunkRegionSlice<>(h, Hunk::newMappedHunk, new BooleanHunkIOAdapter(), c, t);
private final Function3<Integer, Integer, Integer, Hunk<T>> factory;
private final GridLock lock;
private final HunkIOAdapter<T> adapter;
private final CompoundTag compound;
private final String key;
private final KMap<ChunkPosition, Hunk<T>> loadedChunks;
private final KMap<ChunkPosition, Long> lastUse;
private final KSet<ChunkPosition> save;
private final KMap<Position2, Hunk<T>> loadedChunks;
private final KMap<Position2, Long> lastUse;
private final KSet<Position2> save;
private final int height;
public HunkRegionSlice(int height, Function3<Integer, Integer, Integer, Hunk<T>> factory, HunkIOAdapter<T> adapter, CompoundTag compound, String key) {
this.lock = new GridLock(32, 32);
this.height = height;
this.loadedChunks = new KMap<>();
this.factory = factory;
@ -73,18 +69,20 @@ public class HunkRegionSlice<T> {
if (loadedChunks.size() != lastUse.size()) {
Iris.warn("Incorrect chunk use counts in " + key);
for (ChunkPosition i : lastUse.k()) {
for (Position2 i : lastUse.k()) {
if (!loadedChunks.containsKey(i)) {
Iris.warn(" Missing LoadChunkKey " + i);
}
}
}
for (ChunkPosition i : lastUse.k()) {
for (Position2 i : lastUse.k()) {
Long l = lastUse.get(i);
if (l == null || M.ms() - l > t) {
v++;
unload(i.getX(), i.getZ());
MultiBurst.burst.lazy(() -> {
unload(i.getX(), i.getZ());
});
}
}
@ -99,30 +97,23 @@ public class HunkRegionSlice<T> {
}
}
public synchronized void save() {
BurstExecutor e = MultiBurst.burst.burst();
public synchronized void save(MultiBurst burst) {
try
{
for (ChunkPosition i : save.copy()) {
try {
for (Position2 i : save.copy()) {
if (i == null) {
continue;
}
e.queue(() -> save(i.getX(), i.getZ()));
save(i.getX(), i.getZ());
try {
lock.withNasty(i.getX(), i.getZ(), () -> save.remove(i));
save.remove(i);
} catch (Throwable eer) {
Iris.reportError(eer);
}
}
e.complete();
}
catch(Throwable ee)
{
} catch (Throwable ee) {
Iris.reportError(ee);
}
}
@ -132,28 +123,23 @@ public class HunkRegionSlice<T> {
}
public void delete(int x, int z) {
lock.with(x, z, () -> compound.getValue().remove(key(x, z)));
compound.getValue().remove(key(x, z));
}
public Hunk<T> read(int x, int z) throws IOException {
AtomicReference<IOException> e = new AtomicReference<>();
Hunk<T> xt = lock.withResult(x, z, () -> {
Tag t = compound.getValue().get(key(x, z));
Hunk<T> xt = null;
if (!(t instanceof ByteArrayTag)) {
Iris.verbose("NOT BYTE ARRAY!");
return null;
}
Tag t = compound.getValue().get(key(x, z));
if ((t instanceof ByteArrayTag)) {
try {
return adapter.read(factory, (ByteArrayTag) t);
xt = adapter.read(factory, (ByteArrayTag) t);
} catch (IOException xe) {
Iris.reportError(xe);
e.set(xe);
}
return null;
});
}
if (xt != null) {
return xt;
@ -167,12 +153,12 @@ public class HunkRegionSlice<T> {
}
public void write(Hunk<T> hunk, int x, int z) throws IOException {
lock.withIO(x, z, () -> compound.getValue().put(key(x, z), hunk.writeByteArrayTag(adapter, key(x, z))));
compound.getValue().put(key(x, z), hunk.writeByteArrayTag(adapter, key(x, z)));
}
public synchronized int unloadAll() {
int v = 0;
for (ChunkPosition i : loadedChunks.k()) {
for (Position2 i : loadedChunks.k()) {
unload(i.getX(), i.getZ());
v++;
}
@ -185,7 +171,7 @@ public class HunkRegionSlice<T> {
public void save(Hunk<T> region, int x, int z) {
try {
lock.withIO(x, z, () -> write(region, x, z));
write(region, x, z);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
@ -193,84 +179,74 @@ public class HunkRegionSlice<T> {
}
public boolean isLoaded(int x, int z) {
return lock.withResult(x, z, () -> loadedChunks.containsKey(new ChunkPosition(x, z)));
return loadedChunks.containsKey(new Position2(x, z));
}
public void save(int x, int z) {
lock.with(x, z, () -> {
if (isLoaded(x, z)) {
save(get(x, z), x, z);
}
});
if (isLoaded(x, z)) {
save(get(x, z), x, z);
}
}
public void unload(int x, int z) {
lock.with(x, z, () -> {
ChunkPosition key = new ChunkPosition(x, z);
if (isLoaded(x, z)) {
if (save.contains(key)) {
save(x, z);
save.remove(key);
}
lastUse.remove(key);
loadedChunks.remove(key);
Position2 key = new Position2(x, z);
if (isLoaded(x, z)) {
if (save.contains(key)) {
save(x, z);
save.remove(key);
}
});
lastUse.remove(key);
loadedChunks.remove(key);
}
}
public Hunk<T> load(int x, int z) {
return lock.withResult(x, z, () -> {
if (isLoaded(x, z)) {
return loadedChunks.get(new ChunkPosition(x, z));
if (isLoaded(x, z)) {
return loadedChunks.get(new Position2(x, z));
}
Hunk<T> v = null;
if (contains(x, z)) {
try {
v = read(x, z);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Hunk<T> v = null;
if (v == null) {
v = factory.apply(16, height, 16);
}
if (contains(x, z)) {
try {
v = read(x, z);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
loadedChunks.put(new Position2(x, z), v);
if (v == null) {
v = factory.apply(16, height, 16);
}
loadedChunks.put(new ChunkPosition(x, z), v);
return v;
});
return v;
}
public Hunk<T> get(int x, int z) {
return lock.withResult(x, z, () -> {
ChunkPosition key = new ChunkPosition(x, z);
Position2 key = new Position2(x, z);
Hunk<T> c = loadedChunks.get(key);
Hunk<T> c = loadedChunks.get(key);
if (c == null) {
c = load(x, z);
}
if (c == null) {
c = load(x, z);
}
lastUse.put(new ChunkPosition(x, z), M.ms());
lastUse.put(new Position2(x, z), M.ms());
return c;
});
return c;
}
public Hunk<T> getR(int x, int z) {
return lock.withResult(x, z, () -> get(x, z).readOnly());
return get(x, z).readOnly();
}
public Hunk<T> getRW(int x, int z) {
return lock.withResult(x, z, () -> {
save.add(new ChunkPosition(x, z));
return get(x, z);
});
save.add(new Position2(x, z));
return get(x, z);
}
private String key(int x, int z) {

View File

@ -51,7 +51,6 @@ public class ChunkDataHunkView implements Hunk<BlockData> {
return;
}
enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1);
chunk.setRegion(x1, y1, z1, x2, y2, z2, t);
}

Some files were not shown because too many files have changed in this diff Show More