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. 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/) ** # [Support](https://discord.gg/3xxPTpT) **|** [Documentation](https://docs.volmit.com/iris/) **
|** [Git](https://github.com/IrisDimensions) |** [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' group 'com.volmit.iris'
version '1.5.2' version '1.5.6'
def apiVersion = '1.17' def apiVersion = '1.17'
def name = 'Iris' def name = 'Iris'
def main = 'com.volmit.iris.Iris' def main = 'com.volmit.iris.Iris'
@ -81,6 +81,8 @@ shadowJar
} }
} }
manifest()
dependencies { dependencies {
compileOnly 'org.projectlombok:lombok:1.18.20' compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor '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.MultiverseCoreLink;
import com.volmit.iris.core.link.MythicMobsLink; import com.volmit.iris.core.link.MythicMobsLink;
import com.volmit.iris.core.nms.INMS; 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.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisCompat; import com.volmit.iris.engine.object.IrisCompat;
import com.volmit.iris.engine.object.IrisDimension; 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.KList;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
@ -79,9 +80,6 @@ public class Iris extends VolmitPlugin implements Listener {
public static MythicMobsLink linkMythicMobs; public static MythicMobsLink linkMythicMobs;
public static TreeManager saplingManager; public static TreeManager saplingManager;
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>(); 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 IrisCompat compat;
public static FileWatcher configWatcher; public static FileWatcher configWatcher;
@ -95,7 +93,6 @@ public class Iris extends VolmitPlugin implements Listener {
instance = this; instance = this;
INMS.get(); INMS.get();
IO.delete(new File("iris")); IO.delete(new File("iris"));
lowMemoryMode = Runtime.getRuntime().maxMemory() < 4000000000L; // 4 * 1000 * 1000 * 1000 // 4;
installDataPacks(); installDataPacks();
} }
@ -156,54 +153,6 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.info("Data Packs Setup!"); 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 @Override
public void start() { public void start() {
@ -276,6 +225,7 @@ public class Iris extends VolmitPlugin implements Listener {
board.disable(); board.disable();
Bukkit.getScheduler().cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this); HandlerList.unregisterAll((Plugin) this);
MultiBurst.burst.shutdown();
super.onDisable(); super.onDisable();
} }
@ -571,18 +521,6 @@ public class Iris extends VolmitPlugin implements Listener {
} }
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n"); 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") @SuppressWarnings("deprecation")

View File

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

View File

@ -56,14 +56,27 @@ public class IrisSettings {
return getParallax().getParallaxRegionEvictionMS(); 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 @Data
public static class IrisSettingsCache { public static class IrisSettingsCache {
public int streamingCacheSize = 8192; public int complexCacheSize = 131072;
} }
@Data @Data
public static class IrisSettingsConcurrency { 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 @Data
@ -99,8 +112,7 @@ public class IrisSettings {
public boolean systemEffects = true; public boolean systemEffects = true;
public boolean systemEntitySpawnOverrides = true; public boolean systemEntitySpawnOverrides = true;
public boolean systemEntityInitialSpawns = true; public boolean systemEntityInitialSpawns = true;
public int maxBiomeChildDepth = 5; public int maxBiomeChildDepth = 4;
} }
@Data @Data

View File

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

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command; package com.volmit.iris.core.command;
import com.volmit.iris.Iris; 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.framework.IrisAccess;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.MortarCommand;

View File

@ -56,7 +56,7 @@ public class CommandIrisStudioClose extends MortarCommand {
World f = null; World f = null;
for (World i : Bukkit.getWorlds()) { 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; continue;
} }

View File

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

View File

@ -21,7 +21,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager; import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.IrisSettings; 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.engine.object.IrisGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
@ -63,14 +63,14 @@ public class CommandIrisStudioExplorerGenerator extends MortarCommand {
if (Iris.proj.isProjectOpen()) { if (Iris.proj.isProjectOpen()) {
generator = Iris.proj.getActiveProject().getActiveProvider().getData().getGeneratorLoader().load(args[0]); 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 { } else {
generator = IrisDataManager.loadAnyGenerator(args[0]); generator = IrisDataManager.loadAnyGenerator(args[0]);
} }
if (generator != null) { if (generator != null) {
long finalSeed = seed; long finalSeed = seed;
IrisExplorer.launch((x, z) -> NoiseExplorerGUI.launch((x, z) ->
generator.getHeight(x, z, new RNG(finalSeed).nextParallelRNG(3245).lmax()), "Gen: " + generator.getLoadKey()); 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() + ")"); 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.Iris;
import com.volmit.iris.core.IrisDataManager; 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.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion; 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.Iris;
import com.volmit.iris.core.IrisSettings; 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.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender; 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.Iris;
import com.volmit.iris.core.IrisSettings; 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.framework.IrisAccess;
import com.volmit.iris.engine.object.InventorySlotType; import com.volmit.iris.engine.object.InventorySlotType;
import com.volmit.iris.engine.object.IrisLootTable; 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.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.IrisVision; import com.volmit.iris.core.gui.VisionGUI;
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.Engine;
import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
@ -57,12 +57,12 @@ public class CommandIrisStudioMap extends MortarCommand {
try { try {
IrisAccess g = Iris.proj.getActiveProject().getActiveProvider(); IrisAccess g = Iris.proj.getActiveProject().getActiveProvider();
IrisVision.launch(g, 0); VisionGUI.launch(g, 0);
sender.sendMessage("Opening Map!"); sender.sendMessage("Opening Map!");
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
IrisAccess g = IrisWorlds.access(sender.player().getWorld()); IrisAccess g = IrisWorlds.access(sender.player().getWorld());
IrisVision.launch(g, 0); VisionGUI.launch(g, 0);
sender.sendMessage("Opening Map!"); sender.sendMessage("Opening Map!");
} }
return true; return true;

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core.command.studio;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; 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.Engine;
import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisEntity; import com.volmit.iris.engine.object.IrisEntity;

View File

@ -57,7 +57,7 @@ public class CommandIrisStudioTPStudio extends MortarCommand {
try { try {
sender.sendMessage("Teleporting you to the active studio world."); 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); sender.player().setGameMode(GameMode.SPECTATOR);
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(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.Iris;
import com.volmit.iris.core.nms.INMS; 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.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;

View File

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

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.command.world; package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris; 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.framework.IrisAccess;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;

View File

@ -19,8 +19,12 @@
package com.volmit.iris.core.command.world; package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris; 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.collection.KList;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -69,17 +73,17 @@ public class CommandIrisPregen extends MortarCommand {
} }
if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("x")) { if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("x")) {
if (Pregenerator.shutdownInstance()) { if (PregeneratorJob.shutdownInstance()) {
sender.sendMessage("Stopped Pregen."); sender.sendMessage("Stopped Pregen. Finishing last region file before shutting down...");
} else { } else {
sender.sendMessage("No Active Pregens."); sender.sendMessage("No Active Pregens.");
} }
return true; return true;
} else if (args[0].equalsIgnoreCase("pause") || args[0].equalsIgnoreCase("resume")) { } else if (args[0].equalsIgnoreCase("pause") || args[0].equalsIgnoreCase("resume")) {
if (Pregenerator.getInstance() != null) { if (PregeneratorJob.getInstance() != null) {
Pregenerator.pauseResume(); PregeneratorJob.pauseResume();
if (Pregenerator.isPaused()) { if (PregeneratorJob.isPaused()) {
sender.sendMessage("Pregen Paused"); sender.sendMessage("Pregen Paused");
} else { } else {
sender.sendMessage("Pregen Resumed"); sender.sendMessage("Pregen Resumed");
@ -105,7 +109,11 @@ public class CommandIrisPregen extends MortarCommand {
} }
} }
try { 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) { } catch (NumberFormatException e) {
Iris.reportError(e); Iris.reportError(e);
sender.sendMessage("Invalid argument in command"); sender.sendMessage("Invalid argument in command");
@ -131,7 +139,12 @@ public class CommandIrisPregen extends MortarCommand {
} }
World world = Bukkit.getWorld(args[1]); World world = Bukkit.getWorld(args[1]);
try { 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) { } catch (NumberFormatException e) {
Iris.reportError(e); Iris.reportError(e);
sender.sendMessage("Invalid argument in command"); 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; package com.volmit.iris.core.command.world;
import com.volmit.iris.Iris; 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.collection.KList;
import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.MortarCommand;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;

View File

@ -19,7 +19,7 @@
package com.volmit.iris.core.edit; package com.volmit.iris.core.edit;
import com.volmit.iris.Iris; 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.framework.IrisAccess;
import com.volmit.iris.engine.parallax.ParallaxAccess; import com.volmit.iris.engine.parallax.ParallaxAccess;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;

View File

@ -38,7 +38,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock; 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; private static final long serialVersionUID = 2094606939770332040L;
@ -74,7 +74,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
double t; double t;
double tz; double tz;
public IrisExplorer() { public NoiseExplorerGUI() {
addMouseWheelListener(this); addMouseWheelListener(this);
addMouseMotionListener(new MouseMotionListener() { addMouseMotionListener(new MouseMotionListener() {
@Override @Override
@ -237,7 +237,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
private static void createAndShowGUI(Function2<Double, Double, Double> gen, String genName) { private static void createAndShowGUI(Function2<Double, Double, Double> gen, String genName) {
JFrame frame = new JFrame("Noise Explorer: " + genName); JFrame frame = new JFrame("Noise Explorer: " + genName);
IrisExplorer nv = new IrisExplorer(); NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
JLayeredPane pane = new JLayeredPane(); JLayeredPane pane = new JLayeredPane();
nv.setSize(new Dimension(1440, 820)); nv.setSize(new Dimension(1440, 820));
@ -259,7 +259,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
private static void createAndShowGUI() { private static void createAndShowGUI() {
JFrame frame = new JFrame("Noise Explorer"); JFrame frame = new JFrame("Noise Explorer");
IrisExplorer nv = new IrisExplorer(); NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
KList<String> li = new KList<>(NoiseStyle.values()).toStringList(); KList<String> li = new KList<>(NoiseStyle.values()).toStringList();
combo = new JComboBox<>(li.toArray(new String[0])); combo = new JComboBox<>(li.toArray(new String[0]));
@ -296,7 +296,7 @@ public class IrisExplorer extends JPanel implements MouseWheelListener {
} }
public static void launch() { public static void launch() {
EventQueue.invokeLater(IrisExplorer::createAndShowGUI); EventQueue.invokeLater(NoiseExplorerGUI::createAndShowGUI);
} }
static class HandScrollListener extends MouseAdapter { 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; package com.volmit.iris.core.gui;
import com.volmit.iris.Iris; 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.IrisComplex;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion; 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.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; 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.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.attribute.Attribute; import org.bukkit.attribute.Attribute;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -54,7 +56,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.BiFunction; 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 static final long serialVersionUID = 2094606939770332040L;
private RenderType currentType = RenderType.BIOME; private RenderType currentType = RenderType.BIOME;
@ -70,7 +72,7 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
private boolean alt = false; private boolean alt = false;
private int posX = 0; private int posX = 0;
private IrisRenderer renderer; private IrisRenderer renderer;
private World world; private IrisWorld world;
private double velocity = 0; private double velocity = 0;
private int lowq = 12; private int lowq = 12;
private int posZ = 0; private int posZ = 0;
@ -128,7 +130,7 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
}); });
private BufferedImage texture; private BufferedImage texture;
public IrisVision(JFrame frame) { public VisionGUI(JFrame frame) {
m.set(8); m.set(8);
rs.put(1); rs.put(1);
addMouseWheelListener(this); addMouseWheelListener(this);
@ -142,6 +144,13 @@ public class IrisVision extends JPanel implements MouseWheelListener, KeyListene
help = false; help = false;
} }
}); });
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
e.shutdown();
eh.shutdown();
}
});
} }
@Override @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"); JFrame frame = new JFrame("Vision");
IrisVision nv = new IrisVision(frame); VisionGUI nv = new VisionGUI(frame);
nv.world = world; nv.world = world;
nv.engine = r; nv.engine = r;
nv.renderer = new IrisRenderer(r); nv.renderer = new IrisRenderer(r);

View File

@ -16,11 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * 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.framework.Engine;
import com.volmit.iris.engine.interpolation.IrisInterpolation; import com.volmit.iris.engine.interpolation.IrisInterpolation;
import org.bukkit.Material;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -60,8 +59,4 @@ public class IrisRenderer {
return image; 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/>. * 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 { public enum RenderType {
BIOME, BIOME_LAND, BIOME_SEA, REGION, CAVE_LAND, HEIGHT, OBJECT_LOAD, DECORATOR_LOAD, LAYER_LOAD 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/>. * 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.*; import java.awt.*;

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * 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.Builder;
import lombok.Data; 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/>. * 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.core.IrisDataManager;
import com.volmit.iris.engine.framework.EngineCompositeGenerator; import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.IrisDimension; 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.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
@ -78,8 +78,14 @@ public class IrisWorldCreator {
public WorldCreator create() { public WorldCreator create() {
EngineCompositeGenerator g = new EngineCompositeGenerator(dimensionName, !studio); 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) return new WorldCreator(name)
.environment(findEnvironment()) .environment(findEnvironment())
.generateStructures(true) .generateStructures(true)
@ -94,4 +100,9 @@ public class IrisWorldCreator {
return dim.getEnvironment(); 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/>. * 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.Iris;
import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.framework.IrisAccess;

View File

@ -107,15 +107,16 @@ public class IrisComplex implements DataProvider {
} }
public IrisComplex(Engine engine, boolean simple) { public IrisComplex(Engine engine, boolean simple) {
int cacheSize = 1024 * 128; int cacheSize = 131072;
this.rng = new RNG(engine.getWorld().getSeed()); IrisBiome emptyBiome = new IrisBiome();
this.rng = new RNG(engine.getWorld().seed());
this.data = engine.getData(); this.data = engine.getData();
double height = engine.getHeight(); double height = engine.getHeight();
fluidHeight = engine.getDimension().getFluidHeight(); fluidHeight = engine.getDimension().getFluidHeight();
generators = new KList<>(); generators = new KList<>();
focus = engine.getFocus(); focus = engine.getFocus();
IrisRegion focusRegion = focus != null ? findRegion(focus, engine) : null; IrisRegion focusRegion = focus != null ? findRegion(focus, engine) : null;
RNG rng = new RNG(engine.getWorld().getSeed()); RNG rng = new RNG(engine.getWorld().seed());
//@builder //@builder
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i) engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
.getAllBiomes(this).forEach((b) -> b .getAllBiomes(this).forEach((b) -> b
@ -124,7 +125,7 @@ public class IrisComplex implements DataProvider {
overlayStream = ProceduralStream.ofDouble((x, z) -> 0D); overlayStream = ProceduralStream.ofDouble((x, z) -> 0D);
engine.getDimension().getOverlayNoise().forEach((i) -> overlayStream.add((x, z) -> i.get(rng, x, z))); 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)) 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(); chunkRngStream = rngStream.blockToChunkCoords();
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream() rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
.select(engine.getDimension().getRockPalette().getBlockData(data)); .select(engine.getDimension().getRockPalette().getBlockData(data));
@ -151,7 +152,7 @@ public class IrisComplex implements DataProvider {
.onNull("") .onNull("")
.convertCached((s) -> { .convertCached((s) -> {
if (s.isEmpty()) { if (s.isEmpty()) {
return new IrisBiome(); return emptyBiome;
} }
return data.getBiomeLoader().load(s) return data.getBiomeLoader().load(s)
@ -193,12 +194,11 @@ public class IrisComplex implements DataProvider {
.convertAware2D(this::implode).cache2D(cacheSize); .convertAware2D(this::implode).cache2D(cacheSize);
heightStream = ProceduralStream.of((x, z) -> { heightStream = ProceduralStream.of((x, z) -> {
IrisBiome b = focus != null ? focus : baseBiomeStream.get(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); }, 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) -> { objectChanceStream = ProceduralStream.ofDouble((x, z) -> {
if(engine.getDimension().hasFeatures(engine)) if (engine.getDimension().hasFeatures(engine)) {
{
AtomicDouble str = new AtomicDouble(1D); AtomicDouble str = new AtomicDouble(1D);
engine.getFramework().getEngineParallax().forEachFeature(x, z, (i) engine.getFramework().getEngineParallax().forEachFeature(x, z, (i)
-> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z)))); -> 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.IrisBiomePaletteLayer;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.engine.object.IrisObjectPlacement; 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.engine.parallel.MultiBurst;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
@ -41,8 +41,6 @@ import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class IrisEngine extends BlockPopulator implements Engine { public class IrisEngine extends BlockPopulator implements Engine {
@Getter @Getter
@ -88,7 +86,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
private double maxBiomeDecoratorDensity; private double maxBiomeDecoratorDensity;
public IrisEngine(EngineTarget target, EngineCompound compound, int index) { 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); metrics = new EngineMetrics(32);
this.target = target; this.target = target;
this.framework = new IrisEngineFramework(this); this.framework = new IrisEngineFramework(this);
@ -136,6 +134,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
closed = true; closed = true;
getWorldManager().close(); getWorldManager().close();
getFramework().close(); getFramework().close();
getTarget().close();
} }
@Override @Override
@ -158,21 +157,39 @@ public class IrisEngine extends BlockPopulator implements Engine {
return z / getDimension().getTerrainZoom(); return z / getDimension().getTerrainZoom();
} }
@ChunkCoordinates
@Override @Override
public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes) { public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes) {
try { try {
PrecisionStopwatch p = PrecisionStopwatch.start(); 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()) { switch (getDimension().getTerrainMode()) {
case NORMAL -> { case NORMAL -> {
getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4); getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4);
getFramework().getBiomeActuator().actuate(x, z, vbiomes);
getFramework().getTerrainActuator().actuate(x, z, vblocks); getFramework().getTerrainActuator().actuate(x, z, vblocks);
getFramework().getBiomeActuator().actuate(x, z, vbiomes);
getFramework().getCaveModifier().modify(x, z, vblocks); getFramework().getCaveModifier().modify(x, z, vblocks);
getFramework().getRavineModifier().modify(x, z, vblocks); getFramework().getRavineModifier().modify(x, z, vblocks);
getFramework().getPostModifier().modify(x, z, vblocks); getFramework().getPostModifier().modify(x, z, vblocks);
getFramework().getDecorantActuator().actuate(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); getFramework().getDepositModifier().modify(x, z, vblocks);
} }
case ISLANDS -> { case ISLANDS -> {
@ -195,6 +212,11 @@ public class IrisEngine extends BlockPopulator implements Engine {
return getData().getBiomeLoader().load(getDimension().getFocus()); return getData().getBiomeLoader().load(getDimension().getFocus());
} }
@Override
public void hotloading() {
close();
}
@Override @Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk c) { public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk c) {
getWorldManager().spawnInitialEntities(c); getWorldManager().spawnInitialEntities(c);

View File

@ -20,6 +20,7 @@ package com.volmit.iris.engine;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager; 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.Engine;
import com.volmit.iris.engine.framework.EngineCompound; import com.volmit.iris.engine.framework.EngineCompound;
import com.volmit.iris.engine.framework.EngineData; 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.IrisDimension;
import com.volmit.iris.engine.object.IrisDimensionIndex; import com.volmit.iris.engine.object.IrisDimensionIndex;
import com.volmit.iris.engine.object.IrisPosition; 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.engine.parallel.MultiBurst;
import com.volmit.iris.util.atomics.AtomicRollingSequence; import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KList; 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 com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -50,7 +51,7 @@ import java.util.List;
public class IrisEngineCompound implements EngineCompound { public class IrisEngineCompound implements EngineCompound {
@Getter @Getter
private World world; private IrisWorld world;
private final AtomicRollingSequence wallClock; private final AtomicRollingSequence wallClock;
@ -77,10 +78,10 @@ public class IrisEngineCompound implements EngineCompound {
@Setter @Setter
private boolean studio; 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); wallClock = new AtomicRollingSequence(32);
this.rootDimension = rootDimension; this.rootDimension = rootDimension;
Iris.info("Initializing Engine Composite for " + world.getName()); Iris.info("Initializing Engine Composite for " + world.name());
this.world = world; this.world = world;
engineMetadata = EngineData.load(getEngineMetadataFile()); engineMetadata = EngineData.load(getEngineMetadataFile());
engineMetadata.setDimension(rootDimension.getLoadKey()); engineMetadata.setDimension(rootDimension.getLoadKey());
@ -97,7 +98,7 @@ public class IrisEngineCompound implements EngineCompound {
} else { } else {
double totalWeight = 0D; double totalWeight = 0D;
engines = new Engine[rootDimension.getDimensionalComposite().size()]; 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; int threadDist = (Math.max(2, maximumThreads - engines.length)) / engines.length;
if ((threadDist * engines.length) + engines.length > maximumThreads) { if ((threadDist * engines.length) + engines.length > maximumThreads) {
@ -208,7 +209,7 @@ public class IrisEngineCompound implements EngineCompound {
} }
private File getEngineMetadataFile() { private File getEngineMetadataFile() {
return new File(world.getWorldFolder(), "iris/engine-metadata.json"); return new File(world.worldFolder(), "iris/engine-metadata.json");
} }
@Override @Override
@ -274,11 +275,6 @@ public class IrisEngineCompound implements EngineCompound {
return defaultEngine; return defaultEngine;
} }
@Override
public void updateWorld(World world) {
this.world = world;
}
@Override @Override
public void hotload() { public void hotload() {
for (int i = 0; i < getSize(); i++) { 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.hunk.view.BiomeGridHunkView;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom; 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.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
@ -37,9 +38,10 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
public IrisBiomeActuator(Engine engine) { public IrisBiomeActuator(Engine engine) {
super(engine, "Biome"); 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) { private boolean injectBiome(Hunk<Biome> h, int x, int y, int z, Object bb) {
try { try {
if (h instanceof BiomeGridHunkView hh) { if (h instanceof BiomeGridHunkView hh) {
@ -59,6 +61,7 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
return false; return false;
} }
@BlockCoordinates
@Override @Override
public void onActuate(int x, int z, Hunk<Biome> h) { public void onActuate(int x, int z, Hunk<Biome> h) {
PrecisionStopwatch p = PrecisionStopwatch.start(); 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.framework.EngineDecorator;
import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; 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.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter; import lombok.Getter;
@ -50,7 +51,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
public IrisDecorantActuator(Engine engine) { public IrisDecorantActuator(Engine engine) {
super(engine, "Decorant"); super(engine, "Decorant");
shouldRay = shouldRayDecorate(); shouldRay = shouldRayDecorate();
this.rng = new RNG(engine.getTarget().getWorld().getSeed()); this.rng = new RNG(engine.getTarget().getWorld().seed());
surfaceDecorator = new IrisSurfaceDecorator(getEngine()); surfaceDecorator = new IrisSurfaceDecorator(getEngine());
ceilingDecorator = new IrisCeilingDecorator(getEngine()); ceilingDecorator = new IrisCeilingDecorator(getEngine());
seaSurfaceDecorator = new IrisSeaSurfaceDecorator(getEngine()); seaSurfaceDecorator = new IrisSeaSurfaceDecorator(getEngine());
@ -58,6 +59,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
seaFloorDecorator = new IrisSeaFloorDecorator(getEngine()); seaFloorDecorator = new IrisSeaFloorDecorator(getEngine());
} }
@BlockCoordinates
@Override @Override
public void onActuate(int x, int z, Hunk<BlockData> output) { public void onActuate(int x, int z, Hunk<BlockData> output) {
if (!getEngine().getDimension().isDecorate()) { 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.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList; 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.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter; import lombok.Getter;
@ -45,11 +46,12 @@ public class IrisTerrainIslandActuator extends EngineAssignedActuator<BlockData>
public IrisTerrainIslandActuator(Engine engine) { public IrisTerrainIslandActuator(Engine engine) {
super(engine, "TerrainIsland"); super(engine, "TerrainIsland");
rng = new RNG(engine.getWorld().getSeed()); rng = new RNG(engine.getWorld().seed());
carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty(); carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty();
hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat(); hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat();
} }
@BlockCoordinates
@Override @Override
public void onActuate(int x, int z, Hunk<BlockData> h) { public void onActuate(int x, int z, Hunk<BlockData> h) {
PrecisionStopwatch p = PrecisionStopwatch.start(); 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.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList; 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.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter; import lombok.Getter;
@ -42,11 +43,12 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
public IrisTerrainNormalActuator(Engine engine) { public IrisTerrainNormalActuator(Engine engine) {
super(engine, "Terrain"); super(engine, "Terrain");
rng = new RNG(engine.getWorld().getSeed()); rng = new RNG(engine.getWorld().seed());
carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty(); carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty();
hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat(); hasUnder = getDimension().getUndercarriage() != null && !getDimension().getUndercarriage().getGenerator().isFlat();
} }
@BlockCoordinates
@Override @Override
public void onActuate(int x, int z, Hunk<BlockData> h) { public void onActuate(int x, int z, Hunk<BlockData> h) {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();

View File

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

View File

@ -18,13 +18,12 @@
package com.volmit.iris.engine.data.chunk; 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.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.data.IrisBiomeStorage; import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.fakenews.HeightedFakeWorld;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.generator.ChunkGenerator.BiomeGrid; import org.bukkit.generator.ChunkGenerator.BiomeGrid;
@ -38,8 +37,12 @@ public class LinkedTerrainChunk implements TerrainChunk {
private ChunkData rawChunkData; private ChunkData rawChunkData;
private final BiomeGrid storage; private final BiomeGrid storage;
public LinkedTerrainChunk(int maxHeight) { public LinkedTerrainChunk(World world) {
this(null, maxHeight); this(null, Bukkit.createChunkData(world));
}
public LinkedTerrainChunk(World world, BiomeGrid storage) {
this(storage, Bukkit.createChunkData(world));
} }
public LinkedTerrainChunk(BiomeGrid storage, ChunkData data) { public LinkedTerrainChunk(BiomeGrid storage, ChunkData data) {
@ -48,23 +51,6 @@ public class LinkedTerrainChunk implements TerrainChunk {
biome3D = storage != null ? null : new IrisBiomeStorage(); 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 @Override
public BiomeBaseInjector getBiomeBaseInjector() { public BiomeBaseInjector getBiomeBaseInjector() {
return (x, y, z, bb) -> INMS.get().forceBiomeInto(x, y, z, bb, storage); 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 { public interface TerrainChunk extends BiomeGrid, ChunkData {
static TerrainChunk create(World world) { static TerrainChunk create(World world) {
return create(world.getMaxHeight()); return new LinkedTerrainChunk(world);
}
static TerrainChunk create(int maxHeight) {
return new LinkedTerrainChunk(maxHeight);
} }
static TerrainChunk create(World world, BiomeGrid grid) { static TerrainChunk create(World world, BiomeGrid grid) {
return create(world.getMaxHeight(), grid); return new LinkedTerrainChunk(world, grid);
} }
static TerrainChunk create(ChunkData raw, BiomeGrid grid) { static TerrainChunk create(ChunkData raw, BiomeGrid grid) {
return new LinkedTerrainChunk(grid, raw); return new LinkedTerrainChunk(grid, raw);
} }
static TerrainChunk create(int maxHeight, BiomeGrid grid) {
return new LinkedTerrainChunk(grid, maxHeight);
}
BiomeBaseInjector getBiomeBaseInjector(); BiomeBaseInjector getBiomeBaseInjector();
void setRaw(ChunkData data); void setRaw(ChunkData data);

View File

@ -19,6 +19,8 @@
package com.volmit.iris.engine.data.mca; package com.volmit.iris.engine.data.mca;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag; 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.IOException;
import java.io.RandomAccessFile; 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() { public AtomicReferenceArray<Chunk> getChunks() {
return chunks; return chunks;
} }
@ -218,8 +241,7 @@ public class MCAFile {
return getChunk(getChunkIndex(chunkX, chunkZ)); return getChunk(getChunkIndex(chunkX, chunkZ));
} }
public boolean hasChunk(int chunkX, int chunkZ) public boolean hasChunk(int chunkX, int chunkZ) {
{
return getChunk(chunkX, chunkZ) != null; return getChunk(chunkX, chunkZ) != null;
} }

View File

@ -18,6 +18,9 @@
package com.volmit.iris.engine.data.mca; 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.File;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; 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. * 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.B;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag; import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
import com.volmit.iris.engine.data.nbt.tag.StringTag; 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.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.IrisLock; import com.volmit.iris.util.scheduling.IrisLock;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; 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 { public class NBTWorld {
private static final BlockData AIR = B.get("AIR"); private static final BlockData AIR = B.get("AIR");
@ -50,8 +49,7 @@ public class NBTWorld {
private final File worldFolder; private final File worldFolder;
private final ExecutorService saveQueue; private final ExecutorService saveQueue;
public NBTWorld(File worldFolder) public NBTWorld(File worldFolder) {
{
this.worldFolder = worldFolder; this.worldFolder = worldFolder;
this.loadedRegions = new KMap<>(); this.loadedRegions = new KMap<>();
this.lastUse = new KMap<>(); this.lastUse = new KMap<>();
@ -63,20 +61,17 @@ public class NBTWorld {
}); });
} }
public void close() public void close() {
{
regionLock.lock(); regionLock.lock();
for(Long i : loadedRegions.k()) for (Long i : loadedRegions.k()) {
{
queueSaveUnload(Cache.keyX(i), Cache.keyZ(i)); queueSaveUnload(Cache.keyX(i), Cache.keyZ(i));
} }
regionLock.unlock(); regionLock.unlock();
saveQueue.shutdown(); saveQueue.shutdown();
try { try {
while(!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) while (!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) {
{
Iris.info("Still Waiting to save MCA Files..."); Iris.info("Still Waiting to save MCA Files...");
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -84,37 +79,43 @@ public class NBTWorld {
} }
} }
public void queueSaveUnload(int x, int z) public void flushNow() {
{ regionLock.lock();
saveQueue.submit(() -> {
MCAFile f = getMCAOrNull(x, z);
if(f != null)
{
unloadRegion(x, z);
}
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(); regionLock.lock();
boolean saving = true; boolean saving = true;
for(Long i : loadedRegions.k()) for (Long i : loadedRegions.k()) {
{
int x = Cache.keyX(i); int x = Cache.keyX(i);
int z = Cache.keyZ(i); int z = Cache.keyZ(i);
if(!lastUse.containsKey(i)) if (!lastUse.containsKey(i)) {
{
lastUse.put(i, M.ms()); lastUse.put(i, M.ms());
} }
if(shouldUnload(x, z)) if (shouldUnload(x, z)) {
{
queueSaveUnload(x, z); queueSaveUnload(x, z);
} }
} }
@ -124,13 +125,11 @@ public class NBTWorld {
regionLock.unlock(); 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); long key = Cache.key(x, z);
regionLock.lock(); regionLock.lock();
loadedRegions.remove(key); loadedRegions.remove(key);
@ -139,8 +138,7 @@ public class NBTWorld {
Iris.debug("Unloaded Region " + C.GOLD + x + " " + z); 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); long k = Cache.key(x, z);
MCAFile mca = getMCAOrNull(x, z); MCAFile mca = getMCAOrNull(x, z);
try { 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 { try {
MCAUtil.write(mca, getRegionFile(x, z), true); MCAUtil.write(mca, getRegionFile(x, z), true);
Iris.debug("Saved Region " + C.GOLD + x + " " + z); 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; return getIdleDuration(x, z) > 60000;
} }
@ -281,8 +277,7 @@ public class NBTWorld {
return c; return c;
} }
public long getIdleDuration(int x, int z) public long getIdleDuration(int x, int z) {
{
Long l = lastUse.get(Cache.key(x, z)); Long l = lastUse.get(Cache.key(x, z));
return l == null ? 0 : (M.ms() - l); return l == null ? 0 : (M.ms() - l);
@ -296,17 +291,8 @@ public class NBTWorld {
MCAFile mcaf = loadedRegions.get(key); MCAFile mcaf = loadedRegions.get(key);
regionLock.unlock(); regionLock.unlock();
if(mcaf == null) if (mcaf == null) {
{ mcaf = new MCAFile(x, z);
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);
}
regionLock.lock(); regionLock.lock();
loadedRegions.put(key, mcaf); loadedRegions.put(key, mcaf);
regionLock.unlock(); regionLock.unlock();
@ -320,8 +306,7 @@ public class NBTWorld {
MCAFile ff = null; MCAFile ff = null;
regionLock.lock(); regionLock.lock();
if(loadedRegions.containsKey(key)) if (loadedRegions.containsKey(key)) {
{
lastUse.put(key, M.ms()); lastUse.put(key, M.ms());
ff = loadedRegions.get(key); 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.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisCeilingDecorator extends IrisEngineDecorator { public class IrisCeilingDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
super(engine, "Ceiling", DecorationPart.CEILING); super(engine, "Ceiling", DecorationPart.CEILING);
} }
@BlockCoordinates
@Override @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) { 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); 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.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisSeaFloorDecorator extends IrisEngineDecorator { public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
super(engine, "Sea Floor", DecorationPart.SEA_FLOOR); super(engine, "Sea Floor", DecorationPart.SEA_FLOOR);
} }
@BlockCoordinates
@Override @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) { 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()) { 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.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisSeaSurfaceDecorator extends IrisEngineDecorator { public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
super(engine, "Sea Surface", DecorationPart.SEA_SURFACE); super(engine, "Sea Surface", DecorationPart.SEA_SURFACE);
} }
@BlockCoordinates
@Override @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) { 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); 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.DecorationPart;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisShoreLineDecorator extends IrisEngineDecorator { public class IrisShoreLineDecorator extends IrisEngineDecorator {
@ -31,6 +32,7 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
super(engine, "Shore Line", DecorationPart.SHORE_LINE); super(engine, "Shore Line", DecorationPart.SHORE_LINE);
} }
@BlockCoordinates
@Override @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) { 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.InferredType;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorator; 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.Bisected;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -34,6 +35,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
super(engine, "Surface", DecorationPart.NONE); super(engine, "Surface", DecorationPart.NONE);
} }
@BlockCoordinates
@Override @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) { 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()) { 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.Iris;
import com.volmit.iris.core.IrisDataManager; import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.gui.RenderType; import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.core.gui.Renderer; import com.volmit.iris.core.gui.components.Renderer;
import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.B; import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.DataProvider; import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.*; 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.parallax.ParallaxAccess;
import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; 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.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -105,7 +105,7 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
return getTarget().getData(); return getTarget().getData();
} }
default World getWorld() { default IrisWorld getWorld() {
return getTarget().getWorld(); return getTarget().getWorld();
} }
@ -357,8 +357,12 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
return getCompound().isStudio(); return getCompound().isStudio();
} }
default MultiBurst burst() {
return getTarget().getBurster();
}
default void clean() { default void clean() {
MultiBurst.burst.lazy(() -> getParallax().cleanup()); burst().lazy(() -> getParallax().cleanup());
} }
default IrisBiome getBiome(Location l) { default IrisBiome getBiome(Location l) {
@ -374,4 +378,6 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
} }
IrisBiome getFocus(); IrisBiome getFocus();
void hotloading();
} }

View File

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

View File

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

View File

@ -69,7 +69,7 @@ public interface EngineComponent {
} }
default long getSeed() { default long getSeed() {
return getTarget().getWorld().getSeed(); return getTarget().getWorld().seed();
} }
default EngineFramework getFramework() { 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.IrisSettings;
import com.volmit.iris.core.nms.BiomeBaseInjector; import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS; 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.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.B;
import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.data.mca.NBTWorld; 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.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition; 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.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; 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.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.ReactiveFolder; 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.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import io.netty.util.internal.ConcurrentSet; import io.netty.util.internal.ConcurrentSet;
import io.papermc.lib.PaperLib;
import lombok.Getter; import lombok.Getter;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
@ -77,11 +77,11 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
private final boolean production; private final boolean production;
private final KList<BlockPopulator> populators; private final KList<BlockPopulator> populators;
private long mst = 0; private long mst = 0;
private HeadlessGenerator headlessGenerator;
private NBTWorld nbtWorld;
private int generated = 0; private int generated = 0;
private int lgenerated = 0; private int lgenerated = 0;
private final KMap<Long, PregeneratedData> chunkCache;
private final ChronoLatch hotloadcd; private final ChronoLatch hotloadcd;
private final AtomicBoolean fake;
@Getter @Getter
private double generatedPerSecond = 0; private double generatedPerSecond = 0;
private final int art; private final int art;
@ -93,8 +93,6 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
public EngineCompositeGenerator(String query, boolean production) { public EngineCompositeGenerator(String query, boolean production) {
super(); super();
chunkCache = new KMap<>();
fake = new AtomicBoolean(true);
hotloadcd = new ChronoLatch(3500); hotloadcd = new ChronoLatch(3500);
mst = M.ms(); mst = M.ms();
this.production = production; this.production = production;
@ -113,6 +111,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}); });
} }
@Override
public void hotload() { public void hotload() {
if (isStudio()) { if (isStudio()) {
Iris.proj.updateWorkspace(); Iris.proj.updateWorkspace();
@ -128,12 +127,14 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
} }
}); });
getComposite().close();
initialized.lazySet(false); initialized.lazySet(false);
} }
} }
public void tick() { public void tick() {
if (isClosed()) { if (getComposite() == null || isClosed()) {
return; 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; String query = dimensionQuery;
query = Iris.linkMultiverseCore.getWorldNameType(world.getName(), query); query = Iris.linkMultiverseCore.getWorldNameType(world.name(), query);
IrisDimension dim = null; IrisDimension dim = null;
if (query == null) { if (query == null) {
File iris = new File(world.getWorldFolder(), "iris"); File iris = new File(world.worldFolder(), "iris");
if (iris.exists() && iris.isDirectory()) { if (iris.exists() && iris.isDirectory()) {
for (File i : iris.listFiles()) { for (File i : iris.listFiles()) {
@ -191,7 +192,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
} }
if (query == null) { 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(); 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()); dim = new IrisDataManager(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) { if (dim == null) {
Iris.info("Installing Iris pack " + od.getName() + " into world " + world.getName() + "..."); Iris.info("Installing Iris pack " + od.getName() + " into world " + world.name() + "...");
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), world.getWorldFolder()); Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), world.worldFolder());
dim = new IrisDataManager(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey()); dim = new IrisDataManager(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) { if (dim == null) {
@ -294,20 +295,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return dim; return dim;
} }
public synchronized void initialize(World world) { public synchronized void initialize(IrisWorld 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");
}
if (initialized.get()) { if (initialized.get()) {
return; return;
} }
@ -316,12 +304,16 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
initialized.set(true); initialized.set(true);
IrisDimension dim = getDimension(world); IrisDimension dim = getDimension(world);
IrisDataManager data = production ? new IrisDataManager(getDataFolder(world)) : dim.getLoader().copy(); 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); compound.get().setStudio(!production);
populators.clear(); populators.clear();
populators.addAll(compound.get().getPopulators()); populators.addAll(compound.get().getPopulators());
hotloader = new ReactiveFolder(data.getDataFolder(), (a, c, d) -> hotload()); 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) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
e.printStackTrace(); e.printStackTrace();
@ -445,8 +437,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
); );
} }
private File getDataFolder(World world) { private File getDataFolder(IrisWorld world) {
return new File(world.getWorldFolder(), "iris/pack"); return new File(world.worldFolder(), "iris/pack");
} }
private File getDataFolder(String world) { 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) { public ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) {
PrecisionStopwatch ps = PrecisionStopwatch.start(); PrecisionStopwatch ps = PrecisionStopwatch.start();
TerrainChunk tc = TerrainChunk.create(world, biome); 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++; generated++;
ps.end(); ps.end();
@ -469,23 +467,48 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return tc.getRaw(); return tc.getRaw();
} }
public void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst) { public void assignHeadlessGenerator(HeadlessGenerator headlessGenerator) {
BurstExecutor e = burst.burst(1024); this.headlessGenerator = headlessGenerator;
int mcaox = x << 5; }
int mcaoz = z << 5;
for (int i = 0; i < 32; i++) { @Override
int ii = i; public HeadlessGenerator getHeadlessGenerator() {
for (int j = 0; j < 32; j++) { return headlessGenerator;
int jj = j; }
e.queue(() -> directWriteChunk(w, ii + mcaox, jj + mcaoz, writer));
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(); 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 ox = x << 4;
int oz = z << 4; int oz = z << 4;
com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z); com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z);
@ -526,12 +549,12 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
@Override @Override
public int getMinHeight() { public int getMinHeight() {
return w.getMinHeight(); return w.minHeight();
} }
@Override @Override
public int getMaxHeight() { public int getMaxHeight() {
return w.getMaxHeight(); return w.maxHeight();
} }
@Override @Override
@ -614,50 +637,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
}).run(); }).run();
} }
public Chunk generatePaper(World world, int x, int z) { public Runnable generateChunkRawData(IrisWorld world, int x, int z, TerrainChunk tc) {
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) {
initialize(world); 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<BlockData> blocks = Hunk.view((ChunkData) tc);
Hunk<Biome> biomes = Hunk.view((BiomeGrid) tc); Hunk<Biome> biomes = Hunk.view((BiomeGrid) tc);
Hunk<BlockData> post = Hunk.newAtomicHunk(biomes.getWidth(), biomes.getHeight(), biomes.getDepth()); 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 // 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 @Override
public void close() { public void close() {
J.car(art); J.car(art);
if (getComposite() != null) { if (getComposite() != null) {
getComposite().close(); getComposite().close();
if (isStudio() && getComposite().getWorld().hasRealWorld()) {
if (isStudio()) { getComposite().getWorld().evacuate();
IrisWorlds.evacuate(getComposite().getWorld()); Bukkit.unloadWorld(getComposite().getWorld().realWorld(), !isStudio());
Bukkit.unloadWorld(getComposite().getWorld(), !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.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition; 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.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender; 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); void generate(int x, int z, Hunk<BlockData> blocks, Hunk<BlockData> postblocks, Hunk<Biome> biomes);
World getWorld(); IrisWorld getWorld();
List<IrisPosition> getStrongholdPositions(); List<IrisPosition> getStrongholdPositions();
@ -149,8 +149,6 @@ public interface EngineCompound extends Listener, Hotloadable, DataProvider {
return v.v(); return v.v();
} }
void updateWorld(World world);
default int getLowestBedrock() { default int getLowestBedrock() {
int f = Integer.MAX_VALUE; 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.data.B;
import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.documentation.BlockCoordinates;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public interface EngineDecorator extends EngineComponent { 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); 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) { 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); 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; package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
public interface EngineModifier<T> extends EngineComponent { public interface EngineModifier<T> extends EngineComponent {
@BlockCoordinates
void modify(int x, int z, Hunk<T> t); 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.ParallaxAccess;
import com.volmit.iris.engine.parallax.ParallaxChunkMeta; import com.volmit.iris.engine.parallax.ParallaxChunkMeta;
import com.volmit.iris.engine.parallel.BurstExecutor; 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.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; 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.format.Form;
import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.math.RNG; 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) { default void insertParallax(int x, int z, Hunk<BlockData> data) {
if (!getEngine().getDimension().isPlaceObjects()) {
return;
}
try { try {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
ParallaxChunkMeta meta = getParallaxAccess().getMetaR(x >> 4, z >> 4); ParallaxChunkMeta meta = getParallaxAccess().getMetaR(x, z);
if (!meta.isParallaxGenerated()) { if (!meta.isParallaxGenerated()) {
generateParallaxLayer(x, z, true); generateParallaxLayer(x, z, true);
meta = getParallaxAccess().getMetaR(x >> 4, z >> 4); meta = getParallaxAccess().getMetaR(x, z);
} }
if (!meta.isObjects()) { if (!meta.isObjects()) {
@ -180,7 +185,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
return; return;
} }
getParallaxAccess().getBlocksR(x >> 4, z >> 4).iterateSync((a, b, c, d) -> { getParallaxAccess().getBlocksR(x, z).iterateSync((a, b, c, d) -> {
if (d != null) { if (d != null) {
data.set(a, b, c, d); data.set(a, b, c, d);
} }
@ -199,8 +204,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
IrisLock getFeatureLock(); IrisLock getFeatureLock();
default void forEachFeature(double x, double z, Consumer<IrisFeaturePositional> f) { default void forEachFeature(double x, double z, Consumer<IrisFeaturePositional> f) {
if(!getEngine().getDimension().hasFeatures(getEngine())) if (!getEngine().getDimension().hasFeatures(getEngine())) {
{
return; return;
} }
@ -229,14 +233,18 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
for (j = -s; j <= s; j++) { for (j = -s; j <= s; j++) {
ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz); ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz);
try { synchronized (m) {
for (IrisFeaturePositional k : m.getFeatures()) { try {
if (k.shouldFilter(x, z)) { for (IrisFeaturePositional k : m.getFeatures()) {
pos.add(k); 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; int i, j;
KList<Runnable> after = new KList<>(); KList<Runnable> after = new KList<>();
int bs = (int) Math.pow((s * 2) + 1, 2); 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 (i = -s; i <= s; i++) {
for (j = -s; j <= s; j++) { for (j = -s; j <= s; j++) {
int xx = i + x; int xx = i + x;
@ -271,7 +279,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
if (!getParallaxAccess().isFeatureGenerated(xx, zz)) { if (!getParallaxAccess().isFeatureGenerated(xx, zz)) {
burst.queue(() -> { burst.queue(() -> {
getParallaxAccess().setFeatureGenerated(xx, zz); 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); IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
IrisBiome biome = getComplex().getTrueBiomeStream().get(xxx, zzz); IrisBiome biome = getComplex().getTrueBiomeStream().get(xxx, zzz);
generateParallaxFeatures(rng, xx, zz, region, biome); generateParallaxFeatures(rng, xx, zz, region, biome);
@ -283,7 +291,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
burst.complete(); burst.complete();
if (getEngine().getDimension().isPlaceObjects()) { if (getEngine().getDimension().isPlaceObjects()) {
burst = MultiBurst.burst.burst(bs); burst = getEngine().getTarget().getBurster().burst(bs);
for (i = -s; i <= s; i++) { for (i = -s; i <= s; i++) {
int ii = i; int ii = i;
@ -299,7 +307,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
} }
burst.complete(); burst.complete();
burst = MultiBurst.burst.burst(bs); burst = getEngine().getTarget().getBurster().burst(bs);
for (i = -s; i <= s; i++) { for (i = -s; i <= s; i++) {
int ii = i; int ii = i;
@ -312,7 +320,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
burst.complete(); burst.complete();
} }
MultiBurst.burst.burst(after); getEngine().getTarget().getBurster().burst(after);
getParallaxAccess().setChunkGenerated(x, z); getParallaxAccess().setChunkGenerated(x, z);
p.end(); p.end();
getEngine().getMetrics().getParallax().put(p.getMilliseconds()); getEngine().getMetrics().getParallax().put(p.getMilliseconds());
@ -325,14 +333,14 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
default KList<Runnable> generateParallaxVacuumLayer(int x, int z) { default KList<Runnable> generateParallaxVacuumLayer(int x, int z) {
KList<Runnable> after = new KList<>(); KList<Runnable> after = new KList<>();
if (getParallaxAccess().isParallaxGenerated(x, z)) { if (getParallaxAccess().isParallaxGenerated(x >> 4, z >> 4)) {
return after; return after;
} }
if (getEngine().getDimension().isPlaceObjects()) { if (getEngine().getDimension().isPlaceObjects()) {
int xx = x << 4; int xx = x << 4;
int zz = z << 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); IrisRegion region = getComplex().getRegionStream().get(xx + 8, zz + 8);
IrisBiome biome = getComplex().getTrueBiomeStream().get(xx + 8, zz + 8); IrisBiome biome = getComplex().getTrueBiomeStream().get(xx + 8, zz + 8);
after.addAll(generateParallaxJigsaw(rng, x, z, biome, region)); after.addAll(generateParallaxJigsaw(rng, x, z, biome, region));
@ -351,7 +359,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
int xx = x << 4; int xx = x << 4;
int zz = z << 4; int zz = z << 4;
getParallaxAccess().setParallaxGenerated(x, z); 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); IrisBiome biome = getComplex().getTrueBiomeStream().get(xx + 8, zz + 8);
IrisRegion region = getComplex().getRegionStream().get(xx + 8, zz + 8); IrisRegion region = getComplex().getRegionStream().get(xx + 8, zz + 8);
generateParallaxSurface(rng, x, z, biome, region, false); 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."); 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<>(); KMap<String, BlockVector> sizeCache = new KMap<>();
for (String i : objects) { for (String i : objects) {
e.queue(() -> { e.queue(() -> {

View File

@ -19,11 +19,12 @@
package com.volmit.iris.engine.framework; package com.volmit.iris.engine.framework;
import com.volmit.iris.core.IrisDataManager; 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.IrisDimension;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.parallax.ParallaxWorld; import com.volmit.iris.engine.parallax.ParallaxWorld;
import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.engine.parallel.MultiBurst;
import lombok.Data; import lombok.Data;
import org.bukkit.World;
import java.io.File; import java.io.File;
@ -31,27 +32,27 @@ import java.io.File;
public class EngineTarget { public class EngineTarget {
private final MultiBurst burster; private final MultiBurst burster;
private final IrisDimension dimension; private final IrisDimension dimension;
private World world; private IrisWorld world;
private final int height; private final int height;
private final IrisDataManager data; private final IrisDataManager data;
private final ParallaxWorld parallaxWorld; private final ParallaxWorld parallaxWorld;
private final boolean inverted; 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.world = world;
this.height = height; this.height = height;
this.dimension = dimension; this.dimension = dimension;
this.data = data; this.data = data;
this.parallaxWorld = new ParallaxWorld(256, new File(world.getWorldFolder(), "iris/" + dimension.getLoadKey() + "/parallax"));
this.inverted = inverted; 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) { public EngineTarget(IrisWorld world, IrisDimension dimension, IrisDataManager data, int height, int threads) {
this.world = world;
}
public EngineTarget(World world, IrisDimension dimension, IrisDataManager data, int height, int threads) {
this(world, dimension, data, height, false, 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; package com.volmit.iris.engine.framework;
import com.volmit.iris.core.IrisDataManager; 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.data.DataProvider;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisObjectPlacement; 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.Iris;
import com.volmit.iris.core.IrisDataManager; import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.DataProvider; import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.data.mca.NBTWorld; 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.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion; 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.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -44,9 +45,19 @@ import java.util.function.Consumer;
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
public interface IrisAccess extends Hotloadable, DataProvider { 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(); int getGenerated();
@ -72,8 +83,6 @@ public interface IrisAccess extends Hotloadable, DataProvider {
void changeThreadCount(int m); void changeThreadCount(int m);
void regenerate(int x, int z);
void close(); void close();
boolean isClosed(); boolean isClosed();
@ -87,6 +96,11 @@ public interface IrisAccess extends Hotloadable, DataProvider {
boolean isStudio(); boolean isStudio();
default Location lookForBiome(IrisBiome biome, long timeout, Consumer<Integer> triesc) { 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); IrisComplex.cacheLock.set(true);
ChronoLatch cl = new ChronoLatch(250, false); ChronoLatch cl = new ChronoLatch(250, false);
long s = M.ms(); long s = M.ms();
@ -130,7 +144,7 @@ public interface IrisAccess extends Hotloadable, DataProvider {
if (b != null && b.getLoadKey().equals(biome.getLoadKey())) { if (b != null && b.getLoadKey().equals(biome.getLoadKey())) {
found.lazySet(true); 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(); tries.getAndIncrement();
@ -167,6 +181,11 @@ public interface IrisAccess extends Hotloadable, DataProvider {
} }
default Location lookForRegion(IrisRegion reg, long timeout, Consumer<Integer> triesc) { 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); IrisComplex.cacheLock.set(true);
ChronoLatch cl = new ChronoLatch(3000, false); ChronoLatch cl = new ChronoLatch(3000, false);
long s = M.ms(); 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())) { if (b != null && b.getLoadKey() != null && b.getLoadKey().equals(reg.getLoadKey())) {
found.lazySet(true); 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(); tries.getAndIncrement();
@ -238,14 +257,6 @@ public interface IrisAccess extends Hotloadable, DataProvider {
return location.get(); 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() { default int getParallaxChunkCount() {
int v = 0; 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; 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. * 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) { 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); 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 i = x1; i < x2; i++) {
for (int j = y1; j < y2; j++) { 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) * @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) { 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); 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 * @param t the value to set
*/ */
default void set(int x1, int y1, int z1, int x2, int y2, int z2, T t) { 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 i = x1; i <= x2; i++) {
for (int j = y1; j <= y2; j++) { for (int j = y1; j <= y2; j++) {
for (int k = z1; k <= z2; k++) { for (int k = z1; k <= z2; k++) {
@ -1036,7 +1021,6 @@ public interface Hunk<T> {
* @param t the value * @param t the value
*/ */
default void set(int x, int y, int z, T t) { default void set(int x, int y, int z, T t) {
enforceBounds(x, y, z);
setRaw(x, y, z, t); setRaw(x, y, z, t);
} }
@ -1089,12 +1073,10 @@ public interface Hunk<T> {
* @return the value or null * @return the value or null
*/ */
default T get(int x, int y, int z) { default T get(int x, int y, int z) {
enforceBounds(x, y, z);
return getRaw(x, y, z); return getRaw(x, y, z);
} }
default T getOr(int x, int y, int z, T t) { default T getOr(int x, int y, int z, T t) {
enforceBounds(x, y, z);
T v = getRaw(x, y, z); T v = getRaw(x, y, z);
if (v == null) { if (v == null) {
@ -1161,8 +1143,6 @@ public interface Hunk<T> {
* @param invertY should the inserted hunk be inverted * @param invertY should the inserted hunk be inverted
*/ */
default void insert(int offX, int offY, int offZ, Hunk<T> hunk, boolean invertY) { 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 i = offX; i < offX + hunk.getWidth(); i++) {
for (int j = offY; j < offY + hunk.getHeight(); j++) { for (int j = offY; j < offY + hunk.getHeight(); j++) {
for (int k = offZ; k < offZ + hunk.getDepth(); k++) { 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 * @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) { 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 i = offX; i < offX + hunk.getWidth(); i++) {
for (int j = offY; j < offY + hunk.getHeight(); j++) { for (int j = offY; j < offY + hunk.getHeight(); j++) {
for (int k = offZ; k < offZ + hunk.getDepth(); k++) { 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.hunk.Hunk;
import com.volmit.iris.engine.object.tile.TileData; import com.volmit.iris.engine.object.tile.TileData;
import com.volmit.iris.engine.parallel.BurstExecutor; 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.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.function.Function2; import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.function.Function3; 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.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.oldnbt.ByteArrayTag; import com.volmit.iris.util.oldnbt.ByteArrayTag;
import com.volmit.iris.util.oldnbt.CompoundTag; import com.volmit.iris.util.oldnbt.CompoundTag;
import com.volmit.iris.util.oldnbt.Tag; import com.volmit.iris.util.oldnbt.Tag;
import io.papermc.lib.PaperLib;
import org.bukkit.block.TileState; import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -42,22 +40,20 @@ import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
public class HunkRegionSlice<T> { 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<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::newMappedHunkSynced, new TileDataHunkIOAdapter(), c, "tile"); 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::newMappedHunkSynced, new StringHunkIOAdapter(), c, t); 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::newMappedHunkSynced, new BooleanHunkIOAdapter(), 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 Function3<Integer, Integer, Integer, Hunk<T>> factory;
private final GridLock lock;
private final HunkIOAdapter<T> adapter; private final HunkIOAdapter<T> adapter;
private final CompoundTag compound; private final CompoundTag compound;
private final String key; private final String key;
private final KMap<ChunkPosition, Hunk<T>> loadedChunks; private final KMap<Position2, Hunk<T>> loadedChunks;
private final KMap<ChunkPosition, Long> lastUse; private final KMap<Position2, Long> lastUse;
private final KSet<ChunkPosition> save; private final KSet<Position2> save;
private final int height; private final int height;
public HunkRegionSlice(int height, Function3<Integer, Integer, Integer, Hunk<T>> factory, HunkIOAdapter<T> adapter, CompoundTag compound, String key) { 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.height = height;
this.loadedChunks = new KMap<>(); this.loadedChunks = new KMap<>();
this.factory = factory; this.factory = factory;
@ -73,18 +69,20 @@ public class HunkRegionSlice<T> {
if (loadedChunks.size() != lastUse.size()) { if (loadedChunks.size() != lastUse.size()) {
Iris.warn("Incorrect chunk use counts in " + key); Iris.warn("Incorrect chunk use counts in " + key);
for (ChunkPosition i : lastUse.k()) { for (Position2 i : lastUse.k()) {
if (!loadedChunks.containsKey(i)) { if (!loadedChunks.containsKey(i)) {
Iris.warn(" Missing LoadChunkKey " + i); Iris.warn(" Missing LoadChunkKey " + i);
} }
} }
} }
for (ChunkPosition i : lastUse.k()) { for (Position2 i : lastUse.k()) {
Long l = lastUse.get(i); Long l = lastUse.get(i);
if (l == null || M.ms() - l > t) { if (l == null || M.ms() - l > t) {
v++; 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() { public synchronized void save(MultiBurst burst) {
BurstExecutor e = MultiBurst.burst.burst();
try try {
{ for (Position2 i : save.copy()) {
for (ChunkPosition i : save.copy()) {
if (i == null) { if (i == null) {
continue; continue;
} }
e.queue(() -> save(i.getX(), i.getZ())); save(i.getX(), i.getZ());
try { try {
lock.withNasty(i.getX(), i.getZ(), () -> save.remove(i)); save.remove(i);
} catch (Throwable eer) { } catch (Throwable eer) {
Iris.reportError(eer); Iris.reportError(eer);
} }
} }
} catch (Throwable ee) {
e.complete();
}
catch(Throwable ee)
{
Iris.reportError(ee); Iris.reportError(ee);
} }
} }
@ -132,28 +123,23 @@ public class HunkRegionSlice<T> {
} }
public void delete(int x, int z) { 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 { public Hunk<T> read(int x, int z) throws IOException {
AtomicReference<IOException> e = new AtomicReference<>(); AtomicReference<IOException> e = new AtomicReference<>();
Hunk<T> xt = lock.withResult(x, z, () -> { Hunk<T> xt = null;
Tag t = compound.getValue().get(key(x, z));
if (!(t instanceof ByteArrayTag)) { Tag t = compound.getValue().get(key(x, z));
Iris.verbose("NOT BYTE ARRAY!");
return null;
}
if ((t instanceof ByteArrayTag)) {
try { try {
return adapter.read(factory, (ByteArrayTag) t); xt = adapter.read(factory, (ByteArrayTag) t);
} catch (IOException xe) { } catch (IOException xe) {
Iris.reportError(xe); Iris.reportError(xe);
e.set(xe); e.set(xe);
} }
}
return null;
});
if (xt != null) { if (xt != null) {
return xt; return xt;
@ -167,12 +153,12 @@ public class HunkRegionSlice<T> {
} }
public void write(Hunk<T> hunk, int x, int z) throws IOException { 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() { public synchronized int unloadAll() {
int v = 0; int v = 0;
for (ChunkPosition i : loadedChunks.k()) { for (Position2 i : loadedChunks.k()) {
unload(i.getX(), i.getZ()); unload(i.getX(), i.getZ());
v++; v++;
} }
@ -185,7 +171,7 @@ public class HunkRegionSlice<T> {
public void save(Hunk<T> region, int x, int z) { public void save(Hunk<T> region, int x, int z) {
try { try {
lock.withIO(x, z, () -> write(region, x, z)); write(region, x, z);
} catch (IOException e) { } catch (IOException e) {
Iris.reportError(e); Iris.reportError(e);
e.printStackTrace(); e.printStackTrace();
@ -193,84 +179,74 @@ public class HunkRegionSlice<T> {
} }
public boolean isLoaded(int x, int z) { 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) { public void save(int x, int z) {
lock.with(x, z, () -> { if (isLoaded(x, z)) {
if (isLoaded(x, z)) { save(get(x, z), x, z);
save(get(x, z), x, z); }
}
});
} }
public void unload(int x, int z) { public void unload(int x, int z) {
lock.with(x, z, () -> { Position2 key = new Position2(x, z);
ChunkPosition key = new ChunkPosition(x, z); if (isLoaded(x, z)) {
if (isLoaded(x, z)) { if (save.contains(key)) {
if (save.contains(key)) { save(x, z);
save(x, z); save.remove(key);
save.remove(key);
}
lastUse.remove(key);
loadedChunks.remove(key);
} }
});
lastUse.remove(key);
loadedChunks.remove(key);
}
} }
public Hunk<T> load(int x, int z) { public Hunk<T> load(int x, int z) {
return lock.withResult(x, z, () -> { if (isLoaded(x, z)) {
if (isLoaded(x, z)) { return loadedChunks.get(new Position2(x, z));
return loadedChunks.get(new ChunkPosition(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)) { loadedChunks.put(new Position2(x, z), v);
try {
v = read(x, z);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
if (v == null) { return v;
v = factory.apply(16, height, 16);
}
loadedChunks.put(new ChunkPosition(x, z), v);
return v;
});
} }
public Hunk<T> get(int x, int z) { public Hunk<T> get(int x, int z) {
return lock.withResult(x, z, () -> { Position2 key = new Position2(x, z);
ChunkPosition key = new ChunkPosition(x, z);
Hunk<T> c = loadedChunks.get(key); Hunk<T> c = loadedChunks.get(key);
if (c == null) { if (c == null) {
c = load(x, z); 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) { 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) { public Hunk<T> getRW(int x, int z) {
return lock.withResult(x, z, () -> { save.add(new Position2(x, z));
save.add(new ChunkPosition(x, z)); return get(x, z);
return get(x, z);
});
} }
private String key(int x, int z) { private String key(int x, int z) {

View File

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