mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
Merge remote-tracking branch 'upstream/master' into DecreeCommands
This commit is contained in:
commit
2dd6db352f
25
.github/workflows/gradlebuild.yml
vendored
Normal file
25
.github/workflows/gradlebuild.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Gradle Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: set up JDK 16
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '16'
|
||||
distribution: 'adopt'
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
@ -32,7 +32,7 @@ plugins {
|
||||
}
|
||||
|
||||
group 'com.volmit.iris'
|
||||
version '1.7.4'
|
||||
version '1.7.8'
|
||||
def apiVersion = '1.17'
|
||||
def name = getRootProject().getName() // See settings.gradle
|
||||
def main = 'com.volmit.iris.Iris'
|
||||
@ -187,6 +187,7 @@ dependencies {
|
||||
implementation 'net.kyori:adventure-api:4.8.1'
|
||||
|
||||
// Dynamically Loaded
|
||||
implementation 'io.timeandspace:smoothie-map:2.0.2'
|
||||
implementation 'it.unimi.dsi:fastutil:8.5.4'
|
||||
implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
|
||||
implementation 'org.zeroturnaround:zt-zip:1.14'
|
||||
@ -195,4 +196,5 @@ dependencies {
|
||||
implementation 'com.google.guava:guava:30.1.1-jre'
|
||||
implementation 'bsf:bsf:2.4.0'
|
||||
implementation 'rhino:js:1.7R2'
|
||||
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.3'
|
||||
}
|
||||
|
@ -17,7 +17,5 @@ libraries:
|
||||
commands:
|
||||
iris:
|
||||
aliases: [ ir, irs ]
|
||||
irisd:
|
||||
aliases: [ ird, irsd ]
|
||||
api-version: ${apiversion}
|
||||
hotload-dependencies: false
|
@ -27,11 +27,11 @@ import com.volmit.iris.core.link.MultiverseCoreLink;
|
||||
import com.volmit.iris.core.link.MythicMobsLink;
|
||||
import com.volmit.iris.core.link.OraxenLink;
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.project.IrisProject;
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiomeCustom;
|
||||
import com.volmit.iris.engine.object.block.IrisBlockData;
|
||||
import com.volmit.iris.engine.object.common.IrisWorld;
|
||||
import com.volmit.iris.engine.object.compat.IrisCompat;
|
||||
import com.volmit.iris.engine.object.dimensional.IrisDimension;
|
||||
@ -116,12 +116,10 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
sender.setTag(getTag());
|
||||
instance = this;
|
||||
compat = IrisCompat.configured(getDataFile("compat.json"));
|
||||
|
||||
linkMultiverseCore = new MultiverseCoreLink();
|
||||
linkOraxen = new OraxenLink();
|
||||
linkMythicMobs = new MythicMobsLink();
|
||||
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
||||
|
||||
services.values().forEach(IrisService::onEnable);
|
||||
services.values().forEach(this::registerListener);
|
||||
}
|
||||
@ -165,6 +163,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
HandlerList.unregisterAll((Plugin) this);
|
||||
postShutdown.forEach(Runnable::run);
|
||||
services.clear();
|
||||
MultiBurst.burst.close();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@ -604,14 +603,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
|
||||
public static void verbose(String string) {
|
||||
try {
|
||||
if (IrisSettings.get().getGeneral().isVerbose()) {
|
||||
msg(C.GRAY + string);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
msg(C.GRAY + string);
|
||||
Iris.reportError(e);
|
||||
}
|
||||
debug(string);
|
||||
}
|
||||
|
||||
public static void success(String string) {
|
||||
@ -683,7 +675,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
|
||||
public boolean isMCA() {
|
||||
return !IrisSettings.get().getGenerator().isDisableMCA();
|
||||
return IrisSettings.get().getGenerator().isHeadlessPregeneration();
|
||||
}
|
||||
|
||||
public static void reportErrorChunk(int x, int z, Throwable e, String extra) {
|
||||
@ -704,7 +696,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void reportError(Throwable e) {
|
||||
public static void reportError(Throwable e) {
|
||||
if (IrisSettings.get().getGeneral().isDebug()) {
|
||||
String n = e.getClass().getCanonicalName() + "-" + e.getStackTrace()[0].getClassName() + "-" + e.getStackTrace()[0].getLineNumber();
|
||||
|
||||
|
@ -20,6 +20,7 @@ package com.volmit.iris.core;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.object.basic.IrisRange;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONException;
|
||||
@ -56,6 +57,11 @@ public class IrisSettings {
|
||||
return getParallax().getParallaxRegionEvictionMS();
|
||||
}
|
||||
|
||||
public static int getPriority(int c)
|
||||
{
|
||||
return Math.max(Math.min(c, Thread.MAX_PRIORITY), Thread.MIN_PRIORITY);
|
||||
}
|
||||
|
||||
public static int getThreadCount(int c) {
|
||||
if (c < 2 && c >= 0) {
|
||||
return 2;
|
||||
@ -82,13 +88,7 @@ public class IrisSettings {
|
||||
|
||||
@Data
|
||||
public static class IrisSettingsConcurrency {
|
||||
public int engineThreadCount = -1;
|
||||
public int engineThreadPriority = 6;
|
||||
public int pregenThreadCount = -1;
|
||||
public int pregenThreadPriority = 8;
|
||||
public int miscThreadCount = -4;
|
||||
public int miscThreadPriority = 3;
|
||||
public boolean unstableLockingHeuristics = false;
|
||||
public int parallelism = -1;
|
||||
}
|
||||
|
||||
@Data
|
||||
@ -101,7 +101,6 @@ public class IrisSettings {
|
||||
public static class IrisSettingsGeneral {
|
||||
public boolean commandSounds = true;
|
||||
public boolean debug = false;
|
||||
public boolean verbose = false;
|
||||
public boolean ignoreWorldEdit = false;
|
||||
public boolean disableNMS = false;
|
||||
public boolean keepProductionOnReload = false;
|
||||
@ -115,7 +114,6 @@ public class IrisSettings {
|
||||
|
||||
@Data
|
||||
public static class IrisSettingsGUI {
|
||||
|
||||
public boolean useServerLaunchedGuis = true;
|
||||
public boolean maximumPregenGuiFPS = false;
|
||||
public boolean localPregenGui = true;
|
||||
@ -124,10 +122,8 @@ public class IrisSettings {
|
||||
@Data
|
||||
public static class IrisSettingsGenerator {
|
||||
public String defaultWorldType = "overworld";
|
||||
public boolean disableMCA = false;
|
||||
public boolean headlessPregeneration = false;
|
||||
public boolean systemEffects = true;
|
||||
public boolean systemEntitySpawnOverrides = true;
|
||||
public boolean systemEntityInitialSpawns = true;
|
||||
public int maxBiomeChildDepth = 4;
|
||||
public boolean preventLeafDecay = true;
|
||||
}
|
||||
@ -162,65 +158,14 @@ public class IrisSettings {
|
||||
try {
|
||||
String ss = IO.readAll(s);
|
||||
settings = new Gson().fromJson(ss, IrisSettings.class);
|
||||
|
||||
J.a(() ->
|
||||
{
|
||||
try {
|
||||
JSONObject j = new JSONObject(ss);
|
||||
boolean u = false;
|
||||
for (String i : def.keySet()) {
|
||||
if (!j.has(i)) {
|
||||
u = true;
|
||||
j.put(i, def.get(i));
|
||||
Iris.warn("Adding new config key: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (String i : new KSet<>(j.keySet())) {
|
||||
if (!def.has(i)) {
|
||||
u = true;
|
||||
j.remove(i);
|
||||
Iris.warn("Removing unused config key: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
if (u) {
|
||||
try {
|
||||
IO.writeAll(s, j.toString(4));
|
||||
Iris.info("Updated Configuration Files");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ee) {
|
||||
Iris.reportError(ee);
|
||||
Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage());
|
||||
Iris.warn("Attempting to fix configuration while retaining valid in-memory settings...");
|
||||
|
||||
try {
|
||||
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
|
||||
Iris.info("Configuration Fixed!");
|
||||
} catch (IOException e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
Iris.error("ERROR! CONFIGURATION IMPOSSIBLE TO READ! Using an unmodifiable configuration from memory. Please delete the settings.json at some point to try to restore configurability!");
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Throwable ee) {
|
||||
Iris.reportError(ee);
|
||||
Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage());
|
||||
Iris.warn("Attempting to fix configuration while retaining valid in-memory settings...");
|
||||
|
||||
try {
|
||||
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
|
||||
Iris.info("Configuration Fixed!");
|
||||
} catch (IOException e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
Iris.error("ERROR! CONFIGURATION IMPOSSIBLE TO READ! Using an unmodifiable configuration from memory. Please delete the settings.json at some point to try to restore configurability!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,9 @@ public class CommandIrisStudio extends MortarCommand {
|
||||
@Command
|
||||
private CommandIrisStudioExecute execute;
|
||||
|
||||
@Command
|
||||
private CommandIrisStudioCompile compile;
|
||||
|
||||
@Command
|
||||
private CommandIrisStudioOpen open;
|
||||
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.studio;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.project.IrisProject;
|
||||
import com.volmit.iris.core.service.ConversionSVC;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.plugin.MortarCommand;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.jobs.Job;
|
||||
import com.volmit.iris.util.scheduling.jobs.JobCollection;
|
||||
|
||||
public class CommandIrisStudioCompile extends MortarCommand {
|
||||
public CommandIrisStudioCompile() {
|
||||
super("compile");
|
||||
requiresPermission(Iris.perm.studio);
|
||||
setDescription("Compiles a pack for speed");
|
||||
setCategory("Studio");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabOptions(VolmitSender sender, String[] args, KList<String> list) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(VolmitSender sender, String[] args) {
|
||||
if (!IrisSettings.get().isStudio()) {
|
||||
sender.sendMessage("To use Iris Studio, please enable studio in Iris/settings.json");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(args.length == 0)
|
||||
{
|
||||
sender.sendMessage(getArgsUsage());
|
||||
return true;
|
||||
}
|
||||
|
||||
IrisProject project = new IrisProject(Iris.instance.getDataFolder(StudioSVC.WORKSPACE_NAME, args[0]));
|
||||
project.compile(sender);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArgsUsage() {
|
||||
return "[project]";
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ public class CommandIrisStudioUpdate extends MortarCommand {
|
||||
IrisData data = IrisData.get(Iris.service(StudioSVC.class).getWorkspaceFolder(args[0]));
|
||||
int t = data.getObjectLoader().getPossibleKeys().length;
|
||||
ChronoLatch cl = new ChronoLatch(250, false);
|
||||
MultiBurst bx = new MultiBurst("Object Rewriter", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors());
|
||||
MultiBurst bx = MultiBurst.burst;
|
||||
BurstExecutor b = bx.burst();
|
||||
int g = 0;
|
||||
for (String f : data.getObjectLoader().getPossibleKeys()) {
|
||||
@ -102,7 +102,6 @@ public class CommandIrisStudioUpdate extends MortarCommand {
|
||||
int finalG = g;
|
||||
J.a(() -> {
|
||||
b.complete();
|
||||
bx.shutdownNow();
|
||||
sender.sendMessage("Done! Rewrote " + Form.f(finalG) + " Objects!");
|
||||
});
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
|
||||
@ -133,7 +134,7 @@ public class DecStudio implements DecreeExecutor {
|
||||
KList<Job> jobs = new KList<>();
|
||||
KList<File> files = new KList<File>();
|
||||
files(Iris.instance.getDataFolder("packs", project.getLoadKey()), files);
|
||||
MultiBurst burst = new MultiBurst("Cleaner", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors() * 2);
|
||||
MultiBurst burst = MultiBurst.burst;
|
||||
|
||||
jobs.add(new SingleJob("Updating Workspace", () -> {
|
||||
if (!new IrisProject(Iris.service(StudioSVC.class).getWorkspaceFolder(project.getLoadKey())).updateWorkspace()) {
|
||||
@ -208,7 +209,7 @@ public class DecStudio implements DecreeExecutor {
|
||||
|
||||
IrisData data = IrisData.get(Iris.service(StudioSVC.class).getWorkspaceFolder(project.getLoadKey()));
|
||||
for (String f : data.getObjectLoader().getPossibleKeys()) {
|
||||
CompletableFuture<?> gg = burst.complete(() -> {
|
||||
Future<?> gg = burst.complete(() -> {
|
||||
File ff = data.getObjectLoader().findFile(f);
|
||||
IrisObject oo = new IrisObject(0, 0, 0);
|
||||
try {
|
||||
@ -237,8 +238,6 @@ public class DecStudio implements DecreeExecutor {
|
||||
jobs.add(q);
|
||||
}
|
||||
|
||||
jobs.add(new SingleJob("Finishing Up", burst::shutdownNow));
|
||||
|
||||
new JobCollection("Cleaning", jobs).execute(sender());
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List
|
||||
static double ascale = 10;
|
||||
CNG cng = NoiseStyle.STATIC.create(new RNG(RNG.r.nextLong()));
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
MultiBurst gx = new MultiBurst("Iris Noise Renderer", Thread.MAX_PRIORITY, Runtime.getRuntime().availableProcessors());
|
||||
MultiBurst gx = MultiBurst.burst;
|
||||
ReentrantLock l = new ReentrantLock();
|
||||
BufferedImage img;
|
||||
int w = 0;
|
||||
@ -213,7 +213,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List
|
||||
});
|
||||
}
|
||||
|
||||
e.complete(1000);
|
||||
e.complete();
|
||||
gg.drawImage(img, 0, 0, getParent().getWidth() * accuracy, getParent().getHeight() * accuracy, (img, infoflags, x, y, width, height) -> true);
|
||||
}
|
||||
|
||||
@ -299,7 +299,6 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List
|
||||
frame.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
|
||||
nv.gx.shutdownLater();
|
||||
Iris.instance.unregisterListener(nv);
|
||||
}
|
||||
});
|
||||
|
@ -29,11 +29,12 @@ import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
private final World world;
|
||||
private final MultiBurst burst;
|
||||
private final KList<CompletableFuture<?>> future;
|
||||
private final KList<Future<?>> future;
|
||||
|
||||
public AsyncPregenMethod(World world, int threads) {
|
||||
if (!PaperLib.isPaper()) {
|
||||
@ -41,7 +42,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
|
||||
this.world = world;
|
||||
burst = new MultiBurst("Iris Async Pregenerator", IrisSettings.get().getConcurrency().getPregenThreadPriority(), threads);
|
||||
burst = MultiBurst.burst;
|
||||
future = new KList<>(1024);
|
||||
}
|
||||
|
||||
@ -69,7 +70,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
|
||||
private void waitForChunks() {
|
||||
for (CompletableFuture<?> i : future.copy()) {
|
||||
for (Future<?> i : future.copy()) {
|
||||
try {
|
||||
i.get();
|
||||
future.remove(i);
|
||||
@ -92,7 +93,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
@Override
|
||||
public void close() {
|
||||
waitForChunks();
|
||||
burst.shutdownAndAwait();
|
||||
unloadAndSaveAllChunks();
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
|
||||
@Override
|
||||
public void generateChunk(int x, int z, PregenListener listener) {
|
||||
if (future.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) {
|
||||
if (future.size() > IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())) { // TODO: FIX
|
||||
waitForChunks();
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class HybridPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
|
||||
private boolean supportsHeadless(World world) {
|
||||
return IrisToolbelt.access(world) != null && !IrisSettings.get().getGenerator().isDisableMCA();
|
||||
return IrisToolbelt.access(world) != null && IrisSettings.get().getGenerator().isHeadlessPregeneration();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,7 +95,7 @@ public class MedievalPregenMethod implements PregeneratorMethod {
|
||||
|
||||
@Override
|
||||
public void generateChunk(int x, int z, PregenListener listener) {
|
||||
if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) {
|
||||
if (futures.size() > IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())) {
|
||||
waitForChunks();
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import com.google.gson.Gson;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.core.project.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.project.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
@ -30,6 +31,7 @@ import com.volmit.iris.engine.object.dimensional.IrisDimension;
|
||||
import com.volmit.iris.engine.object.entity.IrisEntity;
|
||||
import com.volmit.iris.engine.object.loot.IrisLootTable;
|
||||
import com.volmit.iris.engine.object.noise.IrisGenerator;
|
||||
import com.volmit.iris.engine.object.objects.IrisObject;
|
||||
import com.volmit.iris.engine.object.objects.IrisObjectPlacement;
|
||||
import com.volmit.iris.engine.object.regional.IrisRegion;
|
||||
import com.volmit.iris.engine.object.spawners.IrisSpawner;
|
||||
@ -37,7 +39,9 @@ import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.exceptions.IrisException;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
@ -48,6 +52,10 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.O;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.scheduling.jobs.Job;
|
||||
import com.volmit.iris.util.scheduling.jobs.JobCollection;
|
||||
import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
|
||||
import com.volmit.iris.util.scheduling.jobs.QueueJob;
|
||||
import lombok.Data;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
@ -443,7 +451,6 @@ public class IrisProject {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static int clean(VolmitSender s, File clean) {
|
||||
int c = 0;
|
||||
if (clean.isDirectory()) {
|
||||
@ -499,4 +506,153 @@ public class IrisProject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void compile(VolmitSender sender) {
|
||||
IrisData data = IrisData.get(getPath());
|
||||
KList<Job> jobs = new KList<Job>();
|
||||
KList<File> files = new KList<File>();
|
||||
KList<File> objects = new KList<File>();
|
||||
files(getPath(), files);
|
||||
filesObjects(getPath(), objects);
|
||||
|
||||
jobs.add(new ParallelQueueJob<File>() {
|
||||
@Override
|
||||
public void execute(File f) {
|
||||
try {
|
||||
IrisObject o = new IrisObject(0,0,0);
|
||||
o.read(f);
|
||||
|
||||
if(o.getBlocks().isEmpty())
|
||||
{
|
||||
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
|
||||
"<yellow>" + f.getPath() +
|
||||
"'><red>- IOB " + f.getName() + " has 0 blocks!");
|
||||
}
|
||||
|
||||
if(o.getW() == 0 || o.getH() == 0 || o.getD() == 0)
|
||||
{
|
||||
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
|
||||
"<yellow>" + f.getPath() + "\n<red>The width height or depth has a zero in it (bad format)" +
|
||||
"'><red>- IOB " + f.getName() + " is not 3D!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IOB";
|
||||
}
|
||||
}.queue(objects));
|
||||
|
||||
jobs.add(new ParallelQueueJob<File>() {
|
||||
@Override
|
||||
public void execute(File f) {
|
||||
try {
|
||||
JSONObject p = new JSONObject(IO.readAll(f));
|
||||
fixBlocks(p);
|
||||
scanForErrors(data, f, p, sender);
|
||||
IO.writeAll(f, p.toString(4));
|
||||
|
||||
} catch (Throwable e) {
|
||||
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
|
||||
"<yellow>" + f.getPath() +
|
||||
"\n<red>" +e.getMessage() +
|
||||
"'><red>- JSON Error " + f.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "JSON";
|
||||
}
|
||||
}.queue(files));
|
||||
|
||||
new JobCollection("Compile", jobs).execute(sender);
|
||||
}
|
||||
|
||||
private void scanForErrors(IrisData data, File f, JSONObject p, VolmitSender sender) {
|
||||
String key = data.toLoadKey(f);
|
||||
ResourceLoader<?> loader = data.getTypedLoaderFor(f);
|
||||
|
||||
if(loader == null)
|
||||
{
|
||||
sender.sendMessageBasic("Can't find loader for " + f.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
IrisRegistrant load = loader.load(key);
|
||||
compare(load.getClass(), p, sender, new KList<>());
|
||||
load.scanForErrors(p, sender);
|
||||
}
|
||||
|
||||
public void compare(Class<?> c, JSONObject j, VolmitSender sender, KList<String> path)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object o = c.getClass().getConstructor().newInstance();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void files(File clean, KList<File> files) {
|
||||
if (clean.isDirectory()) {
|
||||
for (File i : clean.listFiles()) {
|
||||
files(i, files);
|
||||
}
|
||||
} else if (clean.getName().endsWith(".json")) {
|
||||
try {
|
||||
files.add(clean);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void filesObjects(File clean, KList<File> files) {
|
||||
if (clean.isDirectory()) {
|
||||
for (File i : clean.listFiles()) {
|
||||
filesObjects(i, files);
|
||||
}
|
||||
} else if (clean.getName().endsWith(".iob")) {
|
||||
try {
|
||||
files.add(clean);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fixBlocks(JSONObject obj) {
|
||||
for (String i : obj.keySet()) {
|
||||
Object o = obj.get(i);
|
||||
|
||||
if (i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) {
|
||||
obj.put(i, "minecraft:" + o);
|
||||
}
|
||||
|
||||
if (o instanceof JSONObject) {
|
||||
fixBlocks((JSONObject) o);
|
||||
} else if (o instanceof JSONArray) {
|
||||
fixBlocks((JSONArray) o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fixBlocks(JSONArray obj) {
|
||||
for (int i = 0; i < obj.length(); i++) {
|
||||
Object o = obj.get(i);
|
||||
|
||||
if (o instanceof JSONObject) {
|
||||
fixBlocks((JSONObject) o);
|
||||
} else if (o instanceof JSONArray) {
|
||||
fixBlocks((JSONArray) o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
@ -536,8 +537,8 @@ public class SchemaBuilder {
|
||||
d.add("* Default Value is " + value);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
} catch (Throwable ignored) {
|
||||
|
||||
}
|
||||
|
||||
description.forEach((g) -> d.add(g.trim()));
|
||||
|
@ -19,9 +19,11 @@
|
||||
package com.volmit.iris.core.project.loader;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.block.IrisBlockData;
|
||||
import com.volmit.iris.engine.object.cave.IrisCave;
|
||||
import com.volmit.iris.engine.object.common.IrisScript;
|
||||
import com.volmit.iris.engine.object.dimensional.IrisDimension;
|
||||
import com.volmit.iris.engine.object.entity.IrisEntity;
|
||||
@ -42,8 +44,9 @@ import com.volmit.iris.util.math.RNG;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
public class IrisData {
|
||||
@ -63,6 +66,7 @@ public class IrisData {
|
||||
private ResourceLoader<IrisExpression> expressionLoader;
|
||||
private ResourceLoader<IrisObject> objectLoader;
|
||||
private ResourceLoader<IrisScript> scriptLoader;
|
||||
private ResourceLoader<IrisCave> caveLoader;
|
||||
private KMap<Class<? extends IrisRegistrant>, ResourceLoader<? extends IrisRegistrant>> loaders = new KMap<>();
|
||||
private boolean closed;
|
||||
private final File dataFolder;
|
||||
@ -87,6 +91,23 @@ public class IrisData {
|
||||
dataLoaders.v().forEach(IrisData::cleanupEngine);
|
||||
}
|
||||
|
||||
public ResourceLoader<?> getTypedLoaderFor(File f) {
|
||||
String[] k = f.getPath().split("\\Q"+File.separator+"\\E");
|
||||
|
||||
for(String i : k)
|
||||
{
|
||||
for(ResourceLoader<?> j : loaders.values())
|
||||
{
|
||||
if(j.getFolderName().equals(i))
|
||||
{
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanupEngine()
|
||||
{
|
||||
if(engine != null && engine.isClosed())
|
||||
@ -199,6 +220,7 @@ public class IrisData {
|
||||
this.jigsawStructureLoader = registerLoader(IrisJigsawStructure.class);
|
||||
this.jigsawPieceLoader = registerLoader(IrisJigsawPiece.class);
|
||||
this.generatorLoader = registerLoader(IrisGenerator.class);
|
||||
this.caveLoader = registerLoader(IrisCave.class);
|
||||
this.blockLoader = registerLoader(IrisBlockData.class);
|
||||
this.expressionLoader = registerLoader(IrisExpression.class);
|
||||
this.objectLoader = registerLoader(IrisObject.class);
|
||||
@ -273,6 +295,10 @@ public class IrisData {
|
||||
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false));
|
||||
}
|
||||
|
||||
public static IrisCave loadAnyCave(String key) {
|
||||
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false));
|
||||
}
|
||||
|
||||
public static IrisDimension loadAnyDimension(String key) {
|
||||
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false));
|
||||
}
|
||||
@ -304,4 +330,39 @@ public class IrisData {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toLoadKey(File f) {
|
||||
if(f.getPath().startsWith(getDataFolder().getPath()))
|
||||
{
|
||||
String[] full = f.getPath().split("\\Q" + File.separator + "\\E");
|
||||
String[] df = getDataFolder().getPath().split("\\Q" + File.separator + "\\E");
|
||||
String g = "";
|
||||
boolean m = true;
|
||||
for(int i = 0; i < full.length; i++)
|
||||
{
|
||||
if(i >= df.length)
|
||||
{
|
||||
if(m)
|
||||
{
|
||||
m = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
g += "/" + full[i];
|
||||
}
|
||||
}
|
||||
|
||||
String ff = g.toString().substring(1).split("\\Q.\\E")[0];
|
||||
return ff;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Iris.error("Forign file from loader " + f.getPath() + " (loader realm: " + getDataFolder().getPath() + ")");
|
||||
}
|
||||
|
||||
Iris.error("Failed to load " + f.getPath() + " (loader realm: " + getDataFolder().getPath() + ")");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -24,6 +24,8 @@ import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.RegistryListResource;
|
||||
import com.volmit.iris.engine.object.common.IrisScript;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.Data;
|
||||
|
||||
import java.awt.*;
|
||||
@ -55,4 +57,6 @@ public abstract class IrisRegistrant {
|
||||
|
||||
return getLoadFile();
|
||||
}
|
||||
|
||||
public abstract void scanForErrors(JSONObject p, VolmitSender sender);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import com.volmit.iris.util.plugin.IrisService;
|
||||
public class CommandSVC implements IrisService, DecreeSystem {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Iris.instance.getCommand("irisd").setExecutor(this);
|
||||
// TODO Iris.instance.getCommand("irisd").setExecutor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +31,6 @@ import java.util.concurrent.ExecutorService;
|
||||
public class PreservationSVC implements IrisService
|
||||
{
|
||||
private KList<Thread> threads = new KList<>();
|
||||
private KList<MultiBurst> bursts = new KList<>();
|
||||
private KList<ExecutorService> services = new KList<>();
|
||||
private Looper dereferencer;
|
||||
|
||||
@ -42,7 +41,7 @@ public class PreservationSVC implements IrisService
|
||||
|
||||
public void register(MultiBurst burst)
|
||||
{
|
||||
bursts.add(burst);
|
||||
|
||||
}
|
||||
|
||||
public void register(ExecutorService service)
|
||||
@ -94,20 +93,6 @@ public class PreservationSVC implements IrisService
|
||||
}
|
||||
}
|
||||
|
||||
for(MultiBurst i : bursts)
|
||||
{
|
||||
try
|
||||
{
|
||||
i.shutdownNow();
|
||||
Iris.info("Shutdown Multiburst " + i);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(ExecutorService i : services)
|
||||
{
|
||||
try
|
||||
|
@ -82,18 +82,6 @@ public class StudioSVC implements IrisService {
|
||||
IrisToolbelt.evacuate(i);
|
||||
IrisToolbelt.access(i).close();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if(!IrisSettings.get().getGeneral().isKeepProductionOnReload())
|
||||
{
|
||||
IrisToolbelt.evacuate(i);
|
||||
IrisToolbelt.access(i).close();
|
||||
Iris.error("You cannot reload Iris while production worlds are active!");
|
||||
Iris.error("To prevent corrupted chunks, Iris is shutting the server down now!");
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ public class IrisToolbelt {
|
||||
return pregenerate(task, new HeadlessPregenMethod(((HeadlessGenerator) gen).getWorld(), (HeadlessGenerator) gen));
|
||||
}
|
||||
|
||||
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())));
|
||||
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,7 +144,7 @@ public class IrisToolbelt {
|
||||
return pregenerate(task, access(world));
|
||||
}
|
||||
|
||||
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())));
|
||||
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,6 @@ import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.common.CaveResult;
|
||||
import com.volmit.iris.engine.object.decoration.IrisDecorationPart;
|
||||
import com.volmit.iris.engine.object.decoration.IrisDecorator;
|
||||
import com.volmit.iris.engine.object.dimensional.IrisTerrainMode;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.engine.object.noise.IrisGenerator;
|
||||
import com.volmit.iris.engine.object.noise.IrisInterpolator;
|
||||
@ -65,9 +64,6 @@ public class IrisComplex implements DataProvider {
|
||||
private ProceduralStream<Double> regionStyleStream;
|
||||
private ProceduralStream<Double> regionIdentityStream;
|
||||
private ProceduralStream<UUID> regionIDStream;
|
||||
private ProceduralStream<Boolean> islandStream;
|
||||
private ProceduralStream<Double> islandHeightStream;
|
||||
private ProceduralStream<Double> islandDepthStream;
|
||||
private ProceduralStream<InferredType> bridgeStream;
|
||||
private ProceduralStream<IrisBiome> landBiomeStream;
|
||||
private ProceduralStream<IrisBiome> caveBiomeStream;
|
||||
@ -86,8 +82,6 @@ public class IrisComplex implements DataProvider {
|
||||
private ProceduralStream<Double> heightFluidStream;
|
||||
private ProceduralStream<Integer> trueHeightStream;
|
||||
private ProceduralStream<Double> slopeStream;
|
||||
private ProceduralStream<Integer> islandTopStream;
|
||||
private ProceduralStream<Integer> islandBottomStream;
|
||||
private ProceduralStream<Integer> topSurfaceStream;
|
||||
private ProceduralStream<RNG> rngStream;
|
||||
private ProceduralStream<RNG> chunkRngStream;
|
||||
@ -167,11 +161,6 @@ public class IrisComplex implements DataProvider {
|
||||
: regionStyleStream
|
||||
.selectRarity(engine.getDimension().getRegions(), (i) -> data.getRegionLoader().load(i))
|
||||
.convertCached((s) -> data.getRegionLoader().load(s)).cache2D(cacheSize);
|
||||
islandStream = regionStyleStream
|
||||
.seededChance(rng.nextParallelRNG(29349), 23968888888L,
|
||||
1D / engine.getDimension().getIslandMode().getIslandChance());
|
||||
islandHeightStream = regionIdentityStream.style(rng.nextParallelRNG(330466), engine.getDimension().getIslandMode().getHeight(), data);
|
||||
islandDepthStream = engine.getDimension().getIslandMode().getIslandDepth().stream(rng.nextParallelRNG(-39578888), data);
|
||||
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i), String.valueOf(i * 38445).hashCode() * 3245556666L));
|
||||
caveBiomeStream = regionStream.convert((r)
|
||||
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
|
||||
@ -334,13 +323,11 @@ public class IrisComplex implements DataProvider {
|
||||
int heightf = (int) Math.round(getHeightStream().get(rx, rz));
|
||||
int m = heightf;
|
||||
|
||||
if (engine.getDimension().isCarving() && engine.getDimension().getTerrainMode().equals(IrisTerrainMode.NORMAL)) {
|
||||
if (engine.getDimension().isCarved(getData(), rx, m, rz, ((IrisTerrainNormalActuator) engine.getTerrainActuator()).getRng(), heightf)) {
|
||||
m--;
|
||||
if (engine.getDimension().isCarved(getData(), rx, m, rz, ((IrisTerrainNormalActuator) engine.getTerrainActuator()).getRng(), heightf)) {
|
||||
m--;
|
||||
|
||||
while (engine.getDimension().isCarved(getData(), rx, m, rz, ((IrisTerrainNormalActuator) engine.getTerrainActuator()).getRng(), heightf)) {
|
||||
m--;
|
||||
}
|
||||
while (engine.getDimension().isCarved(getData(), rx, m, rz, ((IrisTerrainNormalActuator) engine.getTerrainActuator()).getRng(), heightf)) {
|
||||
m--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,27 +354,9 @@ public class IrisComplex implements DataProvider {
|
||||
d.hashCode());
|
||||
})
|
||||
.cache2D(cacheSize);
|
||||
islandTopStream = islandStream.convertAware2D((i, x, z) ->
|
||||
i ? heightStream.round()
|
||||
.subtract(fluidHeight)
|
||||
.add((xx, zz) -> getIslandHeight(xx.intValue(), zz.intValue(), engine.getDimension()
|
||||
.getIslandMode().getIslandEdgeInterpolator()))
|
||||
.get(x, z) : 0);
|
||||
islandBottomStream = islandStream.convertAware2D((i, x, z) ->
|
||||
i ? islandHeightStream.subtract(islandDepthStream).round().get(x, z) : 0);
|
||||
//@done
|
||||
}
|
||||
|
||||
private double getIslandHeight(int x, int z, IrisInterpolator interp) {
|
||||
return interp.interpolate(x, z, (xx, zz) -> {
|
||||
if (getIslandStream().get(xx, zz)) {
|
||||
return getIslandHeightStream().get(xx, zz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
private IrisRegion findRegion(IrisBiome focus, Engine engine) {
|
||||
for (IrisRegion i : engine.getDimension().getAllRegions(engine)) {
|
||||
if (i.getAllBiomeIds().contains(focus.getLoadKey())) {
|
||||
|
@ -26,7 +26,6 @@ import com.volmit.iris.core.events.IrisEngineHotloadEvent;
|
||||
import com.volmit.iris.core.service.PreservationSVC;
|
||||
import com.volmit.iris.engine.actuator.IrisBiomeActuator;
|
||||
import com.volmit.iris.engine.actuator.IrisDecorantActuator;
|
||||
import com.volmit.iris.engine.actuator.IrisTerrainIslandActuator;
|
||||
import com.volmit.iris.engine.actuator.IrisTerrainNormalActuator;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.*;
|
||||
@ -49,6 +48,7 @@ import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
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.PrecisionStopwatch;
|
||||
@ -96,8 +96,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
private double maxBiomeLayerDensity;
|
||||
private double maxBiomeDecoratorDensity;
|
||||
private IrisComplex complex;
|
||||
private EngineActuator<BlockData> terrainNormalActuator;
|
||||
private EngineActuator<BlockData> terrainIslandActuator;
|
||||
private EngineActuator<BlockData> terrainActuator;
|
||||
private EngineActuator<BlockData> decorantActuator;
|
||||
private EngineActuator<Biome> biomeActuator;
|
||||
private EngineModifier<BlockData> depositModifier;
|
||||
@ -132,6 +131,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
closed = false;
|
||||
art = J.ar(this::tickRandomPlayer, 0);
|
||||
setupEngine();
|
||||
Iris.debug("Engine Initialized " + getCacheID());
|
||||
}
|
||||
|
||||
private void tickRandomPlayer() {
|
||||
@ -145,8 +145,7 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
worldManager.close();
|
||||
complex.close();
|
||||
execution.close();
|
||||
terrainNormalActuator.close();
|
||||
terrainIslandActuator.close();
|
||||
terrainActuator.close();
|
||||
decorantActuator.close();
|
||||
biomeActuator.close();
|
||||
depositModifier.close();
|
||||
@ -158,20 +157,31 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
|
||||
private void setupEngine()
|
||||
{
|
||||
cacheId = RNG.r.nextInt();
|
||||
worldManager = new IrisWorldManager(this);
|
||||
complex = new IrisComplex(this);
|
||||
execution = new IrisExecutionEnvironment(this);
|
||||
terrainNormalActuator = new IrisTerrainNormalActuator(this);
|
||||
terrainIslandActuator = new IrisTerrainIslandActuator(this);
|
||||
decorantActuator = new IrisDecorantActuator(this);
|
||||
biomeActuator = new IrisBiomeActuator(this);
|
||||
depositModifier = new IrisDepositModifier(this);
|
||||
ravineModifier = new IrisRavineModifier(this);
|
||||
caveModifier = new IrisCaveModifier(this);
|
||||
postModifier = new IrisPostModifier(this);
|
||||
effects = new IrisEngineEffects(this);
|
||||
J.a(this::computeBiomeMaxes);
|
||||
try
|
||||
{
|
||||
Iris.debug("Setup Engine " + getCacheID());
|
||||
cacheId = RNG.r.nextInt();
|
||||
worldManager = new IrisWorldManager(this);
|
||||
complex = new IrisComplex(this);
|
||||
execution = new IrisExecutionEnvironment(this);
|
||||
terrainActuator = new IrisTerrainNormalActuator(this);
|
||||
decorantActuator = new IrisDecorantActuator(this);
|
||||
biomeActuator = new IrisBiomeActuator(this);
|
||||
depositModifier = new IrisDepositModifier(this);
|
||||
ravineModifier = new IrisRavineModifier(this);
|
||||
caveModifier = new IrisCaveModifier(this);
|
||||
postModifier = new IrisPostModifier(this);
|
||||
effects = new IrisEngineEffects(this);
|
||||
J.a(this::computeBiomeMaxes);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
Iris.error("FAILED TO SETUP ENGINE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Iris.debug("Engine Setup Complete " + getCacheID());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -374,13 +384,6 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
});
|
||||
}
|
||||
|
||||
public EngineActuator<BlockData> getTerrainActuator() {
|
||||
return switch (getDimension().getTerrainMode()) {
|
||||
case NORMAL -> getTerrainNormalActuator();
|
||||
case ISLANDS -> getTerrainIslandActuator();
|
||||
};
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@Override
|
||||
public double modifyX(double x) {
|
||||
@ -406,23 +409,24 @@ public class IrisEngine extends BlockPopulator implements Engine {
|
||||
try {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y + getMinHeight(), z + zz, t));
|
||||
getMantle().generateMatter(x >> 4, z >> 4, multicore);
|
||||
|
||||
switch (getDimension().getTerrainMode()) {
|
||||
case NORMAL -> {
|
||||
getMantle().generateMatter(x >> 4, z >> 4, multicore);
|
||||
getTerrainActuator().actuate(x, z, vblocks, multicore);
|
||||
getBiomeActuator().actuate(x, z, vbiomes, multicore);
|
||||
getCaveModifier().modify(x, z, vblocks, multicore);
|
||||
getRavineModifier().modify(x, z, vblocks, multicore);
|
||||
getPostModifier().modify(x, z, vblocks, multicore);
|
||||
getDecorantActuator().actuate(x, z, blocks, multicore);
|
||||
getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore);
|
||||
getDepositModifier().modify(x, z, blocks, multicore);
|
||||
}
|
||||
case ISLANDS -> {
|
||||
getTerrainActuator().actuate(x, z, vblocks, multicore);
|
||||
}
|
||||
}
|
||||
burst().burst(multicore,
|
||||
() -> getTerrainActuator().actuate(x, z, vblocks, multicore),
|
||||
() -> getBiomeActuator().actuate(x, z, vbiomes, multicore)
|
||||
);
|
||||
burst().burst(multicore,
|
||||
() -> getCaveModifier().modify(x, z, vblocks, multicore),
|
||||
() -> getDecorantActuator().actuate(x, z, blocks, multicore),
|
||||
() -> getRavineModifier().modify(x, z, vblocks, multicore)
|
||||
);
|
||||
|
||||
getPostModifier().modify(x, z, vblocks, multicore);
|
||||
|
||||
burst().burst(multicore,
|
||||
() -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore),
|
||||
() -> getDepositModifier().modify(x, z, vblocks, multicore)
|
||||
);
|
||||
|
||||
getMetrics().getTotal().put(p.getMilliseconds());
|
||||
generated.incrementAndGet();
|
||||
|
@ -18,7 +18,9 @@
|
||||
|
||||
package com.volmit.iris.engine;
|
||||
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.mantle.MantleComponent;
|
||||
@ -27,6 +29,7 @@ import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
|
||||
import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.deposits.IrisDepositGenerator;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePotential;
|
||||
import com.volmit.iris.engine.object.jigsaw.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.engine.object.objects.IrisObject;
|
||||
@ -36,16 +39,22 @@ import com.volmit.iris.engine.object.regional.IrisRegion;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.stream.ProceduralStream;
|
||||
import com.volmit.iris.util.stream.interpolation.Interpolated;
|
||||
import com.volmit.iris.util.stream.utility.CachedStream2D;
|
||||
import lombok.Data;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Data
|
||||
@ -53,12 +62,13 @@ public class IrisEngineMantle implements EngineMantle {
|
||||
private final Engine engine;
|
||||
private final Mantle mantle;
|
||||
private final KList<MantleComponent> components;
|
||||
private final CompletableFuture<Integer> radius;
|
||||
private final int radius;
|
||||
private final AtomicCache<Integer> radCache = new AtomicCache<>();
|
||||
|
||||
public IrisEngineMantle(Engine engine) {
|
||||
this.engine = engine;
|
||||
this.mantle = new Mantle(new File(engine.getWorld().worldFolder(), "mantle"), engine.getTarget().getHeight());
|
||||
radius = burst().completeValue(this::computeParallaxSize);
|
||||
radius = radCache.aquire(this::computeParallaxSize);
|
||||
components = new KList<>();
|
||||
registerComponent(new MantleFeatureComponent(this));
|
||||
registerComponent(new MantleJigsawComponent(this));
|
||||
|
@ -211,7 +211,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
.shuffleCopy(RNG.r).stream()
|
||||
.filter(this::canSpawn),
|
||||
getData().getSpawnerLoader().streamAll(getEngine().getMantle()
|
||||
.getFeaturesInChunk(c).stream()
|
||||
.forEachFeature(c).stream()
|
||||
.flatMap((o) -> o.getFeature().getEntitySpawners().stream()))
|
||||
.filter(this::canSpawn))
|
||||
.filter((i) -> i.isValid(biome))
|
||||
@ -294,6 +294,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
private KList<IrisEntitySpawn> spawnRandomly(List<IrisEntitySpawn> types) {
|
||||
KList<IrisEntitySpawn> rarityTypes = new KList<>();
|
||||
int totalRarity = 0;
|
||||
|
||||
for (IrisEntitySpawn i : types) {
|
||||
totalRarity += IRare.get(i);
|
||||
}
|
||||
@ -344,7 +345,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
public void onChunkLoad(Chunk e, boolean generated) {
|
||||
if (generated) {
|
||||
energy += 1.2;
|
||||
spawnIn(e, true);
|
||||
J.a(() -> spawnIn(e, true), RNG.r.i(5, 50));
|
||||
} else {
|
||||
energy += 0.3;
|
||||
}
|
||||
|
@ -68,8 +68,7 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
|
||||
@Override
|
||||
public void onActuate(int x, int z, Hunk<Biome> h, boolean multicore) {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
BurstExecutor burst = burst().burst();
|
||||
burst.setMulticore(multicore);
|
||||
BurstExecutor burst = burst().burst(multicore);
|
||||
|
||||
for (int xf = 0; xf < h.getWidth(); xf++) {
|
||||
int finalXf = xf;
|
||||
|
@ -90,8 +90,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
|
||||
}
|
||||
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
BurstExecutor burst = burst().burst();
|
||||
burst.setMulticore(multicore);
|
||||
BurstExecutor burst = burst().burst(multicore);
|
||||
|
||||
for (int i = 0; i < output.getWidth(); i++) {
|
||||
int finalI = i;
|
||||
|
@ -1,95 +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.engine.actuator;
|
||||
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.EngineAssignedActuator;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
public class IrisTerrainIslandActuator extends EngineAssignedActuator<BlockData> {
|
||||
private static final BlockData AIR = Material.AIR.createBlockData();
|
||||
private static final BlockData BEDROCK = Material.BEDROCK.createBlockData();
|
||||
private static final BlockData WEB = Material.COBWEB.createBlockData();
|
||||
private static final BlockData BLACK_GLASS = Material.BLACK_STAINED_GLASS.createBlockData();
|
||||
private static final BlockData WHITE_GLASS = Material.WHITE_STAINED_GLASS.createBlockData();
|
||||
private static final BlockData CAVE_AIR = Material.CAVE_AIR.createBlockData();
|
||||
@Getter
|
||||
private final RNG rng;
|
||||
private final boolean carving;
|
||||
@Getter
|
||||
private final int lastBedrock = -1;
|
||||
|
||||
public IrisTerrainIslandActuator(Engine engine) {
|
||||
super(engine, "TerrainIsland");
|
||||
rng = new RNG(engine.getWorld().seed());
|
||||
carving = getDimension().isCarving() && getDimension().getCarveLayers().isNotEmpty();
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@Override
|
||||
public void onActuate(int x, int z, Hunk<BlockData> h, boolean multicore) {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
int i, zf, depth, surface, realX, realZ;
|
||||
IrisBiome biome;
|
||||
KList<BlockData> blocks, fblocks;
|
||||
int hi, lo;
|
||||
double hh;
|
||||
|
||||
for (int xf = 0; xf < h.getWidth(); xf++) {
|
||||
for (zf = 0; zf < h.getDepth(); zf++) {
|
||||
realX = (int) modX(xf + x);
|
||||
realZ = (int) modZ(zf + z);
|
||||
|
||||
if (getComplex().getIslandStream().get(realX, realZ)) {
|
||||
biome = getComplex().getTrueBiomeStream().get(realX, realZ);
|
||||
hh = getComplex().getTrueHeightStream().get(realX, realZ) - getComplex().getFluidHeight();
|
||||
depth = (int) (getComplex().getIslandDepthStream().get(realX, realZ).intValue() + hh);
|
||||
blocks = biome.generateLayers(realX, realZ, rng, depth, depth, getData(), getComplex());
|
||||
hi = getComplex().getIslandTopStream().get(realX, realZ);
|
||||
lo = getComplex().getIslandBottomStream().get(realX, realZ);
|
||||
|
||||
// 10
|
||||
// 6
|
||||
|
||||
// hf = 4
|
||||
|
||||
for (i = hi; i >= lo; i--) {
|
||||
int hf = (i - hi);
|
||||
if (blocks.hasIndex(hf)) {
|
||||
h.set(xf, i, zf, blocks.get(hf));
|
||||
continue;
|
||||
}
|
||||
|
||||
h.set(xf, i, zf, getComplex().getRockStream().get(realX, realZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getEngine().getMetrics().getTerrain().put(p.getMilliseconds());
|
||||
}
|
||||
}
|
@ -55,8 +55,7 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
||||
public void onActuate(int x, int z, Hunk<BlockData> h, boolean multicore) {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
|
||||
BurstExecutor e = getEngine().burst().burst(h.getWidth());
|
||||
e.setMulticore(multicore);
|
||||
BurstExecutor e = burst().burst(multicore);
|
||||
for (int xf = 0; xf < h.getWidth(); xf++) {
|
||||
int finalXf = xf;
|
||||
e.queue(() -> terrainSliver(x, z, finalXf, h));
|
||||
@ -67,70 +66,6 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
||||
getEngine().getMetrics().getTerrain().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
public void generateGround(int realX, int realZ, int xf, int zf, Hunk<BlockData> h, int surface, int bottom, int height, int fluidOrHeight, IrisBiome biome)
|
||||
{
|
||||
if(surface == bottom || surface-1 == bottom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KList<BlockData> blocks = null;
|
||||
KList<BlockData> fblocks = null;
|
||||
int depth,fdepth;
|
||||
|
||||
for (int i = surface; i >= bottom; i--) {
|
||||
if (i >= h.getHeight()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
if (getDimension().isBedrock()) {
|
||||
h.set(xf, i, zf, BEDROCK);
|
||||
lastBedrock = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (carving && getDimension().isCarved(getData(), realX, i, realZ, rng, height)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getDimension().getCaverns() != null && getDimension().getCaverns().isCavern(rng, realX, i, realZ, height, getData())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > height && i <= fluidOrHeight) {
|
||||
fdepth = fluidOrHeight - i;
|
||||
|
||||
if (fblocks == null) {
|
||||
fblocks = biome.generateSeaLayers(realX, realZ, rng, fluidOrHeight - height, getData());
|
||||
}
|
||||
|
||||
if (fblocks.hasIndex(fdepth)) {
|
||||
h.set(xf, i, zf, fblocks.get(fdepth));
|
||||
continue;
|
||||
}
|
||||
|
||||
h.set(xf, i, zf, getComplex().getFluidStream().get(realX, +realZ));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i <= height) {
|
||||
depth = surface - i;
|
||||
if (blocks == null) {
|
||||
blocks = biome.generateLayers(realX, realZ, rng, surface - bottom, surface, getData(), getComplex());
|
||||
}
|
||||
|
||||
if (blocks.hasIndex(depth)) {
|
||||
h.set(xf, i, zf, blocks.get(depth));
|
||||
continue;
|
||||
}
|
||||
|
||||
h.set(xf, i, zf, getComplex().getRockStream().get(realX, realZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int fluidOrHeight(int height)
|
||||
{
|
||||
return Math.max(getDimension().getFluidHeight(), height);
|
||||
@ -146,12 +81,12 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
||||
*/
|
||||
@BlockCoordinates
|
||||
public void terrainSliver(int x, int z, int xf, Hunk<BlockData> h) {
|
||||
int i, realX, realZ, hf, he;
|
||||
int zf, realX, realZ, hf, he;
|
||||
IrisBiome biome;
|
||||
|
||||
for (i = 0; i < h.getDepth(); i++) {
|
||||
for (zf = 0; zf < h.getDepth(); zf++) {
|
||||
realX = (int) modX(xf + x);
|
||||
realZ = (int) modZ(i + z);
|
||||
realZ = (int) modZ(zf + z);
|
||||
biome = getComplex().getTrueBiomeStream().get(realX, realZ);
|
||||
he = (int) Math.round(Math.min(h.getHeight(), getComplex().getHeightStream().get(realX, realZ)));
|
||||
hf = Math.round(Math.max(Math.min(h.getHeight(), getDimension().getFluidHeight()), he));
|
||||
@ -160,7 +95,65 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
||||
continue;
|
||||
}
|
||||
|
||||
generateGround(realX, realZ, xf, i, h, hf, 0, he, hf, biome);
|
||||
KList<BlockData> blocks = null;
|
||||
KList<BlockData> fblocks = null;
|
||||
int depth,fdepth;
|
||||
|
||||
for (int i = hf; i >= 0; i--) {
|
||||
if (i >= h.getHeight()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
if (getDimension().isBedrock()) {
|
||||
h.set(xf, i, zf, BEDROCK);
|
||||
lastBedrock = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (carving && getDimension().isCarved(getData(), realX, i, realZ, rng, he)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getDimension().getCaverns() != null && getDimension().getCaverns().isCavern(rng, realX, i, realZ, he, getData())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > he && i <= hf) {
|
||||
fdepth = hf - i;
|
||||
|
||||
if (fblocks == null) {
|
||||
fblocks = biome.generateSeaLayers(realX, realZ, rng, hf - he, getData());
|
||||
}
|
||||
|
||||
if (fblocks.hasIndex(fdepth)) {
|
||||
h.set(xf, i, zf, fblocks.get(fdepth));
|
||||
continue;
|
||||
}
|
||||
|
||||
h.set(xf, i, zf, getComplex().getFluidStream().get(realX, +realZ));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i <= he) {
|
||||
depth = he - i;
|
||||
if (blocks == null) {
|
||||
blocks = biome.generateLayers(realX, realZ, rng,
|
||||
he,
|
||||
he,
|
||||
getData(),
|
||||
getComplex());
|
||||
}
|
||||
|
||||
if (blocks.hasIndex(depth)) {
|
||||
h.set(xf, i, zf, blocks.get(depth));
|
||||
continue;
|
||||
}
|
||||
|
||||
h.set(xf, i, zf, getComplex().getRockStream().get(realX, realZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.data.chunk;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.BiomeBaseInjector;
|
||||
import com.volmit.iris.util.nbt.mca.Chunk;
|
||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
||||
@ -69,7 +70,7 @@ public class MCATerrainChunk implements TerrainChunk {
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, Biome bio) {
|
||||
writer.setBiome(ox + x, y, oz + z, bio);
|
||||
mcaChunk.setBiomeAt((ox + x) & 15, y, (oz + z) & 15, writer.getBiomeId(bio));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -91,6 +92,11 @@ public class MCATerrainChunk implements TerrainChunk {
|
||||
return;
|
||||
}
|
||||
|
||||
if(blockData == null)
|
||||
{
|
||||
Iris.error("NULL BD");
|
||||
}
|
||||
|
||||
mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false);
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
updateLighting(x, y, z, c);
|
||||
}
|
||||
}
|
||||
}, MantleFlag.UPDATE);
|
||||
});
|
||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
@ -434,13 +434,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
IrisDimension dim = getDimension();
|
||||
dim.getAllBiomes(this).forEach((i) -> v.put(i.getLoadKey(), i));
|
||||
|
||||
try {
|
||||
dim.getDimensionalComposite().forEach((m) -> getData().getDimensionLoader().load(m.getDimension()).getAllBiomes(this).forEach((i) -> v.put(i.getLoadKey(), i)));
|
||||
} catch (Throwable ignored) {
|
||||
Iris.reportError(ignored);
|
||||
|
||||
}
|
||||
|
||||
return v.v();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.math.RollingSequence;
|
||||
import lombok.Data;
|
||||
|
||||
@ -28,6 +29,7 @@ public class EngineAssignedComponent implements EngineComponent {
|
||||
private final String name;
|
||||
|
||||
public EngineAssignedComponent(Engine engine, String name) {
|
||||
Iris.debug("Engine: " + engine.getCacheID() + " Starting " + name);
|
||||
this.engine = engine;
|
||||
this.metrics = new RollingSequence(16);
|
||||
this.name = name;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
|
||||
|
@ -36,9 +36,7 @@ public class EngineTarget {
|
||||
this.world = world;
|
||||
this.dimension = dimension;
|
||||
this.data = data;
|
||||
this.burster = new MultiBurst("Iris Engine " + dimension.getName(),
|
||||
IrisSettings.get().getConcurrency().getEngineThreadPriority(),
|
||||
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getEngineThreadCount()));
|
||||
this.burster = MultiBurst.burst;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
@ -46,6 +44,6 @@ public class EngineTarget {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
burster.shutdownLater();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -114,9 +114,26 @@ public class PlannedStructure {
|
||||
int xx = i.getPosition().getX() + sx;
|
||||
int zz = i.getPosition().getZ() + sz;
|
||||
int offset = i.getPosition().getY() - startHeight;
|
||||
int height = (i.getStructure().getStructure().getLockY() != -1
|
||||
? i.getStructure().getStructure().getLockY()
|
||||
: placer.getHighest(xx, zz, getData())) + offset + (v.getH() / 2);
|
||||
int height = 0;
|
||||
|
||||
if(i.getStructure().getStructure().getLockY() == -1)
|
||||
{
|
||||
if(i.getStructure().getStructure().getOverrideYRange() != null)
|
||||
{
|
||||
height = (int)i.getStructure().getStructure().getOverrideYRange().get(rng, xx, zz, getData());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
height = placer.getHighest(xx, zz, getData());
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
height = i.getStructure().getStructure().getLockY();
|
||||
}
|
||||
|
||||
height += offset + (v.getH() / 2);
|
||||
|
||||
if (options.getMode().equals(ObjectPlaceMode.PAINT) || options.isVacuum()) {
|
||||
height = -1;
|
||||
|
@ -34,6 +34,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
@ -41,11 +42,8 @@ import org.bukkit.Chunk;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
// TODO: MOVE PLACER OUT OF MATTER INTO ITS OWN THING
|
||||
@ -56,7 +54,7 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
|
||||
Engine getEngine();
|
||||
|
||||
CompletableFuture<Integer> getRadius();
|
||||
int getRadius();
|
||||
|
||||
KList<MantleComponent> getComponents();
|
||||
|
||||
@ -171,15 +169,7 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
}
|
||||
|
||||
default int getRealRadius() {
|
||||
try {
|
||||
return (int) Math.ceil(getRadius().get() / 2D);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return (int) Math.ceil(getRadius() / 2D);
|
||||
}
|
||||
|
||||
|
||||
@ -189,7 +179,6 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
return;
|
||||
}
|
||||
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
KList<Runnable> post = new KList<>();
|
||||
Consumer<Runnable> c = (i) -> {
|
||||
synchronized (post)
|
||||
@ -198,15 +187,14 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
}
|
||||
};
|
||||
int s = getRealRadius();
|
||||
BurstExecutor burst = burst().burst();
|
||||
burst.setMulticore(multicore);
|
||||
|
||||
BurstExecutor burst = burst().burst(multicore);
|
||||
MantleWriter writer = getMantle().write(this, x, z, s * 2);
|
||||
for (int i = -s; i <= s; i++) {
|
||||
int xx = i + x;
|
||||
for (int j = -s; j <= s; j++) {
|
||||
int xx = i + x;
|
||||
int zz = j + z;
|
||||
burst.queue(() -> {
|
||||
getComponents().forEach((f) -> generateMantleComponent(xx, zz, f, c));
|
||||
getComponents().forEach((f) -> generateMantleComponent(writer, xx, zz, f, c));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -217,21 +205,12 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
{
|
||||
KList<Runnable> px = post.copy();
|
||||
post.clear();
|
||||
|
||||
if(multicore)
|
||||
{
|
||||
burst().burst(px);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
burst().sync(px);
|
||||
}
|
||||
burst().burst(multicore, px);
|
||||
}
|
||||
}
|
||||
|
||||
default void generateMantleComponent(int x, int z, MantleComponent c, Consumer<Runnable> post) {
|
||||
getMantle().raiseFlag(x, z, c.getFlag(), () -> c.generateLayer(x, z, post));
|
||||
default void generateMantleComponent(MantleWriter writer, int x, int z, MantleComponent c, Consumer<Runnable> post) {
|
||||
getMantle().raiseFlag(x, z, c.getFlag(), () -> c.generateLayer(writer, x, z, post));
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
@ -245,20 +224,23 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
|
||||
@BlockCoordinates
|
||||
default void updateBlock(int x, int y, int z) {
|
||||
getMantle().flag(x >> 4, z >> 4, MantleFlag.UPDATE, true);
|
||||
getMantle().set(x, y, z, true);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
default KList<IrisFeaturePositional> getFeaturesInChunk(Chunk c) {
|
||||
default List<IrisFeaturePositional> getFeaturesInChunk(Chunk c) {
|
||||
return getFeaturesInChunk(c.getX(), c.getZ());
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
default KList<IrisFeaturePositional> getFeaturesInChunk(int x, int z) {
|
||||
KList<IrisFeaturePositional> pos = new KList<>();
|
||||
getMantle().iterateChunk(x, z, IrisFeaturePositional.class, (a, b, c, f) -> pos.add(f), MantleFlag.FEATURE);
|
||||
return pos;
|
||||
default List<IrisFeaturePositional> getFeaturesInChunk(int x, int z) {
|
||||
return getMantle().getChunk(x, z).getFeatures();
|
||||
}
|
||||
|
||||
|
||||
@ChunkCoordinates
|
||||
default KList<IrisFeaturePositional> forEachFeature(Chunk c) {
|
||||
return forEachFeature((c.getX() << 4) + 8, (c.getZ() << 4) + 8);
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@ -283,7 +265,7 @@ public interface EngineMantle extends IObjectPlacer {
|
||||
for (i = -s; i <= s; i++) {
|
||||
for (j = -s; j <= s; j++) {
|
||||
try {
|
||||
for (IrisFeaturePositional k : getFeaturesInChunk(i + cx, j + cx)) {
|
||||
for (IrisFeaturePositional k : getFeaturesInChunk(i + cx, j + cz)) {
|
||||
if (k.shouldFilter(x, z, getEngine().getComplex().getRng(), getData())) {
|
||||
pos.add(k);
|
||||
}
|
||||
|
@ -62,5 +62,5 @@ public interface MantleComponent {
|
||||
MantleFlag getFlag();
|
||||
|
||||
@ChunkCoordinates
|
||||
void generateLayer(int x, int z, Consumer<Runnable> post);
|
||||
void generateLayer(MantleWriter writer, int x, int z, Consumer<Runnable> post);
|
||||
}
|
||||
|
149
src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java
Normal file
149
src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.mantle;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.engine.IrisEngineMantle;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.object.common.IObjectPlacer;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.engine.object.tile.TileData;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.matter.Matter;
|
||||
import lombok.Data;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
@Data
|
||||
public class MantleWriter implements IObjectPlacer
|
||||
{
|
||||
private final EngineMantle engineMantle;
|
||||
private final Mantle mantle;
|
||||
private final KMap<Long, MantleChunk> cachedChunks;
|
||||
private final int radius;
|
||||
private final int x;
|
||||
private final int z;
|
||||
|
||||
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius)
|
||||
{
|
||||
this.engineMantle = engineMantle;
|
||||
this.mantle = mantle;
|
||||
this.cachedChunks = new KMap<>();
|
||||
this.radius = radius;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
|
||||
for (int i = -radius; i <= radius; i++) {
|
||||
for (int j = -radius; j <= radius; j++) {
|
||||
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void setData(int x, int y, int z, T t)
|
||||
{
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
if (y < 0 || y >= mantle.getWorldHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cx >= this.x - radius && cx <= this.x + radius
|
||||
&& cz >= this.z - radius && cz <= this.z + radius)
|
||||
{
|
||||
MantleChunk chunk = cachedChunks.get(Cache.key(cx, cz));
|
||||
|
||||
if(chunk == null)
|
||||
{
|
||||
Iris.error("Mantle Writer Accessed " + cx + "," + cz + " and came up null (and yet within bounds!)");
|
||||
return;
|
||||
}
|
||||
|
||||
if(t instanceof IrisFeaturePositional)
|
||||
{
|
||||
chunk.addFeature((IrisFeaturePositional) t);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Matter matter = chunk.getOrCreate(y >> 4);
|
||||
matter.slice(matter.getClass(t)).set(x & 15, y & 15, z & 15, t);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Iris.error("Mantle Writer[" + this.x + "," + this.z + ",R" + this.radius + "] Tried to access " + x + "," + y + "," + z + " (Chunk " + cx + "," + cz + ") which is OUT OF BOUNDS!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z, IrisData data) {
|
||||
return engineMantle.getHighest(x, z, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
|
||||
return engineMantle.getHighest(x, z, data, ignoreFluid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int x, int y, int z, BlockData d) {
|
||||
setData(x, y, z, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData get(int x, int y, int z) {
|
||||
return getEngineMantle().get(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventingDecay() {
|
||||
return getEngineMantle().isPreventingDecay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid(int x, int y, int z) {
|
||||
return getEngineMantle().isSolid(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnderwater(int x, int z) {
|
||||
return getEngineMantle().isUnderwater(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFluidHeight() {
|
||||
return getEngineMantle().getFluidHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugSmartBore() {
|
||||
return getEngineMantle().isDebugSmartBore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
|
||||
getEngineMantle().setTile(xx,yy,zz,tile);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ package com.volmit.iris.engine.mantle.components;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.mantle.IrisMantleComponent;
|
||||
import com.volmit.iris.engine.mantle.MantleWriter;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePotential;
|
||||
@ -38,34 +39,34 @@ public class MantleFeatureComponent extends IrisMantleComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateLayer(int x, int z, Consumer<Runnable> post) {
|
||||
public void generateLayer(MantleWriter writer, int x, int z, Consumer<Runnable> post) {
|
||||
RNG rng = new RNG(Cache.key(x, z) + seed());
|
||||
int xxx = 8 + (x << 4);
|
||||
int zzz = 8 + (z << 4);
|
||||
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
|
||||
IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz);
|
||||
generateFeatures(rng, x, z, region, biome);
|
||||
generateFeatures(writer, rng, x, z, region, biome);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
private void generateFeatures(RNG rng, int cx, int cz, IrisRegion region, IrisBiome biome) {
|
||||
private void generateFeatures(MantleWriter writer, RNG rng, int cx, int cz, IrisRegion region, IrisBiome biome) {
|
||||
for (IrisFeaturePotential i : getFeatures()) {
|
||||
placeZone(rng, cx, cz, i);
|
||||
placeZone(writer, rng, cx, cz, i);
|
||||
}
|
||||
|
||||
for (IrisFeaturePotential i : region.getFeatures()) {
|
||||
placeZone(rng, cx, cz, i);
|
||||
placeZone(writer, rng, cx, cz, i);
|
||||
}
|
||||
|
||||
for (IrisFeaturePotential i : biome.getFeatures()) {
|
||||
placeZone(rng, cx, cz, i);
|
||||
placeZone(writer, rng, cx, cz, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void placeZone(RNG rng, int cx, int cz, IrisFeaturePotential i) {
|
||||
private void placeZone(MantleWriter writer, RNG rng, int cx, int cz, IrisFeaturePotential i) {
|
||||
int x = (cx << 4) + rng.nextInt(16);
|
||||
int z = (cz << 4) + rng.nextInt(16);
|
||||
getMantle().set(x, 0, z, new IrisFeaturePositional(x, z, i.getZone()));
|
||||
writer.setData(x, 0, z, new IrisFeaturePositional(x, z, i.getZone()));
|
||||
}
|
||||
|
||||
private KList<IrisFeaturePotential> getFeatures() {
|
||||
|
@ -18,42 +18,47 @@
|
||||
|
||||
package com.volmit.iris.engine.mantle.components;
|
||||
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.jigsaw.PlannedStructure;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.mantle.IrisMantleComponent;
|
||||
import com.volmit.iris.engine.mantle.MantleWriter;
|
||||
import com.volmit.iris.engine.object.basic.IrisPosition;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.engine.object.jigsaw.IrisJigsawStructure;
|
||||
import com.volmit.iris.engine.object.jigsaw.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.engine.object.noise.NoiseStyle;
|
||||
import com.volmit.iris.engine.object.regional.IrisRegion;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
private final CNG cng;
|
||||
|
||||
public MantleJigsawComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, MantleFlag.JIGSAW);
|
||||
cng = NoiseStyle.STATIC.create(new RNG());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateLayer(int x, int z, Consumer<Runnable> post) {
|
||||
RNG rng = new RNG(Cache.key(x, z) + seed());
|
||||
public void generateLayer(MantleWriter writer, int x, int z, Consumer<Runnable> post) {
|
||||
RNG rng = new RNG(cng.fit(-Integer.MAX_VALUE, Integer.MAX_VALUE, x, z));
|
||||
int xxx = 8 + (x << 4);
|
||||
int zzz = 8 + (z << 4);
|
||||
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
|
||||
IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz);
|
||||
generateJigsaw(rng, x, z, biome, region, post);
|
||||
generateJigsaw(writer, rng, x, z, biome, region, post);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
private void generateJigsaw(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer<Runnable> post) {
|
||||
private void generateJigsaw(MantleWriter writer, RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer<Runnable> post) {
|
||||
boolean placed = false;
|
||||
|
||||
if (getDimension().getStronghold() != null) {
|
||||
@ -63,7 +68,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
for (Position2 pos : poss) {
|
||||
if (x == pos.getX() >> 4 && z == pos.getZ() >> 4) {
|
||||
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(getDimension().getStronghold());
|
||||
place(pos.toIris(), structure, rng, post);
|
||||
place(writer, pos.toIris(), structure, rng, post);
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
@ -75,7 +80,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
if (rng.nextInt(i.getRarity()) == 0) {
|
||||
IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15));
|
||||
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure());
|
||||
place(position, structure, rng, post);
|
||||
place(writer, position, structure, rng, post);
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
@ -86,7 +91,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
if (rng.nextInt(i.getRarity()) == 0) {
|
||||
IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15));
|
||||
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure());
|
||||
place(position, structure, rng, post);
|
||||
place(writer, position, structure, rng, post);
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
@ -97,23 +102,22 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
if (rng.nextInt(i.getRarity()) == 0) {
|
||||
IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15));
|
||||
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure());
|
||||
place(position, structure, rng, post);
|
||||
place(writer, position, structure, rng, post);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
private void place(IrisPosition position, IrisJigsawStructure structure, RNG rng, Consumer<Runnable> post) {
|
||||
private void place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, Consumer<Runnable> post) {
|
||||
if (structure.getFeature() != null) {
|
||||
if (structure.getFeature().getBlockRadius() == 32) {
|
||||
structure.getFeature().setBlockRadius((double) structure.getMaxDimension() / 3);
|
||||
}
|
||||
|
||||
getMantle().set(position.getX(), 0, position.getZ(),
|
||||
writer.setData(position.getX(), 0, position.getZ(),
|
||||
new IrisFeaturePositional(position.getX(), position.getZ(), structure.getFeature()));
|
||||
}
|
||||
|
||||
post.accept(() -> new PlannedStructure(structure, position, rng).place(getEngineMantle(), getMantle(), post));
|
||||
post.accept(() -> new PlannedStructure(structure, position, rng).place(writer, getMantle(), post));
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.mantle.IrisMantleComponent;
|
||||
import com.volmit.iris.engine.mantle.MantleWriter;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeature;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
@ -42,21 +43,21 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateLayer(int x, int z, Consumer<Runnable> post) {
|
||||
public void generateLayer(MantleWriter writer, int x, int z, Consumer<Runnable> post) {
|
||||
RNG rng = new RNG(Cache.key(x, z) + seed());
|
||||
int xxx = 8 + (x << 4);
|
||||
int zzz = 8 + (z << 4);
|
||||
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
|
||||
IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz);
|
||||
placeObjects(rng, x, z, biome, region, post);
|
||||
placeObjects(writer, rng, x, z, biome, region, post);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
private void placeObjects(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer<Runnable> post) {
|
||||
private void placeObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer<Runnable> post) {
|
||||
for (IrisObjectPlacement i : biome.getSurfaceObjects()) {
|
||||
if (rng.chance(i.getChance() + rng.d(-0.005, 0.005)) && rng.chance(getComplex().getObjectChanceStream().get(x << 4, z << 4))) {
|
||||
try {
|
||||
placeObject(rng, x << 4, z << 4, i, post);
|
||||
placeObject(writer, rng, x << 4, z << 4, i, post);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
Iris.error("Failed to place objects in the following biome: " + biome.getName());
|
||||
@ -70,7 +71,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
||||
for (IrisObjectPlacement i : region.getSurfaceObjects()) {
|
||||
if (rng.chance(i.getChance() + rng.d(-0.005, 0.005)) && rng.chance(getComplex().getObjectChanceStream().get(x << 4, z << 4))) {
|
||||
try {
|
||||
placeObject(rng, x << 4, z << 4, i, post);
|
||||
placeObject(writer, rng, x << 4, z << 4, i, post);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
Iris.error("Failed to place objects in the following region: " + region.getName());
|
||||
@ -83,7 +84,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
private void placeObject(RNG rng, int x, int z, IrisObjectPlacement objectPlacement, Consumer<Runnable> post) {
|
||||
private void placeObject(MantleWriter writer, RNG rng, int x, int z, IrisObjectPlacement objectPlacement, Consumer<Runnable> post) {
|
||||
for (int i = 0; i < objectPlacement.getDensity(); i++) {
|
||||
IrisObject v = objectPlacement.getScale().get(rng, objectPlacement.getObject(getComplex(), rng));
|
||||
if (v == null) {
|
||||
@ -94,8 +95,8 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
||||
int id = rng.i(0, Integer.MAX_VALUE);
|
||||
|
||||
Runnable r = () -> {
|
||||
int h = v.place(xx, -1, zz, getEngineMantle(), objectPlacement, rng,
|
||||
(b) -> getMantle().set(b.getX(), b.getY(), b.getZ(),
|
||||
int h = v.place(xx, -1, zz, writer, objectPlacement, rng,
|
||||
(b) -> writer.setData(b.getX(), b.getY(), b.getZ(),
|
||||
v.getLoadKey() + "@" + id), null, getData());
|
||||
|
||||
if (objectPlacement.usesFeatures()) {
|
||||
@ -108,12 +109,12 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
||||
f.setInterpolationRadius(objectPlacement.getVacuumInterpolationRadius());
|
||||
f.setInterpolator(objectPlacement.getVacuumInterpolationMethod());
|
||||
f.setStrength(1D);
|
||||
getMantle().set(xx, 0, zz, new IrisFeaturePositional(xx, zz, f));
|
||||
writer.setData(xx, 0, zz, new IrisFeaturePositional(xx, zz, f));
|
||||
}
|
||||
|
||||
for (IrisFeaturePotential j : objectPlacement.getAddFeatures()) {
|
||||
if (j.hasZone(rng, xx >> 4, zz >> 4)) {
|
||||
getMantle().set(xx, 0, zz, new IrisFeaturePositional(xx, zz, j.getZone()));
|
||||
writer.setData(xx, 0, zz, new IrisFeaturePositional(xx, zz, j.getZone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,20 +55,13 @@ public class IrisCaveModifier extends EngineAssignedModifier<BlockData> {
|
||||
}
|
||||
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
if (multicore) {
|
||||
BurstExecutor e = getEngine().burst().burst(a.getWidth());
|
||||
for (int i = 0; i < a.getWidth(); i++) {
|
||||
int finalI = i;
|
||||
e.queue(() -> modifySliver(x, z, finalI, a));
|
||||
}
|
||||
|
||||
e.complete();
|
||||
} else {
|
||||
for (int i = 0; i < a.getWidth(); i++) {
|
||||
modifySliver(x, z, i, a);
|
||||
}
|
||||
BurstExecutor e = burst().burst(multicore);
|
||||
for (int i = 0; i < a.getWidth(); i++) {
|
||||
int finalI = i;
|
||||
e.queue(() -> modifySliver(x, z, finalI, a));
|
||||
}
|
||||
|
||||
e.complete();
|
||||
getEngine().getMetrics().getCave().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
@ -244,7 +237,7 @@ public class IrisCaveModifier extends EngineAssignedModifier<BlockData> {
|
||||
}
|
||||
|
||||
public boolean canAir(Material m, BlockData caveFluid) {
|
||||
return (B.isSolid(m) ||
|
||||
return (m.isSolid() ||
|
||||
(B.isDecorant(m.createBlockData())) || m.equals(Material.AIR)
|
||||
|| m.equals(caveFluid.getMaterial()) ||
|
||||
m.equals(B.getMaterial("CAVE_AIR")))
|
||||
@ -256,6 +249,6 @@ public class IrisCaveModifier extends EngineAssignedModifier<BlockData> {
|
||||
}
|
||||
|
||||
public boolean can(Material m) {
|
||||
return B.isSolid(m) && !m.equals(Material.BEDROCK);
|
||||
return m.isSolid() && !m.equals(Material.BEDROCK);
|
||||
}
|
||||
}
|
||||
|
@ -1,75 +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.engine.modifier;
|
||||
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.EngineAssignedModifier;
|
||||
import com.volmit.iris.engine.object.common.CaveResult;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.FastNoiseDouble;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
public class IrisCaveModifier2 extends EngineAssignedModifier<BlockData> {
|
||||
public static final BlockData CAVE_AIR = B.get("CAVE_AIR");
|
||||
public static final BlockData AIR = B.get("AIR");
|
||||
private static final KList<CaveResult> EMPTY = new KList<>();
|
||||
private final FastNoiseDouble gg;
|
||||
private final RNG rng;
|
||||
|
||||
public IrisCaveModifier2(Engine engine) {
|
||||
super(engine, "Cave");
|
||||
rng = new RNG(engine.getWorld().seed() + 28934555);
|
||||
gg = new FastNoiseDouble(324895L * rng.nextParallelRNG(49678).imax());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModify(int x, int z, Hunk<BlockData> a, boolean multicore) {
|
||||
if (!getDimension().isCaves()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
if (multicore) {
|
||||
BurstExecutor e = getEngine().burst().burst(a.getWidth());
|
||||
for (int i = 0; i < a.getWidth(); i++) {
|
||||
int finalI = i;
|
||||
e.queue(() -> modifySliver(x, z, finalI, a));
|
||||
}
|
||||
|
||||
e.complete();
|
||||
} else {
|
||||
for (int i = 0; i < a.getWidth(); i++) {
|
||||
modifySliver(x, z, i, a);
|
||||
}
|
||||
}
|
||||
|
||||
getEngine().getMetrics().getCave().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
public void modifySliver(int x, int z, int finalI, Hunk<BlockData> a) {
|
||||
for (int j = 0; j < a.getDepth(); j++) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -54,8 +54,8 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
|
||||
RNG ro = rx.nextParallelRNG(x * x).nextParallelRNG(z * z);
|
||||
IrisRegion region = getComplex().getRegionStream().get((x * 16) + 7, (z * 16) + 7);
|
||||
IrisBiome biome = getComplex().getTrueBiomeStream().get((x * 16) + 7, (z * 16) + 7);
|
||||
BurstExecutor burst = burst().burst();
|
||||
burst.setMulticore(multicore);
|
||||
BurstExecutor burst = burst().burst(multicore);
|
||||
|
||||
for (IrisDepositGenerator k : getDimension().getDeposits()) {
|
||||
burst.queue(() -> generate(k, terrain, ro, x, z, false));
|
||||
}
|
||||
|
@ -64,20 +64,15 @@ public class IrisPostModifier extends EngineAssignedModifier<BlockData> {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
AtomicInteger i = new AtomicInteger();
|
||||
AtomicInteger j = new AtomicInteger();
|
||||
BurstExecutor burst = burst().burst();
|
||||
burst.setMulticore(multicore);
|
||||
Hunk<BlockData> sync = output.synchronize();
|
||||
for (i.set(0); i.get() < output.getWidth(); i.getAndIncrement()) {
|
||||
burst.queue(() -> {
|
||||
for (j.set(0); j.get() < output.getDepth(); j.getAndIncrement()) {
|
||||
int ii = i.get();
|
||||
int jj = j.get();
|
||||
post(ii, jj, sync, ii + x, jj + z);
|
||||
}
|
||||
});
|
||||
for (j.set(0); j.get() < output.getDepth(); j.getAndIncrement()) {
|
||||
int ii = i.get();
|
||||
int jj = j.get();
|
||||
post(ii, jj, sync, ii + x, jj + z);
|
||||
}
|
||||
}
|
||||
|
||||
burst.complete();
|
||||
getEngine().getMetrics().getPost().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,10 @@ public class IrisPosition {
|
||||
public IrisPosition(Vector v) {
|
||||
this(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||
}
|
||||
public IrisPosition(double x, double y, double z) {
|
||||
this((int)x,(int)y,(int)z);
|
||||
}
|
||||
|
||||
|
||||
public IrisPosition add(IrisPosition relativePosition) {
|
||||
return new IrisPosition(relativePosition.x + x, relativePosition.y + y, relativePosition.z + z);
|
||||
|
@ -48,8 +48,10 @@ import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.data.DataProvider;
|
||||
import com.volmit.iris.util.data.VanillaBiomeMap;
|
||||
import com.volmit.iris.util.inventorygui.RandomColor;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -696,4 +698,9 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
public String getTypeName() {
|
||||
return "Biome";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import com.volmit.iris.engine.object.annotations.*;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -193,17 +195,15 @@ public class IrisBlockData extends IrisRegistrant {
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.valueOf(string);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
return Integer.parseInt(string);
|
||||
} catch (Throwable ignored) {
|
||||
// Checks
|
||||
}
|
||||
|
||||
try {
|
||||
return Double.valueOf(string).intValue();
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
} catch (Throwable ignored) {
|
||||
// Checks
|
||||
}
|
||||
|
||||
return string;
|
||||
@ -218,4 +218,9 @@ public class IrisBlockData extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Block";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.object.cave;
|
||||
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.core.project.loader.IrisRegistrant;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.noise.IrisWorm;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.Worm;
|
||||
import com.volmit.iris.util.noise.Worm3;
|
||||
import com.volmit.iris.util.noise.WormIterator3;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Desc("Translate objects")
|
||||
@Data
|
||||
public class IrisCave extends IrisRegistrant {
|
||||
@Desc("Define the shape of this cave")
|
||||
private IrisWorm worm;
|
||||
|
||||
@Override
|
||||
public String getFolderName() {
|
||||
return "caves";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Cave";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
@ -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.engine.object.cave;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.MinNumber;
|
||||
import com.volmit.iris.engine.object.annotations.RegistryListResource;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
import com.volmit.iris.engine.object.basic.IrisPosition;
|
||||
import com.volmit.iris.engine.object.common.IRare;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.Worm3;
|
||||
import com.volmit.iris.util.noise.WormIterator3;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Desc("Translate objects")
|
||||
@Data
|
||||
public class IrisCavePlacer implements IRare {
|
||||
private static final BlockData CAVE_AIR = B.get("CAVE_AIR");
|
||||
|
||||
@Required
|
||||
@Desc("Typically a 1 in RARITY on a per chunk basis")
|
||||
@MinNumber(1)
|
||||
private int rarity = 15;
|
||||
|
||||
@MinNumber(1)
|
||||
@Required
|
||||
@Desc("The cave to place")
|
||||
@RegistryListResource(IrisCave.class)
|
||||
private String cave;
|
||||
|
||||
private transient final AtomicCache<IrisCave> caveCache = new AtomicCache<>();
|
||||
private transient final AtomicBoolean fail = new AtomicBoolean(false);
|
||||
|
||||
public IrisCave getRealCave(IrisData data)
|
||||
{
|
||||
return caveCache.aquire(() -> data.getCaveLoader().load(getCave()));
|
||||
}
|
||||
|
||||
public void generateCave(Mantle mantle, RNG rng, IrisData data, int x, int y, int z)
|
||||
{
|
||||
if(fail.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IrisCave cave = getRealCave(data);
|
||||
|
||||
if(cave == null)
|
||||
{
|
||||
Iris.warn("Unable to locate cave for generation!");
|
||||
fail.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
WormIterator3 w = cave.getWorm().iterate3D(rng, data, x, y, z);
|
||||
KList<Vector> points = new KList<>();
|
||||
int itr = 0;
|
||||
while(w.hasNext())
|
||||
{
|
||||
itr++;
|
||||
Worm3 wx = w.next();
|
||||
points.add(new Vector(wx.getX().getPosition(), wx.getY().getPosition(), wx.getZ().getPosition()));
|
||||
}
|
||||
|
||||
|
||||
Iris.info(x + " " + y + " " + z + " /." + " POS: " + points.convert((i) -> "[" + i.getBlockX() + "," + i.getBlockY() + "," + i.getBlockZ() + "]").toString(", "));
|
||||
|
||||
mantle.setLine(points.convert(IrisPosition::new), cave.getWorm().getGirth().get(rng, x, z, data), true, CAVE_AIR);
|
||||
|
||||
|
||||
// TODO decorate somehow
|
||||
}
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
package com.volmit.iris.engine.object.common;
|
||||
|
||||
import com.volmit.iris.core.project.loader.IrisRegistrant;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@ -48,4 +50,9 @@ public class IrisScript extends IrisRegistrant {
|
||||
public String toString() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -50,9 +50,11 @@ import com.volmit.iris.engine.object.villager.IrisVillagerOverride;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.data.DataProvider;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -81,13 +83,6 @@ public class IrisDimension extends IrisRegistrant {
|
||||
@Desc("The human readable name of this dimension")
|
||||
private String name = "A Dimension";
|
||||
|
||||
@Desc("You can create mutliple dimensions on top of each other taking up less height of the same world. Such as the nether with a floor + ceiling.")
|
||||
@ArrayType(min = 1, type = IrisDimensionIndex.class)
|
||||
private KList<IrisDimensionIndex> dimensionalComposite = new KList<>();
|
||||
|
||||
@Desc("Create an inverted dimension in the sky (like the nether)")
|
||||
private IrisDimension sky = null;
|
||||
|
||||
@RegistryListResource(IrisJigsawStructure.class)
|
||||
@Desc("If defined, Iris will place the given jigsaw structure where minecraft should place the overworld stronghold.")
|
||||
private String stronghold;
|
||||
@ -285,12 +280,6 @@ public class IrisDimension extends IrisRegistrant {
|
||||
@Desc("Change the size of regions")
|
||||
private double regionZoom = 1;
|
||||
|
||||
@Desc("The terrain mode. NORMAL is normal... ISLANDS creates floating islands at varied heights")
|
||||
private IrisTerrainMode terrainMode = IrisTerrainMode.NORMAL;
|
||||
|
||||
@Desc("The configuration for island mode dimensions")
|
||||
private IrisTerrainIsland islandMode = new IrisTerrainIsland();
|
||||
|
||||
@Desc("Disable this to stop placing objects, entities, features & updates")
|
||||
private boolean useMantle = true;
|
||||
|
||||
@ -358,10 +347,6 @@ public class IrisDimension extends IrisRegistrant {
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasSky() {
|
||||
return getSky() != null;
|
||||
}
|
||||
|
||||
public CNG getCoordFracture(RNG rng, int signature) {
|
||||
return coordFracture.aquire(() ->
|
||||
{
|
||||
@ -560,4 +545,9 @@ public class IrisDimension extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Dimension";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +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.engine.object.dimensional;
|
||||
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.MinNumber;
|
||||
import com.volmit.iris.engine.object.annotations.RegistryListResource;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@SuppressWarnings("DefaultAnnotationParam")
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Desc("Represents an index for dimensions to take up vertical slots in the same world")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisDimensionIndex {
|
||||
@Required
|
||||
@Desc("The weight of this dimension. If there are 2 dimensions, if the weight is the same on both, both dimensions will take up 128 blocks of height.")
|
||||
private double weight = 1D;
|
||||
|
||||
@Desc("If inverted is set to true, the dimension will be updide down in the world")
|
||||
private boolean inverted = false;
|
||||
|
||||
@Desc("Only one dimension layer should be set to primary. The primary dimension layer is where players spawn, and the biomes that the vanilla structure system uses to figure out what structures to place.")
|
||||
private boolean primary = false;
|
||||
|
||||
@Required
|
||||
@RegistryListResource(IrisDimension.class)
|
||||
@MinNumber(1)
|
||||
@Desc("Name of dimension")
|
||||
private String dimension = "";
|
||||
}
|
@ -1,50 +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.engine.object.dimensional;
|
||||
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.MaxNumber;
|
||||
import com.volmit.iris.engine.object.annotations.MinNumber;
|
||||
import com.volmit.iris.engine.object.noise.IrisInterpolator;
|
||||
import com.volmit.iris.engine.object.noise.IrisStyledRange;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Desc("Translate objects")
|
||||
@Data
|
||||
public class IrisTerrainIsland {
|
||||
@Desc("The height range")
|
||||
private IrisStyledRange height = new IrisStyledRange().setMin(60).setMax(160);
|
||||
|
||||
@Desc("How deep the island can get")
|
||||
private IrisStyledRange islandDepth = new IrisStyledRange().setMin(60).setMax(160);
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(10000)
|
||||
@Desc("How often are regions islands instead of nothing?")
|
||||
private double islandChance = 0.5;
|
||||
|
||||
@Desc("Interpolate the edges of islands")
|
||||
private IrisInterpolator islandEdgeInterpolator = new IrisInterpolator();
|
||||
}
|
@ -32,7 +32,9 @@ import com.volmit.iris.engine.object.meta.IrisEffect;
|
||||
import com.volmit.iris.engine.object.spawners.IrisSurface;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
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.PrecisionStopwatch;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -380,4 +382,9 @@ public class IrisEntity extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Entity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.volmit.iris.engine.object.feature;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
@ -63,7 +64,18 @@ public class IrisFeaturePositional {
|
||||
private static double BLOCK = 1D / 256D; // TODO: WARNING HEIGHT
|
||||
|
||||
public static IrisFeaturePositional read(DataInputStream s) throws IOException {
|
||||
return new Gson().fromJson(s.readUTF(), IrisFeaturePositional.class);
|
||||
String sx = s.readUTF();
|
||||
try
|
||||
{
|
||||
return new Gson().fromJson(sx, IrisFeaturePositional.class);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
Iris.error(sx);
|
||||
e.printStackTrace();
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(DataOutputStream s) throws IOException {
|
||||
|
@ -30,6 +30,8 @@ import com.volmit.iris.engine.object.objects.IrisObject;
|
||||
import com.volmit.iris.engine.object.objects.IrisObjectPlacement;
|
||||
import com.volmit.iris.engine.object.objects.ObjectPlaceMode;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -136,4 +138,9 @@ public class IrisJigsawPiece extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Jigsaw Piece";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.RegistryListResource;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -54,4 +56,9 @@ public class IrisJigsawPool extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Jigsaw Pool";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,10 @@ import com.volmit.iris.core.project.loader.IrisRegistrant;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeature;
|
||||
import com.volmit.iris.engine.object.noise.IrisStyledRange;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -59,7 +62,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
|
||||
@Desc("If set to true, iris will look for any pieces with only one connector in valid pools for edge connectors and attach them to 'terminate' the paths/piece connectors. Essentially it caps off ends. For example in a village, Iris would add houses to the ends of roads where possible. For terminators to be selected, they can only have one connector or they wont be chosen.")
|
||||
private boolean terminate = true;
|
||||
|
||||
@Desc("Set to lock the starting peice to a y coordinate, otherwise the surface will be used.")
|
||||
@Desc("Override the y range instead of placing on the height map")
|
||||
private IrisStyledRange overrideYRange = null;
|
||||
|
||||
@Desc("Force Y to a specific value")
|
||||
private int lockY = -1;
|
||||
|
||||
private transient AtomicCache<Integer> maxDimension = new AtomicCache<>();
|
||||
@ -144,4 +150,9 @@ public class IrisJigsawStructure extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Jigsaw Structure";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ import com.volmit.iris.engine.object.annotations.MinNumber;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
import com.volmit.iris.engine.object.meta.InventorySlotType;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -96,4 +98,9 @@ public class IrisLootTable extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Loot";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import com.volmit.iris.engine.object.objects.IrisObject;
|
||||
import com.volmit.iris.engine.object.objects.IrisObjectReplace;
|
||||
import com.volmit.iris.engine.object.regional.IrisRegion;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -113,4 +115,9 @@ public class IrisMod extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Mod";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,9 @@ import com.volmit.iris.engine.object.annotations.ArrayType;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.stream.ProceduralStream;
|
||||
import com.volmit.iris.util.stream.interpolation.Interpolated;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -128,4 +130,9 @@ public class IrisExpression extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Expression";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ import com.volmit.iris.engine.object.common.IRare;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.context.IrisContext;
|
||||
import com.volmit.iris.util.interpolation.IrisInterpolation;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CellGenerator;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -295,4 +297,9 @@ public class IrisGenerator extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Generator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.engine.object.cave;
|
||||
package com.volmit.iris.engine.object.noise;
|
||||
|
||||
import com.volmit.iris.core.project.loader.IrisData;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.MinNumber;
|
||||
import com.volmit.iris.engine.object.annotations.Required;
|
||||
@ -27,7 +29,11 @@ import com.volmit.iris.engine.object.noise.IrisGeneratorStyle;
|
||||
import com.volmit.iris.engine.object.noise.IrisNoiseGenerator;
|
||||
import com.volmit.iris.engine.object.noise.IrisStyledRange;
|
||||
import com.volmit.iris.engine.object.noise.NoiseStyle;
|
||||
import com.volmit.iris.util.function.NoiseProvider;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.Worm;
|
||||
import com.volmit.iris.util.noise.WormIterator2;
|
||||
import com.volmit.iris.util.noise.WormIterator3;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -38,14 +44,9 @@ import lombok.experimental.Accessors;
|
||||
@AllArgsConstructor
|
||||
@Desc("Generate worms")
|
||||
@Data
|
||||
public class IrisWormGenerator implements IRare {
|
||||
@Required
|
||||
@Desc("Typically a 1 in RARITY on a per chunk basis")
|
||||
@MinNumber(1)
|
||||
private int rarity = 15;
|
||||
|
||||
public class IrisWorm {
|
||||
@Desc("The style used to determine the curvature of this worm")
|
||||
private IrisGeneratorStyle angleStyle = new IrisGeneratorStyle();
|
||||
private IrisGeneratorStyle angleStyle = new IrisGeneratorStyle(NoiseStyle.PERLIN);
|
||||
|
||||
@Desc("The max block distance this worm can travel from its start. This can have performance implications at ranges over 1,000 blocks but it's not too serious, test.")
|
||||
private int maxDistance = 128;
|
||||
@ -53,7 +54,36 @@ public class IrisWormGenerator implements IRare {
|
||||
@Desc("The max segments, or iterations this worm can execute on. Setting this to -1 will allow it to run up to the maxDistance's value of iterations (default)")
|
||||
private int maxSegments = -1;
|
||||
|
||||
@Desc("The thickness of the worm over distance")
|
||||
private IrisStyledRange girth = new IrisStyledRange().setMin(3).setMax(7)
|
||||
.setStyle(new IrisGeneratorStyle(NoiseStyle.SIMPLEX));
|
||||
@Desc("The distance between segments")
|
||||
private IrisStyledRange segmentDistance = new IrisStyledRange().setMin(4).setMax(7)
|
||||
.setStyle(new IrisGeneratorStyle(NoiseStyle.PERLIN));
|
||||
|
||||
@Desc("The thickness of the worms. Each individual worm has the same thickness while traveling however, each spawned worm will vary in thickness.")
|
||||
private IrisStyledRange girth = new IrisStyledRange().setMin(3).setMax(5)
|
||||
.setStyle(new IrisGeneratorStyle(NoiseStyle.PERLIN));
|
||||
|
||||
private transient final AtomicCache<NoiseProvider> angleProviderCache = new AtomicCache<>();
|
||||
|
||||
public NoiseProvider getAngleProvider(RNG rng, IrisData data)
|
||||
{
|
||||
return angleProviderCache.aquire(() -> (xx, zz) -> angleStyle.create(rng, data).fitDouble(-0.5, 0.5, xx, zz) * segmentDistance.get(rng, xx, zz, data));
|
||||
}
|
||||
|
||||
public WormIterator2 iterate2D(RNG rng, IrisData data, int x, int z)
|
||||
{
|
||||
return WormIterator2.builder()
|
||||
.maxDistance(maxDistance)
|
||||
.maxIterations(maxSegments == -1 ? maxDistance : maxSegments)
|
||||
.noise(getAngleProvider(rng, data)).x(x).z(z)
|
||||
.build();
|
||||
}
|
||||
|
||||
public WormIterator3 iterate3D(RNG rng, IrisData data, int x, int y, int z)
|
||||
{
|
||||
return WormIterator3.builder()
|
||||
.maxDistance(maxDistance)
|
||||
.maxIterations(maxSegments == -1 ? maxDistance : maxSegments)
|
||||
.noise(getAngleProvider(rng, data)).x(x).z(z).y(y)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -31,10 +31,12 @@ import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.interpolation.IrisInterpolation;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.AxisAlignedBB;
|
||||
import com.volmit.iris.util.math.BlockPosition;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.IrisLock;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
@ -281,7 +283,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
if (!din.readUTF().equals("Iris V2 IOB;")) {
|
||||
throw new IOException("Not V2 Format");
|
||||
return;
|
||||
}
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readShort();
|
||||
@ -994,4 +996,9 @@ public class IrisObject extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Object";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,10 @@ import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.data.DataProvider;
|
||||
import com.volmit.iris.util.data.VanillaBiomeMap;
|
||||
import com.volmit.iris.util.inventorygui.RandomColor;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -572,4 +574,9 @@ public class IrisRegion extends IrisRegistrant implements IRare {
|
||||
public String getTypeName() {
|
||||
return "Region";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import com.volmit.iris.engine.object.basic.IrisWeather;
|
||||
import com.volmit.iris.engine.object.biome.IrisBiome;
|
||||
import com.volmit.iris.engine.object.entity.IrisEntitySpawn;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -106,4 +108,9 @@ public class IrisSpawner extends IrisRegistrant {
|
||||
public String getTypeName() {
|
||||
return "Spawner";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
}
|
||||
|
||||
loadLock.acquire();
|
||||
PrecisionStopwatch ps = PrecisionStopwatch.start();
|
||||
TerrainChunk tc = TerrainChunk.create(world, biome);
|
||||
Hunk<BlockData> blocks = Hunk.view((ChunkData) tc);
|
||||
Hunk<Biome> biomes = Hunk.view((BiomeGrid) tc);
|
||||
|
@ -34,6 +34,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.documentation.RegionCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.nbt.mca.MCAFile;
|
||||
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||
@ -58,18 +59,17 @@ public class HeadlessGenerator implements PlatformChunkGenerator {
|
||||
|
||||
public HeadlessGenerator(HeadlessWorld world) {
|
||||
this.world = world;
|
||||
burst = new MultiBurst("Iris Headless Generator", 9, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount()));
|
||||
burst = MultiBurst.burst;
|
||||
writer = new NBTWorld(world.getWorld().worldFolder());
|
||||
engine = new IrisEngine(new EngineTarget(world.getWorld(), world.getDimension(), world.getDimension().getLoader()), isStudio());
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
public void generateChunk(int x, int z) {
|
||||
public void generateChunk(MCAFile file, int x, int z) {
|
||||
try {
|
||||
int ox = x << 4;
|
||||
int oz = z << 4;
|
||||
com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(x, z);
|
||||
|
||||
com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(file, x, z);
|
||||
TerrainChunk tc = MCATerrainChunk.builder()
|
||||
.writer(writer).ox(ox).oz(oz).mcaChunk(chunk)
|
||||
.minHeight(world.getWorld().minHeight()).maxHeight(world.getWorld().maxHeight())
|
||||
@ -102,11 +102,12 @@ public class HeadlessGenerator implements PlatformChunkGenerator {
|
||||
@RegionCoordinates
|
||||
public void generateRegion(int x, int z, PregenListener listener) {
|
||||
BurstExecutor e = burst.burst(1024);
|
||||
MCAFile f = writer.getMCA(x, x);
|
||||
PregenTask.iterateRegion(x, z, (ii, jj) -> e.queue(() -> {
|
||||
if (listener != null) {
|
||||
listener.onChunkGenerating(ii, jj);
|
||||
}
|
||||
generateChunk(ii, jj);
|
||||
generateChunk(f, ii, jj);
|
||||
if (listener != null) {
|
||||
listener.onChunkGenerated(ii, jj);
|
||||
}
|
||||
@ -131,7 +132,6 @@ public class HeadlessGenerator implements PlatformChunkGenerator {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
burst.shutdownAndAwait();
|
||||
getEngine().close();
|
||||
writer.close();
|
||||
}
|
||||
|
@ -22,7 +22,10 @@ import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSets;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@ -33,395 +36,201 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.bukkit.Material.*;
|
||||
|
||||
public class B {
|
||||
private static final Material AIR_MATERIAL = Material.AIR;
|
||||
private static final BlockData AIR = AIR_MATERIAL.createBlockData();
|
||||
private static final KSet<String> nullBlockDataCache = new KSet<>();
|
||||
private static final KSet<String> nullMaterialCache = new KSet<>();
|
||||
private static final KMap<Material, Boolean> solidCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> updatableCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> foliageCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> litCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> decorantCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> storageCache = new KMap<>();
|
||||
private static final KMap<Material, Boolean> storageChestCache = new KMap<>();
|
||||
private static final IntSet foliageCache = buildFoliageCache();
|
||||
private static final IntSet decorantCache = buildDecorantCache();
|
||||
private static final IntSet storageCache = buildStorageCache();
|
||||
private static final IntSet storageChestCache = buildStorageChestCache();
|
||||
private static final IntSet litCache = buildLitCache();
|
||||
private static final KMap<String, BlockData> blockDataCache = new KMap<>();
|
||||
private static final KMap<String, Material> materialCache = new KMap<>();
|
||||
private static final ChronoLatch clw = new ChronoLatch(1000);
|
||||
|
||||
public static boolean isWater(BlockData b) {
|
||||
return b.getMaterial().equals(Material.WATER);
|
||||
private static IntSet buildFoliageCache() {
|
||||
IntSet b = new IntOpenHashSet();
|
||||
Arrays.stream(new Material[]{
|
||||
POPPY,
|
||||
DANDELION,
|
||||
CORNFLOWER,
|
||||
SWEET_BERRY_BUSH,
|
||||
CRIMSON_ROOTS,
|
||||
WARPED_ROOTS,
|
||||
NETHER_SPROUTS,
|
||||
ALLIUM,
|
||||
AZURE_BLUET,
|
||||
BLUE_ORCHID,
|
||||
OXEYE_DAISY,
|
||||
LILY_OF_THE_VALLEY,
|
||||
WITHER_ROSE,
|
||||
DARK_OAK_SAPLING,
|
||||
ACACIA_SAPLING,
|
||||
JUNGLE_SAPLING,
|
||||
BIRCH_SAPLING,
|
||||
SPRUCE_SAPLING,
|
||||
OAK_SAPLING,
|
||||
ORANGE_TULIP,
|
||||
PINK_TULIP,
|
||||
RED_TULIP,
|
||||
WHITE_TULIP,
|
||||
FERN,
|
||||
LARGE_FERN,
|
||||
GRASS,
|
||||
TALL_GRASS
|
||||
}).forEach((i) -> b.add(i.ordinal()));
|
||||
|
||||
return IntSets.unmodifiable(b);
|
||||
}
|
||||
|
||||
public static BlockData getAir() {
|
||||
return AIR;
|
||||
private static IntSet buildDecorantCache() {
|
||||
IntSet b = new IntOpenHashSet();
|
||||
Arrays.stream(new Material[]{
|
||||
GRASS,
|
||||
TALL_GRASS,
|
||||
FERN,
|
||||
LARGE_FERN,
|
||||
CORNFLOWER,
|
||||
SUNFLOWER,
|
||||
CHORUS_FLOWER,
|
||||
POPPY,
|
||||
DANDELION,
|
||||
OXEYE_DAISY,
|
||||
ORANGE_TULIP,
|
||||
PINK_TULIP,
|
||||
RED_TULIP,
|
||||
WHITE_TULIP,
|
||||
LILAC,
|
||||
DEAD_BUSH,
|
||||
SWEET_BERRY_BUSH,
|
||||
ROSE_BUSH,
|
||||
WITHER_ROSE,
|
||||
ALLIUM,
|
||||
BLUE_ORCHID,
|
||||
LILY_OF_THE_VALLEY,
|
||||
CRIMSON_FUNGUS,
|
||||
WARPED_FUNGUS,
|
||||
RED_MUSHROOM,
|
||||
BROWN_MUSHROOM,
|
||||
CRIMSON_ROOTS,
|
||||
AZURE_BLUET,
|
||||
WEEPING_VINES,
|
||||
WEEPING_VINES_PLANT,
|
||||
WARPED_ROOTS,
|
||||
NETHER_SPROUTS,
|
||||
TWISTING_VINES,
|
||||
TWISTING_VINES_PLANT,
|
||||
SUGAR_CANE,
|
||||
WHEAT,
|
||||
POTATOES,
|
||||
CARROTS,
|
||||
BEETROOTS,
|
||||
NETHER_WART,
|
||||
SEA_PICKLE,
|
||||
SEAGRASS,
|
||||
ACACIA_BUTTON,
|
||||
BIRCH_BUTTON,
|
||||
CRIMSON_BUTTON,
|
||||
DARK_OAK_BUTTON,
|
||||
JUNGLE_BUTTON,
|
||||
OAK_BUTTON,
|
||||
POLISHED_BLACKSTONE_BUTTON,
|
||||
SPRUCE_BUTTON,
|
||||
STONE_BUTTON,
|
||||
WARPED_BUTTON,
|
||||
TORCH,
|
||||
SOUL_TORCH
|
||||
}).forEach((i) -> b.add(i.ordinal()));
|
||||
b.addAll(foliageCache);
|
||||
|
||||
return IntSets.unmodifiable(b);
|
||||
}
|
||||
|
||||
public static Material getMaterial(String bdx) {
|
||||
Material mat = getMaterialOrNull(bdx);
|
||||
private static IntSet buildLitCache() {
|
||||
IntSet b = new IntOpenHashSet();
|
||||
Arrays.stream(new Material[]{
|
||||
GLOWSTONE,
|
||||
END_ROD,
|
||||
SOUL_SAND,
|
||||
TORCH,
|
||||
REDSTONE_TORCH,
|
||||
SOUL_TORCH,
|
||||
REDSTONE_WALL_TORCH,
|
||||
WALL_TORCH,
|
||||
SOUL_WALL_TORCH,
|
||||
LANTERN,
|
||||
CANDLE,
|
||||
JACK_O_LANTERN,
|
||||
REDSTONE_LAMP,
|
||||
MAGMA_BLOCK,
|
||||
LIGHT,
|
||||
SHROOMLIGHT,
|
||||
SEA_LANTERN,
|
||||
SOUL_LANTERN,
|
||||
FIRE,
|
||||
SOUL_FIRE,
|
||||
SEA_PICKLE,
|
||||
BREWING_STAND,
|
||||
REDSTONE_ORE,
|
||||
}).forEach((i) -> b.add(i.ordinal()));
|
||||
|
||||
if (mat != null) {
|
||||
return mat;
|
||||
}
|
||||
|
||||
return AIR_MATERIAL;
|
||||
return IntSets.unmodifiable(b);
|
||||
}
|
||||
|
||||
public static Material getMaterialOrNull(String bdxx) {
|
||||
String bx = bdxx.trim().toUpperCase();
|
||||
private static IntSet buildStorageCache() {
|
||||
IntSet b = new IntOpenHashSet();
|
||||
Arrays.stream(new Material[]{
|
||||
CHEST,
|
||||
SMOKER,
|
||||
TRAPPED_CHEST,
|
||||
SHULKER_BOX,
|
||||
WHITE_SHULKER_BOX,
|
||||
ORANGE_SHULKER_BOX,
|
||||
MAGENTA_SHULKER_BOX,
|
||||
LIGHT_BLUE_SHULKER_BOX,
|
||||
YELLOW_SHULKER_BOX,
|
||||
LIME_SHULKER_BOX,
|
||||
PINK_SHULKER_BOX,
|
||||
GRAY_SHULKER_BOX,
|
||||
LIGHT_GRAY_SHULKER_BOX,
|
||||
CYAN_SHULKER_BOX,
|
||||
PURPLE_SHULKER_BOX,
|
||||
BLUE_SHULKER_BOX,
|
||||
BROWN_SHULKER_BOX,
|
||||
GREEN_SHULKER_BOX,
|
||||
RED_SHULKER_BOX,
|
||||
BLACK_SHULKER_BOX,
|
||||
BARREL,
|
||||
DISPENSER,
|
||||
DROPPER,
|
||||
HOPPER,
|
||||
FURNACE,
|
||||
BLAST_FURNACE
|
||||
}).forEach((i) -> b.add(i.ordinal()));
|
||||
|
||||
if (nullMaterialCache.contains(bx)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Material mat = materialCache.get(bx);
|
||||
|
||||
if (mat != null) {
|
||||
return mat;
|
||||
}
|
||||
|
||||
try {
|
||||
Material mm = Material.valueOf(bx);
|
||||
materialCache.put(bx, mm);
|
||||
return mm;
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
nullMaterialCache.add(bx);
|
||||
return null;
|
||||
}
|
||||
return IntSets.unmodifiable(b);
|
||||
}
|
||||
|
||||
public static boolean isSolid(BlockData mat) {
|
||||
return isSolid(mat.getMaterial());
|
||||
}
|
||||
private static IntSet buildStorageChestCache() {
|
||||
IntSet b = new IntOpenHashSet(storageCache);
|
||||
b.remove(SMOKER.ordinal());
|
||||
b.remove(FURNACE.ordinal());
|
||||
b.remove(BLAST_FURNACE.ordinal());
|
||||
|
||||
public static boolean isSolid(Material mat) {
|
||||
Boolean solid = solidCache.get(mat);
|
||||
|
||||
if (solid != null) {
|
||||
return solid;
|
||||
}
|
||||
|
||||
solid = mat.isSolid();
|
||||
solidCache.put(mat, solid);
|
||||
|
||||
return solid;
|
||||
}
|
||||
|
||||
public static BlockData getOrNull(String bdxf) {
|
||||
try {
|
||||
String bd = bdxf.trim();
|
||||
BlockData bdx = parseBlockData(bd);
|
||||
|
||||
if (bdx == null) {
|
||||
Iris.warn("Unknown Block Data '" + bd + "'");
|
||||
return AIR;
|
||||
}
|
||||
|
||||
return bdx;
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
Iris.warn("Unknown Block Data '" + bdxf + "'");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BlockData get(String bdxf) {
|
||||
BlockData bd = getOrNull(bdxf);
|
||||
|
||||
if (bd != null) {
|
||||
return bd;
|
||||
}
|
||||
|
||||
return AIR;
|
||||
}
|
||||
|
||||
private static BlockData parseBlockDataOrNull(String ix) {
|
||||
if (nullBlockDataCache.contains(ix)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
BlockData bb = blockDataCache.get(ix);
|
||||
|
||||
if (bb != null) {
|
||||
return bb;
|
||||
}
|
||||
BlockData bx = null;
|
||||
|
||||
if (ix.startsWith("oraxen:") && Iris.linkOraxen.supported()) {
|
||||
bx = Iris.linkOraxen.getBlockDataFor(ix.split("\\Q:\\E")[1]);
|
||||
}
|
||||
|
||||
if (bx == null) {
|
||||
bx = Bukkit.createBlockData(ix);
|
||||
}
|
||||
|
||||
if (bx instanceof Leaves && IrisSettings.get().getGenerator().preventLeafDecay) {
|
||||
((Leaves) bx).setPersistent(true);
|
||||
} else if (bx instanceof Leaves) {
|
||||
((Leaves) bx).setPersistent(false);
|
||||
}
|
||||
|
||||
blockDataCache.put(ix, bx);
|
||||
return bx;
|
||||
} catch (Exception e) {
|
||||
//Iris.reportError(e);
|
||||
Iris.debug("Failed to load block \"" + ix + "\"");
|
||||
|
||||
String block = ix.contains(":") ? ix.split(":")[1].toLowerCase() : ix.toLowerCase();
|
||||
String state = block.contains("[") ? block.split("\\[")[1].split("\\]")[0] : "";
|
||||
Map<String, String> stateMap = new HashMap<>();
|
||||
if (!state.equals("")) {
|
||||
Arrays.stream(state.split(",")).forEach(s -> {
|
||||
stateMap.put(s.split("=")[0], s.split("=")[1]);
|
||||
});
|
||||
}
|
||||
block = block.split("\\[")[0];
|
||||
|
||||
switch (block) {
|
||||
case "cauldron" -> block = "water_cauldron"; //Would fail to load if it has a level parameter
|
||||
case "grass_path" -> block = "dirt_path";
|
||||
case "concrete" -> block = "white_concrete";
|
||||
case "wool" -> block = "white_wool";
|
||||
case "beetroots" -> {
|
||||
if (stateMap.containsKey("age")) {
|
||||
String updated = stateMap.get("age");
|
||||
switch (updated) {
|
||||
case "7" -> updated = "3";
|
||||
case "3", "4", "5" -> updated = "2";
|
||||
case "1", "2" -> updated = "1";
|
||||
}
|
||||
stateMap.put("age", updated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> newStates = new HashMap<>();
|
||||
for (String key : stateMap.keySet()) { //Iterate through every state and check if its valid
|
||||
try {
|
||||
String newState = block + "[" + key + "=" + stateMap.get(key) + "]";
|
||||
Bukkit.createBlockData(newState);
|
||||
|
||||
//If we get to here, the state is okay so we can use it
|
||||
newStates.put(key, stateMap.get(key));
|
||||
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
//Combine all the "good" states again
|
||||
state = newStates.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining(","));
|
||||
if (!state.equals("")) state = "[" + state + "]";
|
||||
String newBlock = block + state;
|
||||
Iris.debug("Converting " + ix + " to " + newBlock);
|
||||
|
||||
try {
|
||||
BlockData bd = Bukkit.createBlockData(newBlock);
|
||||
blockDataCache.put(ix, bd);
|
||||
return bd;
|
||||
} catch (Throwable e1) {
|
||||
Iris.reportError(e1);
|
||||
}
|
||||
|
||||
nullBlockDataCache.add(ix);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockData parseBlockData(String ix) {
|
||||
BlockData bd = parseBlockDataOrNull(ix);
|
||||
|
||||
if (bd != null) {
|
||||
return bd;
|
||||
}
|
||||
|
||||
Iris.warn("Unknown Block Data: " + ix);
|
||||
|
||||
return AIR;
|
||||
}
|
||||
|
||||
public static boolean isStorage(BlockData mat) {
|
||||
Material mm = mat.getMaterial();
|
||||
Boolean f = storageCache.get(mm);
|
||||
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
|
||||
f = mm.equals(B.getMaterial("CHEST"))
|
||||
|| mm.equals(B.getMaterial("TRAPPED_CHEST"))
|
||||
|| mm.equals(B.getMaterial("SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("WHITE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("ORANGE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("MAGENTA_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIGHT_BLUE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("YELLOW_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIME_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("PINK_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("GRAY_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIGHT_GRAY_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("CYAN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("PURPLE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BLUE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BROWN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("GREEN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("RED_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BLACK_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BARREL"))
|
||||
|| mm.equals(B.getMaterial("DISPENSER"))
|
||||
|| mm.equals(B.getMaterial("DROPPER"))
|
||||
|| mm.equals(B.getMaterial("HOPPER"))
|
||||
|| mm.equals(B.getMaterial("FURNACE"))
|
||||
|| mm.equals(B.getMaterial("BLAST_FURNACE"))
|
||||
|| mm.equals(B.getMaterial("SMOKER"));
|
||||
storageCache.put(mm, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static boolean isStorageChest(BlockData mat) {
|
||||
if (!isStorage(mat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Material mm = mat.getMaterial();
|
||||
Boolean f = storageChestCache.get(mm);
|
||||
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
|
||||
f = mm.equals(B.getMaterial("CHEST"))
|
||||
|| mm.equals(B.getMaterial("TRAPPED_CHEST"))
|
||||
|| mm.equals(B.getMaterial("SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("WHITE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("ORANGE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("MAGENTA_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIGHT_BLUE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("YELLOW_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIME_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("PINK_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("GRAY_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("LIGHT_GRAY_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("CYAN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("PURPLE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BLUE_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BROWN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("GREEN_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("RED_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BLACK_SHULKER_BOX"))
|
||||
|| mm.equals(B.getMaterial("BARREL"))
|
||||
|| mm.equals(B.getMaterial("DISPENSER"))
|
||||
|| mm.equals(B.getMaterial("DROPPER"))
|
||||
|| mm.equals(B.getMaterial("HOPPER"));
|
||||
storageChestCache.put(mm, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static boolean isLit(BlockData mat) {
|
||||
Material mm = mat.getMaterial();
|
||||
Boolean f = litCache.get(mm);
|
||||
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
|
||||
f = mm.equals(B.getMaterial("GLOWSTONE"))
|
||||
|| mm.equals(B.getMaterial("END_ROD"))
|
||||
|| mm.equals(B.getMaterial("SOUL_SAND"))
|
||||
|| mm.equals(B.getMaterial("TORCH"))
|
||||
|| mm.equals(Material.REDSTONE_TORCH)
|
||||
|| mm.equals(B.getMaterial("SOUL_TORCH"))
|
||||
|| mm.equals(Material.REDSTONE_WALL_TORCH)
|
||||
|| mm.equals(Material.WALL_TORCH)
|
||||
|| mm.equals(B.getMaterial("SOUL_WALL_TORCH"))
|
||||
|| mm.equals(B.getMaterial("LANTERN"))
|
||||
|| mm.equals(Material.JACK_O_LANTERN)
|
||||
|| mm.equals(Material.REDSTONE_LAMP)
|
||||
|| mm.equals(Material.MAGMA_BLOCK)
|
||||
|| mm.equals(B.getMaterial("SHROOMLIGHT"))
|
||||
|| mm.equals(B.getMaterial("SEA_LANTERN"))
|
||||
|| mm.equals(B.getMaterial("SOUL_LANTERN"))
|
||||
|| mm.equals(Material.FIRE)
|
||||
|| mm.equals(B.getMaterial("SOUL_FIRE"))
|
||||
|| mm.equals(B.getMaterial("SEA_PICKLE"))
|
||||
|| mm.equals(Material.BREWING_STAND)
|
||||
|| mm.equals(Material.REDSTONE_ORE);
|
||||
litCache.put(mm, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static boolean isUpdatable(BlockData mat) {
|
||||
Boolean u = updatableCache.get(mat.getMaterial());
|
||||
|
||||
if (u != null) {
|
||||
return u;
|
||||
}
|
||||
|
||||
u = isLit(mat) || isStorage(mat);
|
||||
updatableCache.put(mat.getMaterial(), u);
|
||||
return u;
|
||||
}
|
||||
|
||||
public static boolean isFoliage(Material d) {
|
||||
return isFoliage(d.createBlockData());
|
||||
}
|
||||
|
||||
public static boolean isFoliage(BlockData d) {
|
||||
Boolean f = foliageCache.get(d.getMaterial());
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
|
||||
if (isFluid(d) || isAir(d) || isSolid(d)) {
|
||||
foliageCache.put(d.getMaterial(), false);
|
||||
return false;
|
||||
}
|
||||
|
||||
Material mat = d.getMaterial();
|
||||
f = mat.equals(Material.POPPY)
|
||||
|| mat.equals(Material.DANDELION)
|
||||
|| mat.equals(B.getMaterial("CORNFLOWER"))
|
||||
|| mat.equals(B.getMaterial("SWEET_BERRY_BUSH"))
|
||||
|| mat.equals(B.getMaterial("CRIMSON_ROOTS"))
|
||||
|| mat.equals(B.getMaterial("WARPED_ROOTS"))
|
||||
|| mat.equals(B.getMaterial("NETHER_SPROUTS"))
|
||||
|| mat.equals(B.getMaterial("ALLIUM"))
|
||||
|| mat.equals(B.getMaterial("AZURE_BLUET"))
|
||||
|| mat.equals(B.getMaterial("BLUE_ORCHID"))
|
||||
|| mat.equals(B.getMaterial("POPPY"))
|
||||
|| mat.equals(B.getMaterial("DANDELION"))
|
||||
|| mat.equals(B.getMaterial("OXEYE_DAISY"))
|
||||
|| mat.equals(B.getMaterial("LILY_OF_THE_VALLEY"))
|
||||
|| mat.equals(B.getMaterial("WITHER_ROSE"))
|
||||
|| mat.equals(Material.DARK_OAK_SAPLING)
|
||||
|| mat.equals(Material.ACACIA_SAPLING)
|
||||
|| mat.equals(Material.JUNGLE_SAPLING)
|
||||
|| mat.equals(Material.BIRCH_SAPLING)
|
||||
|| mat.equals(Material.SPRUCE_SAPLING)
|
||||
|| mat.equals(Material.OAK_SAPLING)
|
||||
|| mat.equals(Material.ORANGE_TULIP)
|
||||
|| mat.equals(Material.PINK_TULIP)
|
||||
|| mat.equals(Material.RED_TULIP)
|
||||
|| mat.equals(Material.WHITE_TULIP)
|
||||
|| mat.equals(Material.FERN)
|
||||
|| mat.equals(Material.LARGE_FERN)
|
||||
|| mat.equals(Material.GRASS)
|
||||
|| mat.equals(Material.TALL_GRASS);
|
||||
foliageCache.put(d.getMaterial(), f);
|
||||
return f;
|
||||
return IntSets.unmodifiable(b);
|
||||
}
|
||||
|
||||
public static boolean canPlaceOnto(Material mat, Material onto) {
|
||||
String key = mat.name() + "" + onto.name();
|
||||
|
||||
if (isFoliage(mat)) {
|
||||
if (!isFoliagePlantable(onto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (onto.equals(Material.AIR) || onto.equals(B.getMaterial("CAVE_AIR")) || onto.equals(B.getMaterial("VOID_AIR"))) {
|
||||
if (onto.equals(Material.AIR) ||
|
||||
onto.equals(B.getMaterial("CAVE_AIR"))
|
||||
|| onto.equals(B.getMaterial("VOID_AIR"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -447,86 +256,6 @@ public class B {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isDecorant(BlockData m) {
|
||||
Material mm = m.getMaterial();
|
||||
Boolean f = decorantCache.get(mm);
|
||||
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
|
||||
f = mm.equals(Material.GRASS)
|
||||
|| mm.equals(Material.TALL_GRASS)
|
||||
|| mm.equals(Material.FERN)
|
||||
|| mm.equals(Material.LARGE_FERN)
|
||||
|| mm.equals(B.getMaterial("CORNFLOWER"))
|
||||
|| mm.equals(Material.SUNFLOWER)
|
||||
|| mm.equals(Material.CHORUS_FLOWER)
|
||||
|| mm.equals(Material.POPPY)
|
||||
|| mm.equals(Material.DANDELION)
|
||||
|| mm.equals(Material.OXEYE_DAISY)
|
||||
|| mm.equals(Material.ORANGE_TULIP)
|
||||
|| mm.equals(Material.PINK_TULIP)
|
||||
|| mm.equals(Material.RED_TULIP)
|
||||
|| mm.equals(Material.WHITE_TULIP)
|
||||
|| mm.equals(Material.LILAC)
|
||||
|| mm.equals(Material.DEAD_BUSH)
|
||||
|| mm.equals(B.getMaterial("SWEET_BERRY_BUSH"))
|
||||
|| mm.equals(Material.ROSE_BUSH)
|
||||
|| mm.equals(B.getMaterial("WITHER_ROSE"))
|
||||
|| mm.equals(Material.ALLIUM)
|
||||
|| mm.equals(Material.BLUE_ORCHID)
|
||||
|| mm.equals(B.getMaterial("LILY_OF_THE_VALLEY"))
|
||||
|| mm.equals(B.getMaterial("CRIMSON_FUNGUS"))
|
||||
|| mm.equals(B.getMaterial("WARPED_FUNGUS"))
|
||||
|| mm.equals(Material.RED_MUSHROOM)
|
||||
|| mm.equals(Material.BROWN_MUSHROOM)
|
||||
|| mm.equals(B.getMaterial("CRIMSON_ROOTS"))
|
||||
|| mm.equals(B.getMaterial("AZURE_BLUET"))
|
||||
|| mm.equals(B.getMaterial("WEEPING_VINES"))
|
||||
|| mm.equals(B.getMaterial("WEEPING_VINES_PLANT"))
|
||||
|| mm.equals(B.getMaterial("WARPED_ROOTS"))
|
||||
|| mm.equals(B.getMaterial("NETHER_SPROUTS"))
|
||||
|| mm.equals(B.getMaterial("TWISTING_VINES"))
|
||||
|| mm.equals(B.getMaterial("TWISTING_VINES_PLANT"))
|
||||
|| mm.equals(Material.SUGAR_CANE)
|
||||
|| mm.equals(Material.WHEAT)
|
||||
|| mm.equals(Material.POTATOES)
|
||||
|| mm.equals(Material.CARROTS)
|
||||
|| mm.equals(Material.BEETROOTS)
|
||||
|| mm.equals(Material.NETHER_WART)
|
||||
|| mm.equals(B.getMaterial("SEA_PICKLE"))
|
||||
|| mm.equals(B.getMaterial("SEAGRASS"))
|
||||
|| mm.equals(B.getMaterial("ACACIA_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("BIRCH_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("CRIMSON_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("DARK_OAK_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("JUNGLE_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("OAK_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("POLISHED_BLACKSTONE_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("SPRUCE_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("STONE_BUTTON"))
|
||||
|| mm.equals(B.getMaterial("WARPED_BUTTON"))
|
||||
|| mm.equals(Material.TORCH)
|
||||
|| mm.equals(B.getMaterial("SOUL_TORCH"));
|
||||
decorantCache.put(mm, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static KList<BlockData> get(KList<String> find) {
|
||||
KList<BlockData> b = new KList<>();
|
||||
|
||||
for (String i : find) {
|
||||
BlockData bd = get(i);
|
||||
|
||||
if (bd != null) {
|
||||
b.add(bd);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean isFoliagePlantable(BlockData d) {
|
||||
return d.getMaterial().equals(Material.GRASS_BLOCK)
|
||||
|| d.getMaterial().equals(Material.ROOTED_DIRT)
|
||||
@ -543,6 +272,207 @@ public class B {
|
||||
|| d.equals(Material.PODZOL);
|
||||
}
|
||||
|
||||
public static boolean isWater(BlockData b) {
|
||||
return b.getMaterial().equals(Material.WATER);
|
||||
}
|
||||
|
||||
public static BlockData getAir() {
|
||||
return AIR;
|
||||
}
|
||||
|
||||
public static Material getMaterialOrNull(String bdx) {
|
||||
try {
|
||||
return Material.valueOf(bdx.trim().toUpperCase());
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
if(clw.flip())
|
||||
{
|
||||
Iris.warn("Unknown Material: " + bdx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Material getMaterial(String bdx) {
|
||||
Material m = getMaterialOrNull(bdx);
|
||||
|
||||
if(m == null)
|
||||
{
|
||||
return AIR_MATERIAL;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public static boolean isSolid(BlockData mat) {
|
||||
return mat.getMaterial().isSolid();
|
||||
}
|
||||
|
||||
public static BlockData getOrNull(String bdxf) {
|
||||
try {
|
||||
String bd = bdxf.trim();
|
||||
BlockData bdx = parseBlockData(bd);
|
||||
|
||||
if (bdx == null) {
|
||||
if(clw.flip())
|
||||
{
|
||||
Iris.warn("Unknown Block Data '" + bd + "'");
|
||||
}
|
||||
return AIR;
|
||||
}
|
||||
|
||||
return bdx;
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
if(clw.flip())
|
||||
{
|
||||
Iris.warn("Unknown Block Data '" + bdxf + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BlockData get(String bdxf) {
|
||||
BlockData bd = getOrNull(bdxf);
|
||||
|
||||
if (bd != null) {
|
||||
return bd;
|
||||
}
|
||||
|
||||
return AIR;
|
||||
}
|
||||
|
||||
private static BlockData parseBlockData(String ix) {
|
||||
try {
|
||||
BlockData bb = blockDataCache.get(ix);
|
||||
|
||||
if (bb != null) {
|
||||
return bb;
|
||||
}
|
||||
|
||||
BlockData bx = null;
|
||||
|
||||
if (ix.startsWith("oraxen:") && Iris.linkOraxen.supported()) {
|
||||
bx = Iris.linkOraxen.getBlockDataFor(ix.split("\\Q:\\E")[1]);
|
||||
}
|
||||
|
||||
if (bx == null) {
|
||||
bx = Bukkit.createBlockData(ix);
|
||||
}
|
||||
|
||||
if (bx instanceof Leaves && IrisSettings.get().getGenerator().preventLeafDecay) {
|
||||
((Leaves) bx).setPersistent(true);
|
||||
} else if (bx instanceof Leaves) {
|
||||
((Leaves) bx).setPersistent(false);
|
||||
}
|
||||
|
||||
blockDataCache.put(ix, bx);
|
||||
return bx;
|
||||
} catch (Throwable e) {
|
||||
if(clw.flip())
|
||||
{
|
||||
Iris.warn("Unknown Block Data: " + ix);
|
||||
}
|
||||
|
||||
String block = ix.contains(":") ? ix.split(":")[1].toLowerCase() : ix.toLowerCase();
|
||||
String state = block.contains("[") ? block.split("\\Q[\\E")[1].split("\\Q]\\E")[0] : "";
|
||||
Map<String, String> stateMap = new HashMap<>();
|
||||
if (!state.equals("")) {
|
||||
Arrays.stream(state.split(",")).forEach(s -> stateMap.put(s.split("=")[0], s.split("=")[1]));
|
||||
}
|
||||
block = block.split("\\Q[\\E")[0];
|
||||
|
||||
switch (block) {
|
||||
case "cauldron" -> block = "water_cauldron";
|
||||
case "grass_path" -> block = "dirt_path";
|
||||
case "concrete" -> block = "white_concrete";
|
||||
case "wool" -> block = "white_wool";
|
||||
case "beetroots" -> {
|
||||
if (stateMap.containsKey("age")) {
|
||||
String updated = stateMap.get("age");
|
||||
switch (updated) {
|
||||
case "7" -> updated = "3";
|
||||
case "3", "4", "5" -> updated = "2";
|
||||
case "1", "2" -> updated = "1";
|
||||
}
|
||||
stateMap.put("age", updated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> newStates = new HashMap<>();
|
||||
for (String key : stateMap.keySet()) { //Iterate through every state and check if its valid
|
||||
try {
|
||||
String newState = block + "[" + key + "=" + stateMap.get(key) + "]";
|
||||
Bukkit.createBlockData(newState);
|
||||
newStates.put(key, stateMap.get(key));
|
||||
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
//Combine all the "good" states again
|
||||
state = newStates.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining(","));
|
||||
if (!state.equals("")) state = "[" + state + "]";
|
||||
String newBlock = block + state;
|
||||
Iris.debug("Converting " + ix + " to " + newBlock);
|
||||
|
||||
try {
|
||||
BlockData bd = Bukkit.createBlockData(newBlock);
|
||||
blockDataCache.put(ix, bd);
|
||||
return bd;
|
||||
} catch (Throwable e1) {
|
||||
Iris.reportError(e1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isStorage(BlockData mat) {
|
||||
return storageCache.contains(mat.getMaterial().ordinal());
|
||||
}
|
||||
|
||||
public static boolean isStorageChest(BlockData mat) {
|
||||
return storageChestCache.contains(mat.getMaterial().ordinal());
|
||||
}
|
||||
|
||||
public static boolean isLit(BlockData mat) {
|
||||
return litCache.contains(mat.getMaterial().ordinal());
|
||||
}
|
||||
|
||||
public static boolean isUpdatable(BlockData mat) {
|
||||
return isLit(mat) || isStorage(mat);
|
||||
}
|
||||
|
||||
public static boolean isFoliage(Material d) {
|
||||
return foliageCache.contains(d.ordinal());
|
||||
}
|
||||
|
||||
public static boolean isFoliage(BlockData d) {
|
||||
return isFoliage(d.getMaterial());
|
||||
}
|
||||
|
||||
public static boolean isDecorant(BlockData m) {
|
||||
return decorantCache.contains(m.getMaterial().ordinal());
|
||||
}
|
||||
|
||||
public static KList<BlockData> get(KList<String> find) {
|
||||
KList<BlockData> b = new KList<>();
|
||||
|
||||
for (String i : find) {
|
||||
BlockData bd = get(i);
|
||||
|
||||
if (bd != null) {
|
||||
b.add(bd);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean isFluid(BlockData d) {
|
||||
return d.getMaterial().equals(Material.WATER) || d.getMaterial().equals(Material.LAVA);
|
||||
}
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.util.hunk.storage;
|
||||
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.function.Consumer4;
|
||||
import com.volmit.iris.util.function.Consumer4IO;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings({"DefaultAnnotationParam", "Lombok"})
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class MappedSyncHunk<T> extends StorageHunk<T> implements Hunk<T> {
|
||||
private final Map<Integer, T> data;
|
||||
|
||||
public MappedSyncHunk(int w, int h, int d) {
|
||||
super(w, h, d);
|
||||
data = new HashMap<>();
|
||||
}
|
||||
|
||||
public int getEntryCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
public boolean isMapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
synchronized(data)
|
||||
{
|
||||
return data.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRaw(int x, int y, int z, T t) {
|
||||
synchronized(data) {
|
||||
if (t == null) {
|
||||
data.remove(index(x, y, z));
|
||||
return;
|
||||
}
|
||||
|
||||
data.put(index(x, y, z), t);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer index(int x, int y, int z) {
|
||||
return (z * getWidth() * getHeight()) + (y * getWidth()) + x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Hunk<T> iterateSync(Consumer4<Integer, Integer, Integer, T> c) {
|
||||
synchronized(data)
|
||||
{
|
||||
int idx, z;
|
||||
|
||||
for (Map.Entry<Integer, T> g : data.entrySet()) {
|
||||
idx = g.getKey();
|
||||
z = idx / (getWidth() * getHeight());
|
||||
idx -= (z * getWidth() * getHeight());
|
||||
c.accept(idx % getWidth(), idx / getWidth(), z, g.getValue());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Hunk<T> iterateSyncIO(Consumer4IO<Integer, Integer, Integer, T> c) throws IOException {
|
||||
synchronized(data)
|
||||
{
|
||||
int idx, z;
|
||||
|
||||
for (Map.Entry<Integer, T> g : data.entrySet()) {
|
||||
idx = g.getKey();
|
||||
z = idx / (getWidth() * getHeight());
|
||||
idx -= (z * getWidth() * getHeight());
|
||||
c.accept(idx % getWidth(), idx / getWidth(), z, g.getValue());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void empty(T b) {
|
||||
synchronized(data)
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getRaw(int x, int y, int z) {
|
||||
synchronized(data)
|
||||
{
|
||||
return data.get(index(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,13 @@
|
||||
|
||||
package com.volmit.iris.util.mantle;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.mantle.MantleWriter;
|
||||
import com.volmit.iris.engine.object.basic.IrisPosition;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
@ -28,19 +33,23 @@ import com.volmit.iris.util.documentation.RegionCoordinates;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.function.Consumer4;
|
||||
import com.volmit.iris.util.math.INode;
|
||||
import com.volmit.iris.util.math.KochanekBartelsInterpolation;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.PathInterpolation;
|
||||
import com.volmit.iris.util.matter.Matter;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.HyperLock;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@ -75,10 +84,17 @@ public class Mantle {
|
||||
unload = new KSet<>();
|
||||
loadedRegions = new KMap<>();
|
||||
lastUse = new KMap<>();
|
||||
ioBurst = new MultiBurst("Iris Mantle[" + dataFolder.hashCode() + "]", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors() / 2);
|
||||
ioBurst = MultiBurst.burst;
|
||||
Iris.debug("Opened The Mantle " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise a flag if it is lowered currently, If the flag was raised, execute the runnable
|
||||
* @param x the chunk x
|
||||
* @param z the chunk z
|
||||
* @param flag the flag to raise
|
||||
* @param r the runnable to fire if the flag is now raised (and was previously lowered)
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public void raiseFlag(int x, int z, MantleFlag flag, Runnable r) {
|
||||
if (!hasFlag(x, z, flag)) {
|
||||
@ -87,6 +103,27 @@ public class Mantle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a cached writer which only contains cached chunks.
|
||||
* This avoids locking on regions when writing to lots of chunks
|
||||
* @param x the x chunk
|
||||
* @param z the z chunk
|
||||
* @param radius the radius chunks
|
||||
* @return the writer
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public MantleWriter write(EngineMantle engineMantle, int x, int z, int radius)
|
||||
{
|
||||
return new MantleWriter(engineMantle, this, x, z, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower a flag if it is raised. If the flag was lowered (meaning it was previously raised), execute the runnable
|
||||
* @param x the chunk x
|
||||
* @param z the chunk z
|
||||
* @param flag the flag to lower
|
||||
* @param r the runnable that is fired if the flag was raised but is now lowered
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public void lowerFlag(int x, int z, MantleFlag flag, Runnable r) {
|
||||
if (hasFlag(x, z, flag)) {
|
||||
@ -95,35 +132,69 @@ public class Mantle {
|
||||
}
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
public MantleChunk getChunk(int x, int z)
|
||||
{
|
||||
return get(x>>5, z>>5).getOrCreate(x & 31, z & 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag or unflag a chunk
|
||||
* @param x the chunk x
|
||||
* @param z the chunk z
|
||||
* @param flag the flag
|
||||
* @param flagged should it be set to flagged or not
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public void flag(int x, int z, MantleFlag flag, boolean flagged) {
|
||||
get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).flag(flag, flagged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check very quickly if a tectonic plate exists via cached or the file system
|
||||
* @param x the x region coordinate
|
||||
* @param z the z region coordinate
|
||||
* @return true if it exists
|
||||
*/
|
||||
@RegionCoordinates
|
||||
public boolean hasTectonicPlate(int x, int z)
|
||||
{
|
||||
Long k = key(x, z);
|
||||
return loadedRegions.containsKey(k) || fileForRegion(dataFolder, k).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate data in a chunk
|
||||
* @param x the chunk x
|
||||
* @param z the chunk z
|
||||
* @param type the type of data to iterate
|
||||
* @param iterator the iterator (x,y,z,data) -> do stuff
|
||||
* @param <T> the type of data to iterate
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public <T> void iterateChunk(int x, int z, Class<T> type, Consumer4<Integer, Integer, Integer, T> iterator, MantleFlag... requiredFlags) {
|
||||
for (MantleFlag i : requiredFlags) {
|
||||
if (!hasFlag(x, z, i)) {
|
||||
return;
|
||||
}
|
||||
public <T> void iterateChunk(int x, int z, Class<T> type, Consumer4<Integer, Integer, Integer, T> iterator) {
|
||||
if(!hasTectonicPlate(x >> 5, z >> 5))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).iterate(type, iterator);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
public <T> void iterateChunk(int x, int z, Class<T> type, Consumer4<Integer, Integer, Integer, T> iterator, BurstExecutor e, MantleFlag... requiredFlags) {
|
||||
for (MantleFlag i : requiredFlags) {
|
||||
if (!hasFlag(x, z, i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).iterate(type, iterator, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this chunk have a flag on it?
|
||||
* @param x the x
|
||||
* @param z the z
|
||||
* @param flag the flag to test
|
||||
* @return true if it's flagged
|
||||
*/
|
||||
@ChunkCoordinates
|
||||
public boolean hasFlag(int x, int z, MantleFlag flag) {
|
||||
if(!hasTectonicPlate(x >> 5, z >> 5))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).isFlagged(flag);
|
||||
}
|
||||
|
||||
@ -151,11 +222,20 @@ public class Mantle {
|
||||
return;
|
||||
}
|
||||
|
||||
Matter matter = get((x >> 4) >> 5, (z >> 4) >> 5)
|
||||
.getOrCreate((x >> 4) & 31, (z >> 4) & 31)
|
||||
.getOrCreate(y >> 4);
|
||||
matter.slice(matter.getClass(t))
|
||||
.set(x & 15, y & 15, z & 15, t);
|
||||
if(t instanceof IrisFeaturePositional)
|
||||
{
|
||||
get((x >> 4) >> 5, (z >> 4) >> 5)
|
||||
.getOrCreate((x >> 4) & 31, (z >> 4) & 31).addFeature((IrisFeaturePositional) t);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Matter matter = get((x >> 4) >> 5, (z >> 4) >> 5)
|
||||
.getOrCreate((x >> 4) & 31, (z >> 4) & 31)
|
||||
.getOrCreate(y >> 4);
|
||||
matter.slice(matter.getClass(t))
|
||||
.set(x & 15, y & 15, z & 15, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +260,12 @@ public class Mantle {
|
||||
throw new RuntimeException("The Mantle is closed");
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
if(!hasTectonicPlate((x >> 4) >> 5, (z >> 4) >> 5))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (y < 0 || y >= worldHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -190,6 +275,10 @@ public class Mantle {
|
||||
.get(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this mantle closed
|
||||
* @return true if it is
|
||||
*/
|
||||
public boolean isClosed()
|
||||
{
|
||||
return closed.get();
|
||||
@ -228,7 +317,6 @@ public class Mantle {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
|
||||
ioBurst.shutdownNow();
|
||||
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
@ -324,7 +412,7 @@ public class Mantle {
|
||||
* @return the future of a tectonic plate.
|
||||
*/
|
||||
@RegionCoordinates
|
||||
private CompletableFuture<TectonicPlate> getSafe(int x, int z) {
|
||||
private Future<TectonicPlate> getSafe(int x, int z) {
|
||||
Long k = key(x, z);
|
||||
TectonicPlate p = loadedRegions.get(k);
|
||||
|
||||
@ -367,17 +455,39 @@ public class Mantle {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file for a region
|
||||
* @param folder the folder
|
||||
* @param x the x coord
|
||||
* @param z the z coord
|
||||
* @return the file
|
||||
*/
|
||||
public static File fileForRegion(File folder, int x, int z) {
|
||||
return fileForRegion(folder, key(x, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file for the given region
|
||||
* @param folder the data folder
|
||||
* @param key the region key
|
||||
* @return the file
|
||||
*/
|
||||
public static File fileForRegion(File folder, Long key) {
|
||||
String id = UUID.nameUUIDFromBytes(("TectonicPlate:" + key).getBytes(StandardCharsets.UTF_8)).toString();
|
||||
File f = new File(folder, id.substring(0, 2) + "/" + id.split("\\Q-\\E")[3] + "/" + id + ".ttp");
|
||||
f.getParentFile().mkdirs();
|
||||
if(!f.getParentFile().exists())
|
||||
{
|
||||
f.getParentFile().mkdirs();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the long value representing a chunk or region coordinate
|
||||
* @param x the x
|
||||
* @param z the z
|
||||
* @return the value
|
||||
*/
|
||||
public static Long key(int x, int z) {
|
||||
return Cache.key(x, z);
|
||||
}
|
||||
@ -385,4 +495,440 @@ public class Mantle {
|
||||
public void saveAll() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sphere into the mantle
|
||||
* @param cx the center x
|
||||
* @param cy the center y
|
||||
* @param cz the center z
|
||||
* @param radius the radius of this sphere
|
||||
* @param fill should it be filled? or just the outer shell?
|
||||
* @param data the data to set
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setSphere(int cx, int cy, int cz, double radius, boolean fill, T data)
|
||||
{
|
||||
setElipsoid(cx, cy, cz, radius, radius, radius, fill, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an elipsoid into the mantle
|
||||
* @param cx the center x
|
||||
* @param cy the center y
|
||||
* @param cz the center z
|
||||
* @param rx the x radius
|
||||
* @param ry the y radius
|
||||
* @param rz the z radius
|
||||
* @param fill should it be filled or just the outer shell?
|
||||
* @param data the data to set
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setElipsoid(int cx, int cy, int cz, double rx, double ry, double rz, boolean fill, T data)
|
||||
{
|
||||
rx += 0.5;
|
||||
ry += 0.5;
|
||||
rz += 0.5;
|
||||
final double invRadiusX = 1 / rx;
|
||||
final double invRadiusY = 1 / ry;
|
||||
final double invRadiusZ = 1 / rz;
|
||||
final int ceilRadiusX = (int) Math.ceil(rx);
|
||||
final int ceilRadiusY = (int) Math.ceil(ry);
|
||||
final int ceilRadiusZ = (int) Math.ceil(rz);
|
||||
double nextXn = 0;
|
||||
|
||||
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
|
||||
final double xn = nextXn;
|
||||
nextXn = (x + 1) * invRadiusX;
|
||||
double nextYn = 0;
|
||||
forY: for (int y = 0; y <= ceilRadiusY; ++y) {
|
||||
final double yn = nextYn;
|
||||
nextYn = (y + 1) * invRadiusY;
|
||||
double nextZn = 0;
|
||||
for (int z = 0; z <= ceilRadiusZ; ++z) {
|
||||
final double zn = nextZn;
|
||||
nextZn = (z + 1) * invRadiusZ;
|
||||
|
||||
double distanceSq = lengthSq(xn, yn, zn);
|
||||
if (distanceSq > 1) {
|
||||
if (z == 0) {
|
||||
if (y == 0) {
|
||||
break forX;
|
||||
}
|
||||
break forY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fill) {
|
||||
if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
set(x + cx,y + cy,z + cz, data);
|
||||
set(-x + cx,y + cy,z + cz, data);
|
||||
set(x + cx,-y + cy,z + cz, data);
|
||||
set(x + cx,y + cy,-z + cz, data);
|
||||
set(-x + cx,y + cy,-z + cz, data);
|
||||
set(-x + cx,-y + cy,z + cz, data);
|
||||
set(x + cx,-y + cy,-z + cz, data);
|
||||
set(-x + cx,y + cy,-z + cz, data);
|
||||
set(-x + cx,-y + cy,-z + cz, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cuboid of data in the mantle
|
||||
* @param x1 the min x
|
||||
* @param y1 the min y
|
||||
* @param z1 the min z
|
||||
* @param x2 the max x
|
||||
* @param y2 the max y
|
||||
* @param z2 the max z
|
||||
* @param data the data to set
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setCuboid(int x1, int y1, int z1, int x2, int y2, int z2, T data)
|
||||
{
|
||||
int j,k;
|
||||
|
||||
for(int i = x1; i <= x2; i++)
|
||||
{
|
||||
for(j = x1; j <= x2; j++)
|
||||
{
|
||||
for(k = x1; k <= x2; k++)
|
||||
{
|
||||
set(i,j,k,data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pyramid of data in the mantle
|
||||
* @param cx the center x
|
||||
* @param cy the base y
|
||||
* @param cz the center z
|
||||
* @param data the data to set
|
||||
* @param size the size of the pyramid (width of base & height)
|
||||
* @param filled should it be filled or hollow
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public <T> void setPyramid(int cx, int cy, int cz, T data, int size, boolean filled) {
|
||||
int height = size;
|
||||
|
||||
for (int y = 0; y <= height; ++y) {
|
||||
size--;
|
||||
for (int x = 0; x <= size; ++x) {
|
||||
for (int z = 0; z <= size; ++z) {
|
||||
if ((filled && z <= size && x <= size) || z == size || x == size) {
|
||||
set(x + cx, y + cy, z + cz, data);
|
||||
set(-x + cx, y + cy, z + cz, data);
|
||||
set(x + cx, y + cy, -z + cz, data);
|
||||
set(-x + cx, y + cy, -z + cz, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a 3d tube spline interpolated with Kochanek Bartels
|
||||
* @param nodevectors the vector points
|
||||
* @param radius the radius
|
||||
* @param filled if it should be filled or hollow
|
||||
* @param data the data to set
|
||||
*/
|
||||
public <T> void setSpline(List<Vector> nodevectors, double radius, boolean filled, T data) {
|
||||
setSpline(nodevectors, 0, 0, 0, 10, radius, filled, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a 3d tube spline interpolated with Kochanek Bartels
|
||||
* @param nodevectors the spline points
|
||||
* @param tension the tension 0
|
||||
* @param bias the bias 0
|
||||
* @param continuity the continuity 0
|
||||
* @param quality the quality 10
|
||||
* @param radius the radius
|
||||
* @param filled filled or hollow
|
||||
* @param data the data to set
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setSpline(List<Vector> nodevectors, double tension, double bias, double continuity, double quality, double radius, boolean filled, T data) {
|
||||
Set<IrisPosition> vset = new KSet<>();
|
||||
List<INode> nodes = new ArrayList<>(nodevectors.size());
|
||||
PathInterpolation interpol = new KochanekBartelsInterpolation();
|
||||
|
||||
for (Vector nodevector : nodevectors) {
|
||||
INode n = new INode(nodevector);
|
||||
n.setTension(tension);
|
||||
n.setBias(bias);
|
||||
n.setContinuity(continuity);
|
||||
nodes.add(n);
|
||||
}
|
||||
|
||||
interpol.setNodes(nodes);
|
||||
double splinelength = interpol.arcLength(0, 1);
|
||||
for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) {
|
||||
Vector tipv = interpol.getPosition(loop);
|
||||
vset.add(new IrisPosition(tipv.toBlockVector()));
|
||||
}
|
||||
|
||||
vset = getBallooned(vset, radius);
|
||||
if (!filled) {
|
||||
vset = getHollowed(vset);
|
||||
}
|
||||
|
||||
set(vset, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a 3d line
|
||||
* @param a the first point
|
||||
* @param b the second point
|
||||
* @param radius the radius
|
||||
* @param filled hollow or filled?
|
||||
* @param data the data
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setLine(IrisPosition a, IrisPosition b, double radius, boolean filled, T data)
|
||||
{
|
||||
setLine(ImmutableList.of(a, b), radius, filled, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lines for points
|
||||
* @param vectors the points
|
||||
* @param radius the radius
|
||||
* @param filled hollow or filled?
|
||||
* @param data the data to set
|
||||
* @param <T> the type of data to apply to the mantle
|
||||
*/
|
||||
public <T> void setLine(List<IrisPosition> vectors, double radius, boolean filled, T data) {
|
||||
Set<IrisPosition> vset = new KSet<>();
|
||||
|
||||
for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) {
|
||||
IrisPosition pos1 = vectors.get(i);
|
||||
IrisPosition pos2 = vectors.get(i + 1);
|
||||
int x1 = pos1.getX();
|
||||
int y1 = pos1.getY();
|
||||
int z1 = pos1.getZ();
|
||||
int x2 = pos2.getX();
|
||||
int y2 = pos2.getY();
|
||||
int z2 = pos2.getZ();
|
||||
int tipx = x1;
|
||||
int tipy = y1;
|
||||
int tipz = z1;
|
||||
int dx = Math.abs(x2 - x1);
|
||||
int dy = Math.abs(y2 - y1);
|
||||
int dz = Math.abs(z2 - z1);
|
||||
|
||||
if (dx + dy + dz == 0) {
|
||||
vset.add(new IrisPosition(tipx, tipy, tipz));
|
||||
continue;
|
||||
}
|
||||
|
||||
int dMax = Math.max(Math.max(dx, dy), dz);
|
||||
if (dMax == dx) {
|
||||
for (int domstep = 0; domstep <= dx; domstep++) {
|
||||
tipx = x1 + domstep * (x2 - x1 > 0 ? 1 : -1);
|
||||
tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dx) * (y2 - y1 > 0 ? 1 : -1));
|
||||
tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dx) * (z2 - z1 > 0 ? 1 : -1));
|
||||
|
||||
vset.add(new IrisPosition(tipx, tipy, tipz));
|
||||
}
|
||||
} else if (dMax == dy) {
|
||||
for (int domstep = 0; domstep <= dy; domstep++) {
|
||||
tipy = y1 + domstep * (y2 - y1 > 0 ? 1 : -1);
|
||||
tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dy) * (x2 - x1 > 0 ? 1 : -1));
|
||||
tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dy) * (z2 - z1 > 0 ? 1 : -1));
|
||||
|
||||
vset.add(new IrisPosition(tipx, tipy, tipz));
|
||||
}
|
||||
} else /* if (dMax == dz) */ {
|
||||
for (int domstep = 0; domstep <= dz; domstep++) {
|
||||
tipz = z1 + domstep * (z2 - z1 > 0 ? 1 : -1);
|
||||
tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dz) * (y2 - y1 > 0 ? 1 : -1));
|
||||
tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dz) * (x2 - x1 > 0 ? 1 : -1));
|
||||
|
||||
vset.add(new IrisPosition(tipx, tipy, tipz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vset = getBallooned(vset, radius);
|
||||
|
||||
if (!filled) {
|
||||
vset = getHollowed(vset);
|
||||
}
|
||||
|
||||
set(vset, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cylinder in the mantle
|
||||
* @param cx the center x
|
||||
* @param cy the base y
|
||||
* @param cz the center z
|
||||
* @param data the data to set
|
||||
* @param radius the radius
|
||||
* @param height the height of the cyl
|
||||
* @param filled filled or not
|
||||
*/
|
||||
public <T> void setCylinder(int cx, int cy, int cz, T data, double radius, int height, boolean filled){
|
||||
setCylinder(cx, cy, cz, data, radius, radius, height, filled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cylinder in the mantle
|
||||
* @param cx the center x
|
||||
* @param cy the base y
|
||||
* @param cz the center z
|
||||
* @param data the data to set
|
||||
* @param radiusX the x radius
|
||||
* @param radiusZ the z radius
|
||||
* @param height the height of this cyl
|
||||
* @param filled filled or hollow?
|
||||
*/
|
||||
public <T> void setCylinder(int cx, int cy, int cz, T data, double radiusX, double radiusZ, int height, boolean filled) {
|
||||
int affected = 0;
|
||||
radiusX += 0.5;
|
||||
radiusZ += 0.5;
|
||||
|
||||
if (height == 0) {
|
||||
return;
|
||||
} else if (height < 0) {
|
||||
height = -height;
|
||||
cy = cy - height;
|
||||
}
|
||||
|
||||
if (cy < 0) {
|
||||
cy = 0;
|
||||
} else if (cy + height - 1 > worldHeight) {
|
||||
height = worldHeight - cy + 1;
|
||||
}
|
||||
|
||||
final double invRadiusX = 1 / radiusX;
|
||||
final double invRadiusZ = 1 / radiusZ;
|
||||
final int ceilRadiusX = (int) Math.ceil(radiusX);
|
||||
final int ceilRadiusZ = (int) Math.ceil(radiusZ);
|
||||
double nextXn = 0;
|
||||
|
||||
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
|
||||
final double xn = nextXn;
|
||||
nextXn = (x + 1) * invRadiusX;
|
||||
double nextZn = 0;
|
||||
for (int z = 0; z <= ceilRadiusZ; ++z) {
|
||||
final double zn = nextZn;
|
||||
nextZn = (z + 1) * invRadiusZ;
|
||||
double distanceSq = lengthSq(xn, zn);
|
||||
|
||||
if (distanceSq > 1) {
|
||||
if (z == 0) {
|
||||
break forX;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!filled) {
|
||||
if (lengthSq(nextXn, zn) <= 1 && lengthSq(xn, nextZn) <= 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
set(cx + x, cy + y, cz + z, data);
|
||||
set(cx + -x, cy + y, cz + z, data);
|
||||
set(cx + x, cy + y, cz + -z, data);
|
||||
set(cx + -x, cy + y, cz + -z, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void set(IrisPosition pos, T data)
|
||||
{
|
||||
set(pos.getX(), pos.getY(), pos.getZ(), data);
|
||||
}
|
||||
|
||||
public <T> void set(List<IrisPosition> positions, T data)
|
||||
{
|
||||
for(IrisPosition i : positions)
|
||||
{
|
||||
set(i, data);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void set(Set<IrisPosition> positions, T data)
|
||||
{
|
||||
for(IrisPosition i : positions)
|
||||
{
|
||||
set(i, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<IrisPosition> getBallooned(Set<IrisPosition> vset, double radius) {
|
||||
Set<IrisPosition> returnset = new HashSet<>();
|
||||
int ceilrad = (int) Math.ceil(radius);
|
||||
|
||||
for (IrisPosition v : vset) {
|
||||
int tipx = v.getX();
|
||||
int tipy = v.getY();
|
||||
int tipz = v.getZ();
|
||||
|
||||
for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) {
|
||||
for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) {
|
||||
for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) {
|
||||
if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) {
|
||||
returnset.add(new IrisPosition(loopx, loopy, loopz));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private static Set<IrisPosition> getHollowed(Set<IrisPosition> vset) {
|
||||
Set<IrisPosition> returnset = new KSet<>();
|
||||
for (IrisPosition v : vset) {
|
||||
double x = v.getX();
|
||||
double y = v.getY();
|
||||
double z = v.getZ();
|
||||
if (!(vset.contains(new IrisPosition(x + 1, y, z))
|
||||
&& vset.contains(new IrisPosition(x - 1, y, z))
|
||||
&& vset.contains(new IrisPosition(x, y + 1, z))
|
||||
&& vset.contains(new IrisPosition(x, y - 1, z))
|
||||
&& vset.contains(new IrisPosition(x, y, z + 1))
|
||||
&& vset.contains(new IrisPosition(x, y, z - 1)))) {
|
||||
returnset.add(v);
|
||||
}
|
||||
}
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private static double hypot(double... pars) {
|
||||
double sum = 0;
|
||||
for (double d : pars) {
|
||||
sum += Math.pow(d, 2);
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
private static double lengthSq(double x, double y, double z) {
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
}
|
||||
|
||||
private static double lengthSq(double x, double z) {
|
||||
return (x * x) + (z * z);
|
||||
}
|
||||
|
||||
public int getWorldHeight() {
|
||||
return worldHeight;
|
||||
}
|
||||
}
|
||||
|
@ -18,17 +18,22 @@
|
||||
|
||||
package com.volmit.iris.util.mantle;
|
||||
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.util.data.Varint;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.function.Consumer4;
|
||||
import com.volmit.iris.util.matter.IrisMatter;
|
||||
import com.volmit.iris.util.matter.Matter;
|
||||
import com.volmit.iris.util.matter.MatterSlice;
|
||||
import com.volmit.iris.util.matter.slices.ZoneMatter;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
@ -37,8 +42,10 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
* Mantle Chunks are fully atomic & thread safe
|
||||
*/
|
||||
public class MantleChunk {
|
||||
private static final ZoneMatter zm = new ZoneMatter();
|
||||
private final AtomicIntegerArray flags;
|
||||
private final AtomicReferenceArray<Matter> sections;
|
||||
private final CopyOnWriteArrayList<IrisFeaturePositional> features;
|
||||
|
||||
/**
|
||||
* Create a mantle chunk
|
||||
@ -49,6 +56,7 @@ public class MantleChunk {
|
||||
public MantleChunk(int sectionHeight) {
|
||||
sections = new AtomicReferenceArray<>(sectionHeight);
|
||||
flags = new AtomicIntegerArray(MantleFlag.values().length);
|
||||
features = new CopyOnWriteArrayList<>();
|
||||
|
||||
for (int i = 0; i < flags.length(); i++) {
|
||||
flags.set(i, 0);
|
||||
@ -76,6 +84,13 @@ public class MantleChunk {
|
||||
sections.set(i, Matter.read(din));
|
||||
}
|
||||
}
|
||||
|
||||
short v = din.readShort();
|
||||
|
||||
for(int i = 0; i < v; i++)
|
||||
{
|
||||
features.add(zm.readNode(din));
|
||||
}
|
||||
}
|
||||
|
||||
public void flag(MantleFlag flag, boolean f) {
|
||||
@ -169,6 +184,13 @@ public class MantleChunk {
|
||||
dos.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
dos.writeShort(features.size());
|
||||
|
||||
for(IrisFeaturePositional i : features)
|
||||
{
|
||||
zm.writeNode(i, dos);
|
||||
}
|
||||
}
|
||||
|
||||
private void trimSlice(int i) {
|
||||
@ -186,26 +208,6 @@ public class MantleChunk {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void iterate(Class<T> type, Consumer4<Integer, Integer, Integer, T> iterator, BurstExecutor burst) {
|
||||
for (int i = 0; i < sections.length(); i++) {
|
||||
int finalI = i;
|
||||
burst.queue(() -> {
|
||||
int bs = (finalI << 4);
|
||||
Matter matter = get(finalI);
|
||||
|
||||
if (matter != null) {
|
||||
MatterSlice<T> t = matter.getSlice(type);
|
||||
|
||||
if (t != null) {
|
||||
t.iterateSync((a, b, c, f) -> iterator.accept(a, b + bs, c, f));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
burst.complete();
|
||||
}
|
||||
|
||||
public <T> void iterate(Class<T> type, Consumer4<Integer, Integer, Integer, T> iterator) {
|
||||
for (int i = 0; i < sections.length(); i++) {
|
||||
int bs = (i << 4);
|
||||
@ -220,4 +222,12 @@ public class MantleChunk {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addFeature(IrisFeaturePositional t) {
|
||||
features.add(t);
|
||||
}
|
||||
|
||||
public List<IrisFeaturePositional> getFeatures() {
|
||||
return features;
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,11 @@
|
||||
package com.volmit.iris.util.mantle;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.hunk.storage.ArrayHunk;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
|
||||
import java.io.*;
|
||||
@ -140,7 +142,7 @@ public class TectonicPlate {
|
||||
|
||||
@ChunkCoordinates
|
||||
private int index(int x, int z) {
|
||||
return (x & 0x1F) + (z & 0x1F) * 32;
|
||||
return Cache.to1D(x, z, 0, 32, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,14 +16,32 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.engine.object.dimensional;
|
||||
package com.volmit.iris.util.math;
|
||||
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import lombok.Data;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@Desc("Terrain modes are used to decide the generator type currently used")
|
||||
public enum IrisTerrainMode {
|
||||
@Desc("Normal terrain, similar to the vanilla overworld")
|
||||
NORMAL,
|
||||
@Desc("Island terrain, more similar to the end, but endless possibilities!")
|
||||
ISLANDS
|
||||
@Data
|
||||
public class INode {
|
||||
|
||||
private Vector position;
|
||||
private double tension;
|
||||
private double bias;
|
||||
private double continuity;
|
||||
|
||||
public INode() {
|
||||
this(new Vector(0,0,0));
|
||||
}
|
||||
|
||||
public INode(INode other) {
|
||||
this.position = other.position;
|
||||
|
||||
this.tension = other.tension;
|
||||
this.bias = other.bias;
|
||||
this.continuity = other.continuity;
|
||||
}
|
||||
|
||||
public INode(Vector position) {
|
||||
this.position = position;
|
||||
}
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* 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.util.math;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class KochanekBartelsInterpolation implements PathInterpolation {
|
||||
|
||||
private List<INode> nodes;
|
||||
private Vector[] coeffA;
|
||||
private Vector[] coeffB;
|
||||
private Vector[] coeffC;
|
||||
private Vector[] coeffD;
|
||||
private double scaling;
|
||||
|
||||
public KochanekBartelsInterpolation() {
|
||||
setNodes(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodes(List<INode> nodes) {
|
||||
this.nodes = nodes;
|
||||
recalc();
|
||||
}
|
||||
|
||||
private void recalc() {
|
||||
final int nNodes = nodes.size();
|
||||
coeffA = new Vector[nNodes];
|
||||
coeffB = new Vector[nNodes];
|
||||
coeffC = new Vector[nNodes];
|
||||
coeffD = new Vector[nNodes];
|
||||
|
||||
if (nNodes == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
INode nodeB = nodes.get(0);
|
||||
double tensionB = nodeB.getTension();
|
||||
double biasB = nodeB.getBias();
|
||||
double continuityB = nodeB.getContinuity();
|
||||
for (int i = 0; i < nNodes; ++i) {
|
||||
final double tensionA = tensionB;
|
||||
final double biasA = biasB;
|
||||
final double continuityA = continuityB;
|
||||
|
||||
if (i + 1 < nNodes) {
|
||||
nodeB = nodes.get(i + 1);
|
||||
tensionB = nodeB.getTension();
|
||||
biasB = nodeB.getBias();
|
||||
continuityB = nodeB.getContinuity();
|
||||
}
|
||||
|
||||
// Kochanek-Bartels tangent coefficients
|
||||
final double ta = (1 - tensionA) * (1 + biasA) * (1 + continuityA) / 2; // Factor for lhs of d[i]
|
||||
final double tb = (1 - tensionA) * (1 - biasA) * (1 - continuityA) / 2; // Factor for rhs of d[i]
|
||||
final double tc = (1 - tensionB) * (1 + biasB) * (1 - continuityB) / 2; // Factor for lhs of d[i+1]
|
||||
final double td = (1 - tensionB) * (1 - biasB) * (1 + continuityB) / 2; // Factor for rhs of d[i+1]
|
||||
|
||||
coeffA[i] = linearCombination(i, -ta, ta - tb - tc + 2, tb + tc - td - 2, td);
|
||||
coeffB[i] = linearCombination(i, 2 * ta, -2 * ta + 2 * tb + tc - 3, -2 * tb - tc + td + 3, -td);
|
||||
coeffC[i] = linearCombination(i, -ta, ta - tb, tb, 0);
|
||||
//coeffD[i] = linearCombination(i, 0, 1, 0, 0);
|
||||
coeffD[i] = retrieve(i); // this is an optimization
|
||||
}
|
||||
|
||||
scaling = nodes.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the linear combination of the given coefficients with the nodes adjacent to baseIndex.
|
||||
*
|
||||
* @param baseIndex node index
|
||||
* @param f1 coefficient for baseIndex-1
|
||||
* @param f2 coefficient for baseIndex
|
||||
* @param f3 coefficient for baseIndex+1
|
||||
* @param f4 coefficient for baseIndex+2
|
||||
* @return linear combination of nodes[n-1..n+2] with f1..4
|
||||
*/
|
||||
private Vector linearCombination(int baseIndex, double f1, double f2, double f3, double f4) {
|
||||
final Vector r1 = retrieve(baseIndex - 1).multiply(f1);
|
||||
final Vector r2 = retrieve(baseIndex ).multiply(f2);
|
||||
final Vector r3 = retrieve(baseIndex + 1).multiply(f3);
|
||||
final Vector r4 = retrieve(baseIndex + 2).multiply(f4);
|
||||
|
||||
return r1.add(r2).add(r3).add(r4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a node. Indexes are clamped to the valid range.
|
||||
*
|
||||
* @param index node index to retrieve
|
||||
* @return nodes[clamp(0, nodes.length-1)]
|
||||
*/
|
||||
private Vector retrieve(int index) {
|
||||
if (index < 0) {
|
||||
return fastRetrieve(0);
|
||||
}
|
||||
|
||||
if (index >= nodes.size()) {
|
||||
return fastRetrieve(nodes.size() - 1);
|
||||
}
|
||||
|
||||
return fastRetrieve(index);
|
||||
}
|
||||
|
||||
private Vector fastRetrieve(int index) {
|
||||
return nodes.get(index).getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getPosition(double position) {
|
||||
if (coeffA == null) {
|
||||
throw new IllegalStateException("Must call setNodes first.");
|
||||
}
|
||||
|
||||
if (position > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
position *= scaling;
|
||||
|
||||
final int index = (int) Math.floor(position);
|
||||
final double remainder = position - index;
|
||||
|
||||
final Vector a = coeffA[index];
|
||||
final Vector b = coeffB[index];
|
||||
final Vector c = coeffC[index];
|
||||
final Vector d = coeffD[index];
|
||||
|
||||
return a.multiply(remainder).add(b).multiply(remainder).add(c).multiply(remainder).add(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector get1stDerivative(double position) {
|
||||
if (coeffA == null) {
|
||||
throw new IllegalStateException("Must call setNodes first.");
|
||||
}
|
||||
|
||||
if (position > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
position *= scaling;
|
||||
|
||||
final int index = (int) Math.floor(position);
|
||||
//final double remainder = position - index;
|
||||
|
||||
final Vector a = coeffA[index];
|
||||
final Vector b = coeffB[index];
|
||||
final Vector c = coeffC[index];
|
||||
|
||||
return a.multiply(1.5 * position - 3.0 * index).add(b).multiply(2.0 * position).add(a.multiply(1.5 * index).subtract(b).multiply(2.0 * index)).add(c).multiply(scaling);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double arcLength(double positionA, double positionB) {
|
||||
if (coeffA == null) {
|
||||
throw new IllegalStateException("Must call setNodes first.");
|
||||
}
|
||||
|
||||
if (positionA > positionB) {
|
||||
return arcLength(positionB, positionA);
|
||||
}
|
||||
|
||||
positionA *= scaling;
|
||||
positionB *= scaling;
|
||||
|
||||
final int indexA = (int) Math.floor(positionA);
|
||||
final double remainderA = positionA - indexA;
|
||||
|
||||
final int indexB = (int) Math.floor(positionB);
|
||||
final double remainderB = positionB - indexB;
|
||||
|
||||
return arcLengthRecursive(indexA, remainderA, indexB, remainderB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes a < b.
|
||||
*/
|
||||
private double arcLengthRecursive(int indexLeft, double remainderLeft, int indexRight, double remainderRight) {
|
||||
switch (indexRight - indexLeft) {
|
||||
case 0:
|
||||
return arcLengthRecursive(indexLeft, remainderLeft, remainderRight);
|
||||
|
||||
case 1:
|
||||
// This case is merely a speed-up for a very common case
|
||||
return arcLengthRecursive(indexLeft, remainderLeft, 1.0)
|
||||
+ arcLengthRecursive(indexRight, 0.0, remainderRight);
|
||||
|
||||
default:
|
||||
return arcLengthRecursive(indexLeft, remainderLeft, indexRight - 1, 1.0)
|
||||
+ arcLengthRecursive(indexRight, 0.0, remainderRight);
|
||||
}
|
||||
}
|
||||
|
||||
private double arcLengthRecursive(int index, double remainderLeft, double remainderRight) {
|
||||
final Vector a = coeffA[index].multiply(3.0);
|
||||
final Vector b = coeffB[index].multiply(2.0);
|
||||
final Vector c = coeffC[index];
|
||||
|
||||
final int nPoints = 8;
|
||||
|
||||
double accum = a.multiply(remainderLeft).add(b).multiply(remainderLeft).add(c).length() / 2.0;
|
||||
for (int i = 1; i < nPoints - 1; ++i) {
|
||||
double t = ((double) i) / nPoints;
|
||||
t = (remainderRight - remainderLeft) * t + remainderLeft;
|
||||
accum += a.multiply(t).add(b).multiply(t).add(c).length();
|
||||
}
|
||||
|
||||
accum += a.multiply(remainderRight).add(b).multiply(remainderRight).add(c).length() / 2.0;
|
||||
return accum * (remainderRight - remainderLeft) / nPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegment(double position) {
|
||||
if (coeffA == null) {
|
||||
throw new IllegalStateException("Must call setNodes first.");
|
||||
}
|
||||
|
||||
if (position > 1) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
position *= scaling;
|
||||
|
||||
return (int) Math.floor(position);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.util.math;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PathInterpolation {
|
||||
|
||||
/**
|
||||
* Sets nodes to be used by subsequent calls to
|
||||
* {@link #getPosition(double)} and the other methods.
|
||||
*
|
||||
* @param nodes the nodes
|
||||
*/
|
||||
void setNodes(List<INode> nodes);
|
||||
|
||||
/**
|
||||
* Gets the result of f(position).
|
||||
*
|
||||
* @param position the position to interpolate
|
||||
* @return the result
|
||||
*/
|
||||
Vector getPosition(double position);
|
||||
|
||||
/**
|
||||
* Gets the result of f'(position).
|
||||
*
|
||||
* @param position the position to interpolate
|
||||
* @return the result
|
||||
*/
|
||||
Vector get1stDerivative(double position);
|
||||
|
||||
/**
|
||||
* Gets the result of ∫<sub>a</sub><sup style="position: relative; left: -1ex">b</sup>|f'(t)| dt.<br />
|
||||
* That means it calculates the arc length (in meters) between positionA
|
||||
* and positionB.
|
||||
*
|
||||
* @param positionA lower limit
|
||||
* @param positionB upper limit
|
||||
* @return the arc length
|
||||
*/
|
||||
double arcLength(double positionA, double positionB);
|
||||
|
||||
/**
|
||||
* Get the segment position.
|
||||
*
|
||||
* @param position the position
|
||||
* @return the segment position
|
||||
*/
|
||||
int getSegment(double position);
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.math.BlockPosition;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.block.data.type.CraftLeaves;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.io.*;
|
||||
@ -189,7 +190,16 @@ public interface Matter {
|
||||
slice = (MatterSlice<T>) createSlice(c, this);
|
||||
|
||||
if (slice == null) {
|
||||
Iris.error("Unable to find a slice for class " + C.DARK_RED + c.getCanonicalName());
|
||||
try
|
||||
{
|
||||
throw new RuntimeException("Bad slice " + c.getCanonicalName());
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.util.matter.slices;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.object.feature.IrisFeaturePositional;
|
||||
import com.volmit.iris.util.matter.Sliced;
|
||||
|
||||
|
@ -225,7 +225,7 @@ public class Chunk {
|
||||
* @param blockZ The z-coordinate of the block.
|
||||
* @return The biome id or -1 if the biomes are not correctly initialized.
|
||||
*/
|
||||
public int getBiomeAt(int blockX, int blockY, int blockZ) {
|
||||
public synchronized int getBiomeAt(int blockX, int blockY, int blockZ) {
|
||||
if (dataVersion < 2202) {
|
||||
if (biomes == null || biomes.length != 256) {
|
||||
return -1;
|
||||
@ -244,7 +244,7 @@ public class Chunk {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setBiomeAt(int blockX, int blockZ, int biomeID) {
|
||||
public synchronized void setBiomeAt(int blockX, int blockZ, int biomeID) {
|
||||
if (dataVersion < 2202) {
|
||||
if (biomes == null || biomes.length != 256) {
|
||||
biomes = new int[256];
|
||||
@ -275,7 +275,7 @@ public class Chunk {
|
||||
* @param biomeID The biome id to be set.
|
||||
* When set to a negative number, Minecraft will replace it with the block column's default biome.
|
||||
*/
|
||||
public void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) {
|
||||
public synchronized void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) {
|
||||
if (dataVersion < 2202) {
|
||||
if (biomes == null || biomes.length != 256) {
|
||||
biomes = new int[256];
|
||||
|
@ -27,6 +27,7 @@ import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||
import com.volmit.iris.util.nbt.tag.StringTag;
|
||||
import com.volmit.iris.util.parallel.HyperLock;
|
||||
import com.volmit.iris.util.scheduling.IrisLock;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Biome;
|
||||
@ -43,8 +44,8 @@ public class NBTWorld {
|
||||
private static final BlockData AIR = B.get("AIR");
|
||||
private static final Map<String, CompoundTag> blockDataCache = new KMap<>();
|
||||
private static final Map<Biome, Integer> biomeIds = computeBiomeIDs();
|
||||
private final IrisLock regionLock = new IrisLock("Region");
|
||||
private final KMap<Long, MCAFile> loadedRegions;
|
||||
private final HyperLock hyperLock = new HyperLock();
|
||||
private final KMap<Long, Long> lastUse;
|
||||
private final File worldFolder;
|
||||
private final ExecutorService saveQueue;
|
||||
@ -62,13 +63,11 @@ public class NBTWorld {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
regionLock.lock();
|
||||
|
||||
for (Long i : loadedRegions.k()) {
|
||||
queueSaveUnload(Cache.keyX(i), Cache.keyZ(i));
|
||||
}
|
||||
|
||||
regionLock.unlock();
|
||||
saveQueue.shutdown();
|
||||
try {
|
||||
while (!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) {
|
||||
@ -80,13 +79,9 @@ public class NBTWorld {
|
||||
}
|
||||
|
||||
public void flushNow() {
|
||||
regionLock.lock();
|
||||
|
||||
for (Long i : loadedRegions.k()) {
|
||||
doSaveUnload(Cache.keyX(i), Cache.keyZ(i));
|
||||
}
|
||||
|
||||
regionLock.unlock();
|
||||
}
|
||||
|
||||
public void queueSaveUnload(int x, int z) {
|
||||
@ -103,8 +98,6 @@ public class NBTWorld {
|
||||
}
|
||||
|
||||
public void save() {
|
||||
regionLock.lock();
|
||||
|
||||
boolean saving = true;
|
||||
|
||||
for (Long i : loadedRegions.k()) {
|
||||
@ -121,8 +114,6 @@ public class NBTWorld {
|
||||
}
|
||||
|
||||
Iris.debug("Regions: " + C.GOLD + loadedRegions.size() + C.LIGHT_PURPLE);
|
||||
|
||||
regionLock.unlock();
|
||||
}
|
||||
|
||||
public void queueSave() {
|
||||
@ -131,10 +122,8 @@ public class NBTWorld {
|
||||
|
||||
public synchronized void unloadRegion(int x, int z) {
|
||||
long key = Cache.key(x, z);
|
||||
regionLock.lock();
|
||||
loadedRegions.remove(key);
|
||||
lastUse.remove(key);
|
||||
regionLock.unlock();
|
||||
Iris.debug("Unloaded Region " + C.GOLD + x + " " + z);
|
||||
}
|
||||
|
||||
@ -249,6 +238,11 @@ public class NBTWorld {
|
||||
getChunkSection(x >> 4, y >> 4, z >> 4).setBlockStateAt(x & 15, y & 15, z & 15, getCompound(data), false);
|
||||
}
|
||||
|
||||
public int getBiomeId(Biome b)
|
||||
{
|
||||
return biomeIds.get(b);
|
||||
}
|
||||
|
||||
public void setBiome(int x, int y, int z, Biome biome) {
|
||||
getChunk(x >> 4, z >> 4).setBiomeAt(x & 15, y, z & 15, biomeIds.get(biome));
|
||||
}
|
||||
@ -265,8 +259,12 @@ public class NBTWorld {
|
||||
return s;
|
||||
}
|
||||
|
||||
public synchronized Chunk getChunk(int x, int z) {
|
||||
MCAFile mca = getMCA(x >> 5, z >> 5);
|
||||
public Chunk getChunk(int x, int z)
|
||||
{
|
||||
return getChunk(getMCA(x >> 5, z >> 5), x, z);
|
||||
}
|
||||
|
||||
public Chunk getChunk(MCAFile mca, int x, int z) {
|
||||
Chunk c = mca.getChunk(x & 31, z & 31);
|
||||
|
||||
if (c == null) {
|
||||
@ -278,41 +276,40 @@ public class NBTWorld {
|
||||
}
|
||||
|
||||
public long getIdleDuration(int x, int z) {
|
||||
Long l = lastUse.get(Cache.key(x, z));
|
||||
|
||||
return l == null ? 0 : (M.ms() - l);
|
||||
return hyperLock.withResult(x, z, () -> {
|
||||
Long l = lastUse.get(Cache.key(x, z));
|
||||
return l == null ? 0 : (M.ms() - l);
|
||||
});
|
||||
}
|
||||
|
||||
public MCAFile getMCA(int x, int z) {
|
||||
long key = Cache.key(x, z);
|
||||
|
||||
regionLock.lock();
|
||||
lastUse.put(key, M.ms());
|
||||
MCAFile mcaf = loadedRegions.get(key);
|
||||
regionLock.unlock();
|
||||
return hyperLock.withResult(x, z, () -> {
|
||||
lastUse.put(key, M.ms());
|
||||
|
||||
if (mcaf == null) {
|
||||
mcaf = new MCAFile(x, z);
|
||||
regionLock.lock();
|
||||
loadedRegions.put(key, mcaf);
|
||||
regionLock.unlock();
|
||||
}
|
||||
MCAFile mcaf = loadedRegions.get(key);
|
||||
|
||||
return mcaf;
|
||||
if (mcaf == null) {
|
||||
mcaf = new MCAFile(x, z);
|
||||
loadedRegions.put(key, mcaf);
|
||||
}
|
||||
|
||||
return mcaf;
|
||||
});
|
||||
}
|
||||
|
||||
public MCAFile getMCAOrNull(int x, int z) {
|
||||
long key = Cache.key(x, z);
|
||||
MCAFile ff = null;
|
||||
regionLock.lock();
|
||||
|
||||
if (loadedRegions.containsKey(key)) {
|
||||
lastUse.put(key, M.ms());
|
||||
ff = loadedRegions.get(key);
|
||||
}
|
||||
return hyperLock.withResult(x, z, () -> {
|
||||
if (loadedRegions.containsKey(key)) {
|
||||
lastUse.put(key, M.ms());
|
||||
return loadedRegions.get(key);
|
||||
}
|
||||
|
||||
regionLock.unlock();
|
||||
return ff;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public int size() {
|
||||
|
@ -24,6 +24,7 @@ import com.volmit.iris.util.nbt.tag.ByteArrayTag;
|
||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||
import com.volmit.iris.util.nbt.tag.ListTag;
|
||||
import com.volmit.iris.util.nbt.tag.LongArrayTag;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -170,7 +171,7 @@ public class Section {
|
||||
* This option should only be used moderately to avoid unnecessary recalculation of the palette indices.
|
||||
* Recalculating the Palette should only be executed once right before saving the Section to file.
|
||||
*/
|
||||
public void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) {
|
||||
public synchronized void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) {
|
||||
int paletteSizeBefore = palette.size();
|
||||
int paletteIndex = addToPalette(state);
|
||||
//power of 2 --> bits must increase, but only if the palette size changed
|
||||
@ -223,7 +224,7 @@ public class Section {
|
||||
* @param paletteIndex The block state to be set (index of block data in the palette).
|
||||
* @param blockStates The block states to be updated.
|
||||
*/
|
||||
public void setPaletteIndex(int blockIndex, int paletteIndex, AtomicLongArray blockStates) {
|
||||
public synchronized void setPaletteIndex(int blockIndex, int paletteIndex, AtomicLongArray blockStates) {
|
||||
int bits = blockStates.length() >> 6;
|
||||
|
||||
if (dataVersion < 2527) {
|
||||
@ -253,7 +254,7 @@ public class Section {
|
||||
return palette;
|
||||
}
|
||||
|
||||
int addToPalette(CompoundTag data) {
|
||||
synchronized int addToPalette(CompoundTag data) {
|
||||
PaletteIndex index;
|
||||
if ((index = getValueIndexedPalette(data)) != null) {
|
||||
return index.index;
|
||||
@ -283,14 +284,14 @@ public class Section {
|
||||
* This should only be used moderately to avoid unnecessary recalculation of the palette indices.
|
||||
* Recalculating the Palette should only be executed once right before saving the Section to file.
|
||||
*/
|
||||
public void cleanupPaletteAndBlockStates() {
|
||||
public synchronized void cleanupPaletteAndBlockStates() {
|
||||
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
|
||||
adjustBlockStateBits(oldToNewMapping, blockStates);
|
||||
}
|
||||
|
||||
private Map<Integer, Integer> cleanupPalette() {
|
||||
private synchronized Map<Integer, Integer> cleanupPalette() {
|
||||
//create index - palette mapping
|
||||
Map<Integer, Integer> allIndices = new HashMap<>();
|
||||
Map<Integer, Integer> allIndices = new Int2IntOpenHashMap();
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
int paletteIndex = getPaletteIndex(i);
|
||||
allIndices.put(paletteIndex, paletteIndex);
|
||||
@ -314,7 +315,7 @@ public class Section {
|
||||
return allIndices;
|
||||
}
|
||||
|
||||
void adjustBlockStateBits(Map<Integer, Integer> oldToNewMapping, AtomicLongArray blockStates) {
|
||||
synchronized void adjustBlockStateBits(Map<Integer, Integer> oldToNewMapping, AtomicLongArray blockStates) {
|
||||
//increases or decreases the amount of bits used per BlockState
|
||||
//based on the size of the palette. oldToNewMapping can be used to update indices
|
||||
//if the palette had been cleaned up before using MCAFile#cleanupPalette().
|
||||
@ -376,7 +377,7 @@ public class Section {
|
||||
* @throws NullPointerException If <code>blockStates</code> is <code>null</code>
|
||||
* @throws IllegalArgumentException When <code>blockStates</code>' length is < 256 or > 4096 and is not a multiple of 64
|
||||
*/
|
||||
public void setBlockStates(AtomicLongArray blockStates) {
|
||||
public synchronized void setBlockStates(AtomicLongArray blockStates) {
|
||||
if (blockStates == null) {
|
||||
throw new NullPointerException("BlockStates cannot be null");
|
||||
} else if (blockStates.length() % 64 != 0 || blockStates.length() < 256 || blockStates.length() > 4096) {
|
||||
|
@ -26,6 +26,7 @@ import lombok.Data;
|
||||
@Data
|
||||
public class WormIterator2 {
|
||||
private transient Worm2 worm;
|
||||
private transient NoiseProvider noise;
|
||||
private int x;
|
||||
private int z;
|
||||
private int maxDistance;
|
||||
@ -39,13 +40,18 @@ public class WormIterator2 {
|
||||
+ ((z * z) - (worm.getZ().getPosition() * worm.getZ().getPosition())) < dist * dist;
|
||||
}
|
||||
|
||||
public Worm2 next(NoiseProvider p)
|
||||
public Worm2 next()
|
||||
{
|
||||
if(worm == null)
|
||||
{
|
||||
worm = new Worm2(x, z, 0, 0);
|
||||
return worm;
|
||||
}
|
||||
|
||||
worm.getX().setVelocity(noise.noise(worm.getX().getPosition(), 0));
|
||||
worm.getZ().setVelocity(noise.noise(worm.getZ().getPosition(), 0));
|
||||
worm.step();
|
||||
|
||||
return worm;
|
||||
}
|
||||
}
|
||||
|
70
src/main/java/com/volmit/iris/util/noise/WormIterator3.java
Normal file
70
src/main/java/com/volmit/iris/util/noise/WormIterator3.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.util.noise;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.function.NoiseProvider;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
public class WormIterator3 {
|
||||
private transient Worm3 worm;
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
private transient NoiseProvider noise;
|
||||
private int maxDistance;
|
||||
private int maxIterations;
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
if(worm == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
double dist = maxDistance - (Math.max(Math.max(Math.abs(worm.getX().getVelocity()),
|
||||
Math.abs(worm.getZ().getVelocity())),
|
||||
Math.abs(worm.getY().getVelocity())) + 1);
|
||||
|
||||
return maxIterations > 0 &&
|
||||
((x * x) - (worm.getX().getPosition() * worm.getX().getPosition()))
|
||||
+ ((y * y) - (worm.getY().getPosition() * worm.getY().getPosition()))
|
||||
+ ((z * z) - (worm.getZ().getPosition() * worm.getZ().getPosition())) < dist * dist;
|
||||
}
|
||||
|
||||
public Worm3 next()
|
||||
{
|
||||
maxIterations--;
|
||||
if(worm == null)
|
||||
{
|
||||
worm = new Worm3(x, y, z, 0, 0, 0);
|
||||
return worm;
|
||||
}
|
||||
|
||||
worm.getX().setVelocity(worm.getX().getVelocity() + noise.noise(worm.getX().getPosition() + 10000, 0));
|
||||
worm.getY().setVelocity(worm.getY().getVelocity() + noise.noise(worm.getY().getPosition() + 1000, 0));
|
||||
worm.getZ().setVelocity(worm.getZ().getVelocity() + noise.noise(worm.getZ().getPosition() - 10000, 0));
|
||||
worm.step();
|
||||
|
||||
return worm;
|
||||
}
|
||||
}
|
@ -28,25 +28,20 @@ import java.util.concurrent.*;
|
||||
@SuppressWarnings("ALL")
|
||||
public class BurstExecutor {
|
||||
private final ExecutorService executor;
|
||||
private final KList<CompletableFuture<Void>> futures;
|
||||
private final KList<Future<?>> futures;
|
||||
@Setter
|
||||
private boolean multicore = true;
|
||||
|
||||
public BurstExecutor(ExecutorService executor, int burstSizeEstimate) {
|
||||
this.executor = executor;
|
||||
futures = new KList<CompletableFuture<Void>>(burstSizeEstimate);
|
||||
futures = new KList<Future<?>>(burstSizeEstimate);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public CompletableFuture<Void> queue(Runnable r) {
|
||||
if(!multicore)
|
||||
{
|
||||
r.run();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<?> queue(Runnable r) {
|
||||
synchronized (futures) {
|
||||
CompletableFuture<Void> c = CompletableFuture.runAsync(r, executor);
|
||||
|
||||
Future<?> c = executor.submit(r);
|
||||
futures.add(c);
|
||||
return c;
|
||||
}
|
||||
@ -55,7 +50,7 @@ public class BurstExecutor {
|
||||
public BurstExecutor queue(List<Runnable> r) {
|
||||
if(!multicore)
|
||||
{
|
||||
for(Runnable i : r)
|
||||
for(Runnable i : new KList<>(r))
|
||||
{
|
||||
i.run();
|
||||
}
|
||||
@ -65,8 +60,7 @@ public class BurstExecutor {
|
||||
|
||||
synchronized (futures) {
|
||||
for (Runnable i : new KList<>(r)) {
|
||||
CompletableFuture<Void> c = CompletableFuture.runAsync(i, executor);
|
||||
futures.add(c);
|
||||
queue(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +70,7 @@ public class BurstExecutor {
|
||||
public BurstExecutor queue(Runnable[] r) {
|
||||
if(!multicore)
|
||||
{
|
||||
for(Runnable i : r)
|
||||
for(Runnable i : new KList<>(r))
|
||||
{
|
||||
i.run();
|
||||
}
|
||||
@ -86,8 +80,7 @@ public class BurstExecutor {
|
||||
|
||||
synchronized (futures) {
|
||||
for (Runnable i : r) {
|
||||
CompletableFuture<Void> c = CompletableFuture.runAsync(i, executor);
|
||||
futures.add(c);
|
||||
queue(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,38 +99,15 @@ public class BurstExecutor {
|
||||
}
|
||||
|
||||
try {
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
|
||||
futures.clear();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean complete(long maxDur) {
|
||||
if(!multicore)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized (futures) {
|
||||
if (futures.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(maxDur, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
return false;
|
||||
for(Future<?> i : futures)
|
||||
{
|
||||
i.get();
|
||||
}
|
||||
|
||||
futures.clear();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,8 @@ import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.service.PreservationSVC;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.io.InstanceState;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.Looper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
@ -33,66 +31,39 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class MultiBurst {
|
||||
public static final MultiBurst burst = new MultiBurst("Iris", IrisSettings.get().getConcurrency().getMiscThreadPriority(), IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getMiscThreadCount()));
|
||||
public static final MultiBurst burst = new MultiBurst();
|
||||
private ExecutorService service;
|
||||
private final Looper heartbeat;
|
||||
private final AtomicLong last;
|
||||
private int tid;
|
||||
private final String name;
|
||||
private final int tc;
|
||||
private final int priority;
|
||||
private final int instance;
|
||||
|
||||
public MultiBurst(int tc) {
|
||||
this("Iris", 6, tc);
|
||||
public MultiBurst() {
|
||||
this("Iris", Thread.MIN_PRIORITY);
|
||||
}
|
||||
|
||||
public MultiBurst(String name, int priority, int tc) {
|
||||
public MultiBurst(String name, int priority) {
|
||||
this.name = name;
|
||||
this.priority = priority;
|
||||
this.tc = tc;
|
||||
instance = InstanceState.getInstanceId();
|
||||
last = new AtomicLong(M.ms());
|
||||
heartbeat = new Looper() {
|
||||
@Override
|
||||
protected long loop() {
|
||||
if (instance != InstanceState.getInstanceId()) {
|
||||
shutdownNow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.ms() - last.get() > TimeUnit.MINUTES.toMillis(1) && service != null) {
|
||||
service.shutdown();
|
||||
service = null;
|
||||
Iris.debug("Shutting down MultiBurst Pool " + getName() + " to conserve resources.");
|
||||
}
|
||||
|
||||
return 30000;
|
||||
}
|
||||
};
|
||||
heartbeat.setName(name + " Monitor");
|
||||
heartbeat.start();
|
||||
Iris.service(PreservationSVC.class).register(this);
|
||||
}
|
||||
|
||||
private synchronized ExecutorService getService() {
|
||||
last.set(M.ms());
|
||||
if (service == null || service.isShutdown()) {
|
||||
service = Executors.newFixedThreadPool(Math.max(tc, 1), r -> {
|
||||
tid++;
|
||||
Thread t = new Thread(r);
|
||||
t.setName(name + " " + tid);
|
||||
t.setPriority(priority);
|
||||
t.setUncaughtExceptionHandler((et, e) ->
|
||||
{
|
||||
Iris.info("Exception encountered in " + et.getName());
|
||||
e.printStackTrace();
|
||||
});
|
||||
service = new ForkJoinPool(IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()),
|
||||
new ForkJoinPool.ForkJoinWorkerThreadFactory() {
|
||||
int m = 0;
|
||||
|
||||
return t;
|
||||
});
|
||||
Iris.service(PreservationSVC.class).register(service);
|
||||
Iris.debug("Started MultiBurst Pool " + name + " with " + tc + " threads at " + priority + " priority.");
|
||||
@Override
|
||||
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
|
||||
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
|
||||
worker.setPriority(priority);
|
||||
worker.setName(name + " " + ++m);
|
||||
return worker;
|
||||
}
|
||||
},
|
||||
(t, e) -> e.printStackTrace(), true);
|
||||
}
|
||||
|
||||
return service;
|
||||
@ -102,10 +73,40 @@ public class MultiBurst {
|
||||
burst(r.length).queue(r).complete();
|
||||
}
|
||||
|
||||
public void burst(boolean multicore, Runnable... r) {
|
||||
if(multicore)
|
||||
{
|
||||
burst(r);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
sync(r);
|
||||
}
|
||||
}
|
||||
|
||||
public void burst(List<Runnable> r) {
|
||||
burst(r.size()).queue(r).complete();
|
||||
}
|
||||
|
||||
public void burst(boolean multicore, List<Runnable> r) {
|
||||
if(multicore)
|
||||
{
|
||||
burst(r);
|
||||
}
|
||||
|
||||
else {
|
||||
sync(r);
|
||||
}
|
||||
}
|
||||
|
||||
private void sync(List<Runnable> r) {
|
||||
for(Runnable i : new KList<>(r))
|
||||
{
|
||||
i.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void sync(Runnable... r) {
|
||||
for (Runnable i : r) {
|
||||
i.run();
|
||||
@ -126,6 +127,12 @@ public class MultiBurst {
|
||||
return burst(16);
|
||||
}
|
||||
|
||||
public BurstExecutor burst(boolean multicore) {
|
||||
BurstExecutor b = burst();
|
||||
b.setMulticore(multicore);
|
||||
return b;
|
||||
}
|
||||
|
||||
public <T> Future<T> lazySubmit(Callable<T> o) {
|
||||
return getService().submit(o);
|
||||
}
|
||||
@ -138,64 +145,15 @@ public class MultiBurst {
|
||||
return getService().submit(o);
|
||||
}
|
||||
|
||||
public CompletableFuture<?> complete(Runnable o) {
|
||||
return CompletableFuture.runAsync(o, getService());
|
||||
public Future<?> complete(Runnable o) {
|
||||
return getService().submit(o);
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> completeValue(Supplier<T> o) {
|
||||
return CompletableFuture.supplyAsync(o, getService());
|
||||
public <T> Future<T> completeValue(Callable<T> o) {
|
||||
return getService().submit(o);
|
||||
}
|
||||
|
||||
public void shutdownNow() {
|
||||
Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + ".");
|
||||
heartbeat.interrupt();
|
||||
|
||||
if (service != null) {
|
||||
service.shutdownNow().forEach(Runnable::run);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + ".");
|
||||
heartbeat.interrupt();
|
||||
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownLater() {
|
||||
if (service != null) {
|
||||
try
|
||||
{
|
||||
service.submit(() -> {
|
||||
J.sleep(3000);
|
||||
Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + ".");
|
||||
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
}
|
||||
});
|
||||
|
||||
heartbeat.interrupt();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + ".");
|
||||
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
}
|
||||
|
||||
heartbeat.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownAndAwait() {
|
||||
Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + ".");
|
||||
heartbeat.interrupt();
|
||||
public void close() {
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
try {
|
||||
|
@ -311,6 +311,9 @@ public class VolmitSender implements CommandSender {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessageBasic(String message) {
|
||||
s.sendMessage(C.translateAlternateColorCodes('&', getTag() + message));
|
||||
}
|
||||
|
||||
public void sendMessageRaw(String message) {
|
||||
if (message.contains("<NOMINI>")) {
|
||||
|
@ -129,7 +129,6 @@ public class J {
|
||||
try {
|
||||
r.run();
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -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.util.scheduling.jobs;
|
||||
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
|
||||
public abstract class ParallelQueueJob<T> extends QueueJob<T> {
|
||||
@Override
|
||||
public void execute() {
|
||||
while (queue.isNotEmpty()) {
|
||||
BurstExecutor b = MultiBurst.burst.burst(queue.size());
|
||||
KList<T> q = queue.copy();
|
||||
queue.clear();
|
||||
for(T i : q)
|
||||
{
|
||||
b.queue(() -> {
|
||||
execute(i);
|
||||
completeWork();
|
||||
});
|
||||
}
|
||||
b.complete();
|
||||
}
|
||||
}
|
||||
}
|
@ -18,27 +18,32 @@
|
||||
|
||||
package com.volmit.iris.util.scheduling.jobs;
|
||||
|
||||
import com.sun.jna.platform.unix.X11;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class QueueJob<T> implements Job {
|
||||
private final KList<T> queue;
|
||||
private int totalWork;
|
||||
private int completed;
|
||||
final KList<T> queue;
|
||||
protected int totalWork;
|
||||
private AtomicInteger completed;
|
||||
|
||||
public QueueJob() {
|
||||
totalWork = 0;
|
||||
completed = 0;
|
||||
completed = new AtomicInteger(0);
|
||||
queue = new KList<>();
|
||||
}
|
||||
|
||||
public void queue(T t) {
|
||||
public QueueJob queue(T t) {
|
||||
queue.add(t);
|
||||
totalWork++;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void queue(KList<T> f) {
|
||||
public QueueJob queue(KList<T> f) {
|
||||
queue.addAll(f);
|
||||
totalWork += f.size();
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract void execute(T t);
|
||||
@ -54,7 +59,7 @@ public abstract class QueueJob<T> implements Job {
|
||||
|
||||
@Override
|
||||
public void completeWork() {
|
||||
completed++;
|
||||
completed.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,6 +69,6 @@ public abstract class QueueJob<T> implements Job {
|
||||
|
||||
@Override
|
||||
public int getWorkCompleted() {
|
||||
return completed;
|
||||
return completed.get();
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,18 @@ authors: [ cyberpwn, NextdoorPsycho ]
|
||||
website: volmit.com
|
||||
description: More than a Dimension!
|
||||
libraries:
|
||||
- org.zeroturnaround:zt-zip:1.14
|
||||
- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2
|
||||
- org.ow2.asm:asm:9.2
|
||||
- com.google.code.gson:gson:2.8.7
|
||||
- it.unimi.dsi:fastutil:8.5.4
|
||||
- com.github.ben-manes.caffeine:caffeine:3.0.3
|
||||
- io.timeandspace:smoothie-map:2.0.2
|
||||
- com.google.guava:guava:30.1.1-jre
|
||||
- bsf:bsf:2.4.0
|
||||
- com.google.code.gson:gson:2.8.7
|
||||
- org.zeroturnaround:zt-zip:1.14
|
||||
- it.unimi.dsi:fastutil:8.5.4
|
||||
- org.ow2.asm:asm:9.2
|
||||
- rhino:js:1.7R2
|
||||
- bsf:bsf:2.4.0
|
||||
commands:
|
||||
iris:
|
||||
aliases: [ ir, irs ]
|
||||
irisd:
|
||||
aliases: [ ird, irsd ]
|
||||
api-version: ${apiversion}
|
||||
hotload-dependencies: false
|
Loading…
x
Reference in New Issue
Block a user