mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-06-18 23:01:07 +00:00
f
This commit is contained in:
@@ -91,6 +91,8 @@ public final class ExternalDataPackPipeline {
|
|||||||
private static final String IMPORT_PREFIX = "imports";
|
private static final String IMPORT_PREFIX = "imports";
|
||||||
private static final String LOCATE_MANIFEST_PATH = "cache/external-datapack-locate-manifest.json";
|
private static final String LOCATE_MANIFEST_PATH = "cache/external-datapack-locate-manifest.json";
|
||||||
private static final String OBJECT_LOCATE_MANIFEST_PATH = "cache/external-datapack-object-locate-manifest.json";
|
private static final String OBJECT_LOCATE_MANIFEST_PATH = "cache/external-datapack-object-locate-manifest.json";
|
||||||
|
private static final String SMARTBORE_STRUCTURE_MANIFEST_PATH = "cache/external-datapack-smartbore-manifest.json";
|
||||||
|
private static final String SUPPRESSED_VANILLA_STRUCTURE_MANIFEST_PATH = "cache/external-datapack-suppressed-vanilla-structures.json";
|
||||||
private static final int CONNECT_TIMEOUT_MS = 4000;
|
private static final int CONNECT_TIMEOUT_MS = 4000;
|
||||||
private static final int READ_TIMEOUT_MS = 8000;
|
private static final int READ_TIMEOUT_MS = 8000;
|
||||||
private static final int IMPORT_PARALLELISM = Math.max(1, Math.min(8, Runtime.getRuntime().availableProcessors()));
|
private static final int IMPORT_PARALLELISM = Math.max(1, Math.min(8, Runtime.getRuntime().availableProcessors()));
|
||||||
@@ -99,6 +101,8 @@ public final class ExternalDataPackPipeline {
|
|||||||
private static final Map<String, String> PACK_ENVIRONMENT_CACHE = new ConcurrentHashMap<>();
|
private static final Map<String, String> PACK_ENVIRONMENT_CACHE = new ConcurrentHashMap<>();
|
||||||
private static final Map<String, Set<String>> RESOLVED_LOCATE_STRUCTURES_BY_ID = new ConcurrentHashMap<>();
|
private static final Map<String, Set<String>> RESOLVED_LOCATE_STRUCTURES_BY_ID = new ConcurrentHashMap<>();
|
||||||
private static final Map<String, Set<String>> RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY = new ConcurrentHashMap<>();
|
private static final Map<String, Set<String>> RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<String, Set<String>> RESOLVED_SMARTBORE_STRUCTURES_BY_ID = new ConcurrentHashMap<>();
|
||||||
|
private static final Set<String> SUPPRESSED_VANILLA_STRUCTURE_KEYS = ConcurrentHashMap.newKeySet();
|
||||||
private static final AtomicCache<KMap<Identifier, StructurePlacement>> VANILLA_STRUCTURE_PLACEMENTS = new AtomicCache<>();
|
private static final AtomicCache<KMap<Identifier, StructurePlacement>> VANILLA_STRUCTURE_PLACEMENTS = new AtomicCache<>();
|
||||||
private static final BlockData AIR = B.getAir();
|
private static final BlockData AIR = B.getAir();
|
||||||
|
|
||||||
@@ -203,11 +207,48 @@ public final class ExternalDataPackPipeline {
|
|||||||
return Set.copyOf(structures);
|
return Set.copyOf(structures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<String> snapshotSmartBoreStructureKeys() {
|
||||||
|
if (RESOLVED_SMARTBORE_STRUCTURES_BY_ID.isEmpty()) {
|
||||||
|
Map<String, Set<String>> manifest = readSmartBoreManifest();
|
||||||
|
if (!manifest.isEmpty()) {
|
||||||
|
RESOLVED_SMARTBORE_STRUCTURES_BY_ID.putAll(manifest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<String> structures = new LinkedHashSet<>();
|
||||||
|
for (Set<String> values : RESOLVED_SMARTBORE_STRUCTURES_BY_ID.values()) {
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String value : values) {
|
||||||
|
String normalized = normalizeLocateStructure(value);
|
||||||
|
if (!normalized.isBlank()) {
|
||||||
|
structures.add(normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Set.copyOf(structures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> snapshotSuppressedVanillaStructureKeys() {
|
||||||
|
if (SUPPRESSED_VANILLA_STRUCTURE_KEYS.isEmpty()) {
|
||||||
|
Set<String> manifest = readSuppressedVanillaStructureManifest();
|
||||||
|
if (!manifest.isEmpty()) {
|
||||||
|
SUPPRESSED_VANILLA_STRUCTURE_KEYS.addAll(manifest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Set.copyOf(SUPPRESSED_VANILLA_STRUCTURE_KEYS);
|
||||||
|
}
|
||||||
|
|
||||||
public static PipelineSummary processDatapacks(List<DatapackRequest> requests, Map<String, KList<File>> worldDatapackFoldersByPack) {
|
public static PipelineSummary processDatapacks(List<DatapackRequest> requests, Map<String, KList<File>> worldDatapackFoldersByPack) {
|
||||||
PipelineSummary summary = new PipelineSummary();
|
PipelineSummary summary = new PipelineSummary();
|
||||||
PACK_ENVIRONMENT_CACHE.clear();
|
PACK_ENVIRONMENT_CACHE.clear();
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_ID.clear();
|
RESOLVED_LOCATE_STRUCTURES_BY_ID.clear();
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.clear();
|
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.clear();
|
||||||
|
RESOLVED_SMARTBORE_STRUCTURES_BY_ID.clear();
|
||||||
|
SUPPRESSED_VANILLA_STRUCTURE_KEYS.clear();
|
||||||
|
|
||||||
Set<File> knownWorldDatapackFolders = new LinkedHashSet<>();
|
Set<File> knownWorldDatapackFolders = new LinkedHashSet<>();
|
||||||
if (worldDatapackFoldersByPack != null) {
|
if (worldDatapackFoldersByPack != null) {
|
||||||
@@ -233,6 +274,8 @@ public final class ExternalDataPackPipeline {
|
|||||||
Iris.info("Downloading datapacks [0/0] Downloading/Done!");
|
Iris.info("Downloading datapacks [0/0] Downloading/Done!");
|
||||||
writeLocateManifest(Map.of());
|
writeLocateManifest(Map.of());
|
||||||
writeObjectLocateManifest(Map.of());
|
writeObjectLocateManifest(Map.of());
|
||||||
|
writeSmartBoreManifest(Map.of());
|
||||||
|
writeSuppressedVanillaStructureManifest(Set.of());
|
||||||
summary.legacyWorldCopyRemovals += pruneManagedWorldDatapacks(knownWorldDatapackFolders, Set.of());
|
summary.legacyWorldCopyRemovals += pruneManagedWorldDatapacks(knownWorldDatapackFolders, Set.of());
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
@@ -240,6 +283,8 @@ public final class ExternalDataPackPipeline {
|
|||||||
List<RequestedSourceInput> sourceInputs = new ArrayList<>();
|
List<RequestedSourceInput> sourceInputs = new ArrayList<>();
|
||||||
LinkedHashMap<String, Set<String>> resolvedLocateStructuresById = new LinkedHashMap<>();
|
LinkedHashMap<String, Set<String>> resolvedLocateStructuresById = new LinkedHashMap<>();
|
||||||
LinkedHashMap<String, Set<String>> resolvedLocateStructuresByObjectKey = new LinkedHashMap<>();
|
LinkedHashMap<String, Set<String>> resolvedLocateStructuresByObjectKey = new LinkedHashMap<>();
|
||||||
|
LinkedHashMap<String, Set<String>> resolvedSmartBoreStructuresById = new LinkedHashMap<>();
|
||||||
|
LinkedHashSet<String> suppressedVanillaStructures = new LinkedHashSet<>();
|
||||||
for (int requestIndex = 0; requestIndex < normalizedRequests.size(); requestIndex++) {
|
for (int requestIndex = 0; requestIndex < normalizedRequests.size(); requestIndex++) {
|
||||||
DatapackRequest request = normalizedRequests.get(requestIndex);
|
DatapackRequest request = normalizedRequests.get(requestIndex);
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
@@ -285,8 +330,12 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
writeLocateManifest(resolvedLocateStructuresById);
|
writeLocateManifest(resolvedLocateStructuresById);
|
||||||
writeObjectLocateManifest(resolvedLocateStructuresByObjectKey);
|
writeObjectLocateManifest(resolvedLocateStructuresByObjectKey);
|
||||||
|
writeSmartBoreManifest(resolvedSmartBoreStructuresById);
|
||||||
|
writeSuppressedVanillaStructureManifest(suppressedVanillaStructures);
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_ID.putAll(resolvedLocateStructuresById);
|
RESOLVED_LOCATE_STRUCTURES_BY_ID.putAll(resolvedLocateStructuresById);
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.putAll(resolvedLocateStructuresByObjectKey);
|
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.putAll(resolvedLocateStructuresByObjectKey);
|
||||||
|
RESOLVED_SMARTBORE_STRUCTURES_BY_ID.putAll(resolvedSmartBoreStructuresById);
|
||||||
|
SUPPRESSED_VANILLA_STRUCTURE_KEYS.addAll(suppressedVanillaStructures);
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,6 +425,13 @@ public final class ExternalDataPackPipeline {
|
|||||||
summary.worldDatapacksInstalled += projectionResult.installedDatapacks();
|
summary.worldDatapacksInstalled += projectionResult.installedDatapacks();
|
||||||
summary.worldAssetsInstalled += projectionResult.installedAssets();
|
summary.worldAssetsInstalled += projectionResult.installedAssets();
|
||||||
mergeResolvedLocateStructures(resolvedLocateStructuresById, request.id(), projectionResult.resolvedLocateStructures());
|
mergeResolvedLocateStructures(resolvedLocateStructuresById, request.id(), projectionResult.resolvedLocateStructures());
|
||||||
|
suppressedVanillaStructures.addAll(determineSuppressedVanillaStructures(request, projectionResult.projectedStructureKeys()));
|
||||||
|
if (request.supportSmartBore()) {
|
||||||
|
LinkedHashSet<String> smartBoreTargets = new LinkedHashSet<>();
|
||||||
|
smartBoreTargets.addAll(request.resolvedLocateStructures());
|
||||||
|
smartBoreTargets.addAll(projectionResult.resolvedLocateStructures());
|
||||||
|
mergeResolvedLocateStructures(resolvedSmartBoreStructuresById, request.id(), smartBoreTargets);
|
||||||
|
}
|
||||||
LinkedHashSet<String> objectLocateTargets = new LinkedHashSet<>();
|
LinkedHashSet<String> objectLocateTargets = new LinkedHashSet<>();
|
||||||
objectLocateTargets.addAll(request.resolvedLocateStructures());
|
objectLocateTargets.addAll(request.resolvedLocateStructures());
|
||||||
objectLocateTargets.addAll(projectionResult.resolvedLocateStructures());
|
objectLocateTargets.addAll(projectionResult.resolvedLocateStructures());
|
||||||
@@ -425,8 +481,12 @@ public final class ExternalDataPackPipeline {
|
|||||||
|
|
||||||
writeLocateManifest(resolvedLocateStructuresById);
|
writeLocateManifest(resolvedLocateStructuresById);
|
||||||
writeObjectLocateManifest(resolvedLocateStructuresByObjectKey);
|
writeObjectLocateManifest(resolvedLocateStructuresByObjectKey);
|
||||||
|
writeSmartBoreManifest(resolvedSmartBoreStructuresById);
|
||||||
|
writeSuppressedVanillaStructureManifest(suppressedVanillaStructures);
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_ID.putAll(resolvedLocateStructuresById);
|
RESOLVED_LOCATE_STRUCTURES_BY_ID.putAll(resolvedLocateStructuresById);
|
||||||
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.putAll(resolvedLocateStructuresByObjectKey);
|
RESOLVED_LOCATE_STRUCTURES_BY_OBJECT_KEY.putAll(resolvedLocateStructuresByObjectKey);
|
||||||
|
RESOLVED_SMARTBORE_STRUCTURES_BY_ID.putAll(resolvedSmartBoreStructuresById);
|
||||||
|
SUPPRESSED_VANILLA_STRUCTURE_KEYS.addAll(suppressedVanillaStructures);
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,6 +498,14 @@ public final class ExternalDataPackPipeline {
|
|||||||
return Iris.instance.getDataFile(OBJECT_LOCATE_MANIFEST_PATH);
|
return Iris.instance.getDataFile(OBJECT_LOCATE_MANIFEST_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static File getSmartBoreManifestFile() {
|
||||||
|
return Iris.instance.getDataFile(SMARTBORE_STRUCTURE_MANIFEST_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getSuppressedVanillaStructureManifestFile() {
|
||||||
|
return Iris.instance.getDataFile(SUPPRESSED_VANILLA_STRUCTURE_MANIFEST_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
private static String normalizeLocateId(String id) {
|
private static String normalizeLocateId(String id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return "";
|
return "";
|
||||||
@@ -464,6 +532,26 @@ public final class ExternalDataPackPipeline {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Set<String> determineSuppressedVanillaStructures(DatapackRequest request, Set<String> projectedStructureKeys) {
|
||||||
|
LinkedHashSet<String> suppressed = new LinkedHashSet<>();
|
||||||
|
if (request == null || !request.replaceVanilla() || request.alongsideMode()) {
|
||||||
|
return suppressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> projected = projectedStructureKeys == null ? Set.of() : projectedStructureKeys;
|
||||||
|
for (String structureTarget : request.structures()) {
|
||||||
|
String normalizedTarget = normalizeLocateStructure(structureTarget);
|
||||||
|
if (normalizedTarget.isBlank() || !normalizedTarget.startsWith("minecraft:")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!projected.contains(normalizedTarget)) {
|
||||||
|
suppressed.add(normalizedTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return suppressed;
|
||||||
|
}
|
||||||
|
|
||||||
private static String normalizeObjectLoadKey(String objectKey) {
|
private static String normalizeObjectLoadKey(String objectKey) {
|
||||||
if (objectKey == null) {
|
if (objectKey == null) {
|
||||||
return "";
|
return "";
|
||||||
@@ -678,6 +766,93 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void writeSmartBoreManifest(Map<String, Set<String>> resolvedSmartBoreStructuresById) {
|
||||||
|
File output = getSmartBoreManifestFile();
|
||||||
|
LinkedHashMap<String, Set<String>> normalized = new LinkedHashMap<>();
|
||||||
|
if (resolvedSmartBoreStructuresById != null) {
|
||||||
|
for (Map.Entry<String, Set<String>> entry : resolvedSmartBoreStructuresById.entrySet()) {
|
||||||
|
String normalizedId = normalizeLocateId(entry.getKey());
|
||||||
|
if (normalizedId.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<String> structures = new LinkedHashSet<>();
|
||||||
|
Set<String> values = entry.getValue();
|
||||||
|
if (values != null) {
|
||||||
|
for (String structure : values) {
|
||||||
|
String normalizedStructure = normalizeLocateStructure(structure);
|
||||||
|
if (!normalizedStructure.isBlank()) {
|
||||||
|
structures.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!structures.isEmpty()) {
|
||||||
|
normalized.put(normalizedId, Set.copyOf(structures));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject root = new JSONObject();
|
||||||
|
root.put("generatedAt", Instant.now().toString());
|
||||||
|
JSONObject mappings = new JSONObject();
|
||||||
|
ArrayList<String> ids = new ArrayList<>(normalized.keySet());
|
||||||
|
ids.sort(String::compareTo);
|
||||||
|
for (String id : ids) {
|
||||||
|
Set<String> structures = normalized.get(id);
|
||||||
|
if (structures == null || structures.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> sortedStructures = new ArrayList<>(structures);
|
||||||
|
sortedStructures.sort(String::compareTo);
|
||||||
|
JSONArray values = new JSONArray();
|
||||||
|
for (String structure : sortedStructures) {
|
||||||
|
values.put(structure);
|
||||||
|
}
|
||||||
|
mappings.put(id, values);
|
||||||
|
}
|
||||||
|
root.put("ids", mappings);
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeBytesToFile(root.toString(4).getBytes(StandardCharsets.UTF_8), output);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.warn("Failed to write external datapack smartbore manifest " + output.getPath());
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeSuppressedVanillaStructureManifest(Set<String> suppressedStructures) {
|
||||||
|
File output = getSuppressedVanillaStructureManifestFile();
|
||||||
|
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||||
|
if (suppressedStructures != null) {
|
||||||
|
for (String value : suppressedStructures) {
|
||||||
|
String normalizedStructure = normalizeLocateStructure(value);
|
||||||
|
if (normalizedStructure.isBlank() || !normalizedStructure.startsWith("minecraft:")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
normalized.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject root = new JSONObject();
|
||||||
|
root.put("generatedAt", Instant.now().toString());
|
||||||
|
JSONArray values = new JSONArray();
|
||||||
|
ArrayList<String> sorted = new ArrayList<>(normalized);
|
||||||
|
sorted.sort(String::compareTo);
|
||||||
|
for (String value : sorted) {
|
||||||
|
values.put(value);
|
||||||
|
}
|
||||||
|
root.put("structures", values);
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeBytesToFile(root.toString(4).getBytes(StandardCharsets.UTF_8), output);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.warn("Failed to write external datapack suppressed-vanilla structure manifest " + output.getPath());
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, Set<String>> readLocateManifest() {
|
private static Map<String, Set<String>> readLocateManifest() {
|
||||||
LinkedHashMap<String, Set<String>> mapped = new LinkedHashMap<>();
|
LinkedHashMap<String, Set<String>> mapped = new LinkedHashMap<>();
|
||||||
File input = getLocateManifestFile();
|
File input = getLocateManifestFile();
|
||||||
@@ -778,6 +953,88 @@ public final class ExternalDataPackPipeline {
|
|||||||
return mapped;
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<String, Set<String>> readSmartBoreManifest() {
|
||||||
|
LinkedHashMap<String, Set<String>> mapped = new LinkedHashMap<>();
|
||||||
|
File input = getSmartBoreManifestFile();
|
||||||
|
if (!input.exists() || !input.isFile()) {
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject root = new JSONObject(Files.readString(input.toPath(), StandardCharsets.UTF_8));
|
||||||
|
JSONObject ids = root.optJSONObject("ids");
|
||||||
|
if (ids == null) {
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> keys = new ArrayList<>(ids.keySet());
|
||||||
|
keys.sort(String::compareTo);
|
||||||
|
for (String key : keys) {
|
||||||
|
String normalizedId = normalizeLocateId(key);
|
||||||
|
if (normalizedId.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<String> structures = new LinkedHashSet<>();
|
||||||
|
JSONArray values = ids.optJSONArray(key);
|
||||||
|
if (values != null) {
|
||||||
|
for (int i = 0; i < values.length(); i++) {
|
||||||
|
Object rawValue = values.opt(i);
|
||||||
|
if (rawValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String normalizedStructure = normalizeLocateStructure(String.valueOf(rawValue));
|
||||||
|
if (!normalizedStructure.isBlank()) {
|
||||||
|
structures.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!structures.isEmpty()) {
|
||||||
|
mapped.put(normalizedId, Set.copyOf(structures));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.warn("Failed to read external datapack smartbore manifest " + input.getPath());
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> readSuppressedVanillaStructureManifest() {
|
||||||
|
LinkedHashSet<String> mapped = new LinkedHashSet<>();
|
||||||
|
File input = getSuppressedVanillaStructureManifestFile();
|
||||||
|
if (!input.exists() || !input.isFile()) {
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject root = new JSONObject(Files.readString(input.toPath(), StandardCharsets.UTF_8));
|
||||||
|
JSONArray values = root.optJSONArray("structures");
|
||||||
|
if (values == null) {
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < values.length(); i++) {
|
||||||
|
Object rawValue = values.opt(i);
|
||||||
|
if (rawValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String normalizedStructure = normalizeLocateStructure(String.valueOf(rawValue));
|
||||||
|
if (!normalizedStructure.isBlank() && normalizedStructure.startsWith("minecraft:")) {
|
||||||
|
mapped.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.warn("Failed to read external datapack suppressed-vanilla structure manifest " + input.getPath());
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
private static List<DatapackRequest> normalizeRequests(List<DatapackRequest> requests) {
|
private static List<DatapackRequest> normalizeRequests(List<DatapackRequest> requests) {
|
||||||
Map<String, DatapackRequest> deduplicated = new HashMap<>();
|
Map<String, DatapackRequest> deduplicated = new HashMap<>();
|
||||||
if (requests == null) {
|
if (requests == null) {
|
||||||
@@ -1028,7 +1285,10 @@ public final class ExternalDataPackPipeline {
|
|||||||
|
|
||||||
String managedName = buildManagedWorldDatapackName(sourceDescriptor.targetPack(), sourceDescriptor.sourceKey());
|
String managedName = buildManagedWorldDatapackName(sourceDescriptor.targetPack(), sourceDescriptor.sourceKey());
|
||||||
if (worldDatapackFolders == null || worldDatapackFolders.isEmpty()) {
|
if (worldDatapackFolders == null || worldDatapackFolders.isEmpty()) {
|
||||||
return ProjectionResult.success(managedName, 0, 0, Set.copyOf(request.resolvedLocateStructures()), 0);
|
if (request.required()) {
|
||||||
|
return ProjectionResult.failure(managedName, "no target world datapack folder is available for required external datapack request");
|
||||||
|
}
|
||||||
|
return ProjectionResult.success(managedName, 0, 0, Set.copyOf(request.resolvedLocateStructures()), 0, Set.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionAssetSummary projectionAssetSummary;
|
ProjectionAssetSummary projectionAssetSummary;
|
||||||
@@ -1041,7 +1301,14 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (projectionAssetSummary.assets().isEmpty()) {
|
if (projectionAssetSummary.assets().isEmpty()) {
|
||||||
return ProjectionResult.success(managedName, 0, 0, projectionAssetSummary.resolvedLocateStructures(), projectionAssetSummary.syntheticStructureSets());
|
return ProjectionResult.success(
|
||||||
|
managedName,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
projectionAssetSummary.resolvedLocateStructures(),
|
||||||
|
projectionAssetSummary.syntheticStructureSets(),
|
||||||
|
projectionAssetSummary.projectedStructureKeys()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int installedDatapacks = 0;
|
int installedDatapacks = 0;
|
||||||
@@ -1070,7 +1337,14 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProjectionResult.success(managedName, installedDatapacks, installedAssets, projectionAssetSummary.resolvedLocateStructures(), projectionAssetSummary.syntheticStructureSets());
|
return ProjectionResult.success(
|
||||||
|
managedName,
|
||||||
|
installedDatapacks,
|
||||||
|
installedAssets,
|
||||||
|
projectionAssetSummary.resolvedLocateStructures(),
|
||||||
|
projectionAssetSummary.syntheticStructureSets(),
|
||||||
|
projectionAssetSummary.projectedStructureKeys()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProjectionAssetSummary buildProjectedAssets(File source, SourceDescriptor sourceDescriptor, DatapackRequest request) throws IOException {
|
private static ProjectionAssetSummary buildProjectedAssets(File source, SourceDescriptor sourceDescriptor, DatapackRequest request) throws IOException {
|
||||||
@@ -1081,7 +1355,16 @@ public final class ExternalDataPackPipeline {
|
|||||||
|
|
||||||
List<ProjectionInputAsset> inputAssets = projectionSelection.assets();
|
List<ProjectionInputAsset> inputAssets = projectionSelection.assets();
|
||||||
if (inputAssets.isEmpty()) {
|
if (inputAssets.isEmpty()) {
|
||||||
return new ProjectionAssetSummary(List.of(), Set.copyOf(request.resolvedLocateStructures()), 0);
|
return new ProjectionAssetSummary(List.of(), Set.copyOf(request.resolvedLocateStructures()), 0, Set.of());
|
||||||
|
}
|
||||||
|
int selectedStructureNbtCount = 0;
|
||||||
|
for (ProjectionInputAsset inputAsset : inputAssets) {
|
||||||
|
if (inputAsset == null || inputAsset.entry() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inputAsset.entry().type() == ProjectedEntryType.STRUCTURE_NBT) {
|
||||||
|
selectedStructureNbtCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String scopeNamespace = buildScopeNamespace(sourceDescriptor, request);
|
String scopeNamespace = buildScopeNamespace(sourceDescriptor, request);
|
||||||
@@ -1103,9 +1386,11 @@ public final class ExternalDataPackPipeline {
|
|||||||
LinkedHashSet<String> resolvedLocateStructures = new LinkedHashSet<>();
|
LinkedHashSet<String> resolvedLocateStructures = new LinkedHashSet<>();
|
||||||
resolvedLocateStructures.addAll(request.resolvedLocateStructures());
|
resolvedLocateStructures.addAll(request.resolvedLocateStructures());
|
||||||
LinkedHashSet<String> remappedStructureKeys = new LinkedHashSet<>();
|
LinkedHashSet<String> remappedStructureKeys = new LinkedHashSet<>();
|
||||||
|
LinkedHashSet<String> projectedStructureKeys = new LinkedHashSet<>();
|
||||||
LinkedHashSet<String> structureSetReferences = new LinkedHashSet<>();
|
LinkedHashSet<String> structureSetReferences = new LinkedHashSet<>();
|
||||||
LinkedHashSet<String> writtenPaths = new LinkedHashSet<>();
|
LinkedHashSet<String> writtenPaths = new LinkedHashSet<>();
|
||||||
ArrayList<ProjectionOutputAsset> outputAssets = new ArrayList<>();
|
ArrayList<ProjectionOutputAsset> outputAssets = new ArrayList<>();
|
||||||
|
int projectedCanonicalStructureNbtCount = 0;
|
||||||
|
|
||||||
for (ProjectionInputAsset inputAsset : inputAssets) {
|
for (ProjectionInputAsset inputAsset : inputAssets) {
|
||||||
ProjectedEntry projectedEntry = inputAsset.entry();
|
ProjectedEntry projectedEntry = inputAsset.entry();
|
||||||
@@ -1152,6 +1437,10 @@ public final class ExternalDataPackPipeline {
|
|||||||
|
|
||||||
remappedStructureKeys.add(effectiveEntry.key());
|
remappedStructureKeys.add(effectiveEntry.key());
|
||||||
resolvedLocateStructures.add(effectiveEntry.key());
|
resolvedLocateStructures.add(effectiveEntry.key());
|
||||||
|
String normalizedProjectedStructure = normalizeLocateStructure(effectiveEntry.key());
|
||||||
|
if (!normalizedProjectedStructure.isBlank()) {
|
||||||
|
projectedStructureKeys.add(normalizedProjectedStructure);
|
||||||
|
}
|
||||||
} else if (projectedEntry.type() == ProjectedEntryType.STRUCTURE_SET) {
|
} else if (projectedEntry.type() == ProjectedEntryType.STRUCTURE_SET) {
|
||||||
structureSetReferences.addAll(readStructureSetReferences(root));
|
structureSetReferences.addAll(readStructureSetReferences(root));
|
||||||
}
|
}
|
||||||
@@ -1160,6 +1449,11 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outputAssets.add(new ProjectionOutputAsset(outputRelativePath, outputBytes));
|
outputAssets.add(new ProjectionOutputAsset(outputRelativePath, outputBytes));
|
||||||
|
if (projectedEntry.type() == ProjectedEntryType.STRUCTURE_NBT
|
||||||
|
&& outputRelativePath.endsWith(".nbt")
|
||||||
|
&& outputRelativePath.contains("/structure/")) {
|
||||||
|
projectedCanonicalStructureNbtCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int syntheticStructureSets = 0;
|
int syntheticStructureSets = 0;
|
||||||
@@ -1195,7 +1489,11 @@ public final class ExternalDataPackPipeline {
|
|||||||
outputAssets.add(new ProjectionOutputAsset(tagPath, root.toString(4).getBytes(StandardCharsets.UTF_8)));
|
outputAssets.add(new ProjectionOutputAsset(tagPath, root.toString(4).getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProjectionAssetSummary(outputAssets, Set.copyOf(resolvedLocateStructures), syntheticStructureSets);
|
if (request.required() && selectedStructureNbtCount > 0 && projectedCanonicalStructureNbtCount <= 0) {
|
||||||
|
throw new IOException("Required external datapack projection produced no canonical structure template outputs (data/*/structure/*.nbt).");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ProjectionAssetSummary(outputAssets, Set.copyOf(resolvedLocateStructures), syntheticStructureSets, Set.copyOf(projectedStructureKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProjectionSelection readProjectedEntries(File source, DatapackRequest request) throws IOException {
|
private static ProjectionSelection readProjectedEntries(File source, DatapackRequest request) throws IOException {
|
||||||
@@ -1775,7 +2073,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
case TEMPLATE_POOL -> "data/" + namespace + "/worldgen/template_pool/" + path + ".json";
|
case TEMPLATE_POOL -> "data/" + namespace + "/worldgen/template_pool/" + path + ".json";
|
||||||
case PROCESSOR_LIST -> "data/" + namespace + "/worldgen/processor_list/" + path + ".json";
|
case PROCESSOR_LIST -> "data/" + namespace + "/worldgen/processor_list/" + path + ".json";
|
||||||
case BIOME_HAS_STRUCTURE_TAG -> "data/" + namespace + "/tags/worldgen/biome/has_structure/" + path + ".json";
|
case BIOME_HAS_STRUCTURE_TAG -> "data/" + namespace + "/tags/worldgen/biome/has_structure/" + path + ".json";
|
||||||
case STRUCTURE_NBT -> "data/" + namespace + "/structures/" + path + ".nbt";
|
case STRUCTURE_NBT -> "data/" + namespace + "/structure/" + path + ".nbt";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3090,6 +3388,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
String requiredEnvironment,
|
String requiredEnvironment,
|
||||||
boolean required,
|
boolean required,
|
||||||
boolean replaceVanilla,
|
boolean replaceVanilla,
|
||||||
|
boolean supportSmartBore,
|
||||||
Set<String> structures,
|
Set<String> structures,
|
||||||
Set<String> structureSets,
|
Set<String> structureSets,
|
||||||
Set<String> configuredFeatures,
|
Set<String> configuredFeatures,
|
||||||
@@ -3110,6 +3409,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
String requiredEnvironment,
|
String requiredEnvironment,
|
||||||
boolean required,
|
boolean required,
|
||||||
boolean replaceVanilla,
|
boolean replaceVanilla,
|
||||||
|
boolean supportSmartBore,
|
||||||
IrisExternalDatapackReplaceTargets replaceTargets,
|
IrisExternalDatapackReplaceTargets replaceTargets,
|
||||||
KList<IrisExternalDatapackStructurePatch> structurePatches
|
KList<IrisExternalDatapackStructurePatch> structurePatches
|
||||||
) {
|
) {
|
||||||
@@ -3120,6 +3420,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
requiredEnvironment,
|
requiredEnvironment,
|
||||||
required,
|
required,
|
||||||
replaceVanilla,
|
replaceVanilla,
|
||||||
|
supportSmartBore,
|
||||||
replaceTargets,
|
replaceTargets,
|
||||||
structurePatches,
|
structurePatches,
|
||||||
Set.of(),
|
Set.of(),
|
||||||
@@ -3136,6 +3437,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
String requiredEnvironment,
|
String requiredEnvironment,
|
||||||
boolean required,
|
boolean required,
|
||||||
boolean replaceVanilla,
|
boolean replaceVanilla,
|
||||||
|
boolean supportSmartBore,
|
||||||
IrisExternalDatapackReplaceTargets replaceTargets,
|
IrisExternalDatapackReplaceTargets replaceTargets,
|
||||||
KList<IrisExternalDatapackStructurePatch> structurePatches,
|
KList<IrisExternalDatapackStructurePatch> structurePatches,
|
||||||
Set<String> forcedBiomeKeys,
|
Set<String> forcedBiomeKeys,
|
||||||
@@ -3150,6 +3452,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
normalizeEnvironment(requiredEnvironment),
|
normalizeEnvironment(requiredEnvironment),
|
||||||
required,
|
required,
|
||||||
replaceVanilla,
|
replaceVanilla,
|
||||||
|
supportSmartBore,
|
||||||
normalizeTargets(replaceTargets == null ? null : replaceTargets.getStructures(), "worldgen/structure/"),
|
normalizeTargets(replaceTargets == null ? null : replaceTargets.getStructures(), "worldgen/structure/"),
|
||||||
normalizeTargets(replaceTargets == null ? null : replaceTargets.getStructureSets(), "worldgen/structure_set/"),
|
normalizeTargets(replaceTargets == null ? null : replaceTargets.getStructureSets(), "worldgen/structure_set/"),
|
||||||
normalizeTargets(replaceTargets == null ? null : replaceTargets.getConfiguredFeatures(), "worldgen/configured_feature/"),
|
normalizeTargets(replaceTargets == null ? null : replaceTargets.getConfiguredFeatures(), "worldgen/configured_feature/"),
|
||||||
@@ -3216,6 +3519,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
environment,
|
environment,
|
||||||
required || other.required,
|
required || other.required,
|
||||||
replaceVanilla || other.replaceVanilla,
|
replaceVanilla || other.replaceVanilla,
|
||||||
|
supportSmartBore || other.supportSmartBore,
|
||||||
union(structures, other.structures),
|
union(structures, other.structures),
|
||||||
union(structureSets, other.structureSets),
|
union(structureSets, other.structureSets),
|
||||||
union(configuredFeatures, other.configuredFeatures),
|
union(configuredFeatures, other.configuredFeatures),
|
||||||
@@ -3573,6 +3877,7 @@ public final class ExternalDataPackPipeline {
|
|||||||
int installedAssets,
|
int installedAssets,
|
||||||
Set<String> resolvedLocateStructures,
|
Set<String> resolvedLocateStructures,
|
||||||
int syntheticStructureSets,
|
int syntheticStructureSets,
|
||||||
|
Set<String> projectedStructureKeys,
|
||||||
String managedName,
|
String managedName,
|
||||||
String error
|
String error
|
||||||
) {
|
) {
|
||||||
@@ -3587,6 +3892,16 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolvedLocateStructures = Set.copyOf(normalized);
|
resolvedLocateStructures = Set.copyOf(normalized);
|
||||||
|
LinkedHashSet<String> normalizedProjected = new LinkedHashSet<>();
|
||||||
|
if (projectedStructureKeys != null) {
|
||||||
|
for (String structure : projectedStructureKeys) {
|
||||||
|
String normalizedStructure = normalizeLocateStructure(structure);
|
||||||
|
if (!normalizedStructure.isBlank()) {
|
||||||
|
normalizedProjected.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectedStructureKeys = Set.copyOf(normalizedProjected);
|
||||||
syntheticStructureSets = Math.max(0, syntheticStructureSets);
|
syntheticStructureSets = Math.max(0, syntheticStructureSets);
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
error = "";
|
error = "";
|
||||||
@@ -3598,14 +3913,15 @@ public final class ExternalDataPackPipeline {
|
|||||||
int installedDatapacks,
|
int installedDatapacks,
|
||||||
int installedAssets,
|
int installedAssets,
|
||||||
Set<String> resolvedLocateStructures,
|
Set<String> resolvedLocateStructures,
|
||||||
int syntheticStructureSets
|
int syntheticStructureSets,
|
||||||
|
Set<String> projectedStructureKeys
|
||||||
) {
|
) {
|
||||||
return new ProjectionResult(true, installedDatapacks, installedAssets, resolvedLocateStructures, syntheticStructureSets, managedName, "");
|
return new ProjectionResult(true, installedDatapacks, installedAssets, resolvedLocateStructures, syntheticStructureSets, projectedStructureKeys, managedName, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProjectionResult failure(String managedName, String error) {
|
private static ProjectionResult failure(String managedName, String error) {
|
||||||
String message = error == null || error.isBlank() ? "projection failed" : error;
|
String message = error == null || error.isBlank() ? "projection failed" : error;
|
||||||
return new ProjectionResult(false, 0, 0, Set.of(), 0, managedName, message);
|
return new ProjectionResult(false, 0, 0, Set.of(), 0, Set.of(), managedName, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3621,7 +3937,12 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ProjectionAssetSummary(List<ProjectionOutputAsset> assets, Set<String> resolvedLocateStructures, int syntheticStructureSets) {
|
private record ProjectionAssetSummary(
|
||||||
|
List<ProjectionOutputAsset> assets,
|
||||||
|
Set<String> resolvedLocateStructures,
|
||||||
|
int syntheticStructureSets,
|
||||||
|
Set<String> projectedStructureKeys
|
||||||
|
) {
|
||||||
private ProjectionAssetSummary {
|
private ProjectionAssetSummary {
|
||||||
assets = assets == null ? List.of() : List.copyOf(assets);
|
assets = assets == null ? List.of() : List.copyOf(assets);
|
||||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||||
@@ -3634,6 +3955,16 @@ public final class ExternalDataPackPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolvedLocateStructures = Set.copyOf(normalized);
|
resolvedLocateStructures = Set.copyOf(normalized);
|
||||||
|
LinkedHashSet<String> normalizedProjected = new LinkedHashSet<>();
|
||||||
|
if (projectedStructureKeys != null) {
|
||||||
|
for (String structure : projectedStructureKeys) {
|
||||||
|
String normalizedStructure = normalizeLocateStructure(structure);
|
||||||
|
if (!normalizedStructure.isBlank()) {
|
||||||
|
normalizedProjected.add(normalizedStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectedStructureKeys = Set.copyOf(normalizedProjected);
|
||||||
syntheticStructureSets = Math.max(0, syntheticStructureSets);
|
syntheticStructureSets = Math.max(0, syntheticStructureSets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import art.arcane.iris.core.loader.ResourceLoader;
|
|||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||||
import art.arcane.iris.core.nms.datapack.IDataFixer;
|
import art.arcane.iris.core.nms.datapack.IDataFixer;
|
||||||
|
import art.arcane.iris.engine.IrisNoisemapPrebakePipeline;
|
||||||
import art.arcane.iris.engine.object.*;
|
import art.arcane.iris.engine.object.*;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
@@ -76,7 +77,10 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deferredInstallPending = false;
|
deferredInstallPending = false;
|
||||||
installDataPacks(true);
|
boolean datapacksMissing = installDataPacks(true);
|
||||||
|
if (!datapacksMissing) {
|
||||||
|
IrisNoisemapPrebakePipeline.scheduleInstalledPacksPrebakeAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void configureIfDeferred() {
|
public static void configureIfDeferred() {
|
||||||
@@ -135,13 +139,21 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean installDataPacks(boolean fullInstall, boolean includeExternal) {
|
public static boolean installDataPacks(boolean fullInstall, boolean includeExternal) {
|
||||||
|
return installDataPacks(fullInstall, includeExternal, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean installDataPacks(
|
||||||
|
boolean fullInstall,
|
||||||
|
boolean includeExternal,
|
||||||
|
KMap<String, KList<File>> extraWorldDatapackFoldersByPack
|
||||||
|
) {
|
||||||
IDataFixer fixer = DataVersion.getDefault();
|
IDataFixer fixer = DataVersion.getDefault();
|
||||||
if (fixer == null) {
|
if (fixer == null) {
|
||||||
DataVersion fallback = DataVersion.getLatest();
|
DataVersion fallback = DataVersion.getLatest();
|
||||||
Iris.warn("Primary datapack fixer was null, forcing latest fixer: " + fallback.getVersion());
|
Iris.warn("Primary datapack fixer was null, forcing latest fixer: " + fallback.getVersion());
|
||||||
fixer = fallback.get();
|
fixer = fallback.get();
|
||||||
}
|
}
|
||||||
return installDataPacks(fixer, fullInstall, includeExternal);
|
return installDataPacks(fixer, fullInstall, includeExternal, extraWorldDatapackFoldersByPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
||||||
@@ -149,6 +161,15 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall, boolean includeExternal) {
|
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall, boolean includeExternal) {
|
||||||
|
return installDataPacks(fixer, fullInstall, includeExternal, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean installDataPacks(
|
||||||
|
IDataFixer fixer,
|
||||||
|
boolean fullInstall,
|
||||||
|
boolean includeExternal,
|
||||||
|
KMap<String, KList<File>> extraWorldDatapackFoldersByPack
|
||||||
|
) {
|
||||||
if (fixer == null) {
|
if (fixer == null) {
|
||||||
Iris.error("Unable to install datapacks, fixer is null!");
|
Iris.error("Unable to install datapacks, fixer is null!");
|
||||||
return false;
|
return false;
|
||||||
@@ -161,7 +182,7 @@ public class ServerConfigurator {
|
|||||||
DimensionHeight height = new DimensionHeight(fixer);
|
DimensionHeight height = new DimensionHeight(fixer);
|
||||||
KList<File> folders = getDatapacksFolder();
|
KList<File> folders = getDatapacksFolder();
|
||||||
if (includeExternal) {
|
if (includeExternal) {
|
||||||
installExternalDataPacks(folders);
|
installExternalDataPacks(folders, extraWorldDatapackFoldersByPack);
|
||||||
}
|
}
|
||||||
KMap<String, KSet<String>> biomes = new KMap<>();
|
KMap<String, KSet<String>> biomes = new KMap<>();
|
||||||
|
|
||||||
@@ -184,13 +205,16 @@ public class ServerConfigurator {
|
|||||||
return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
|
return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void installExternalDataPacks(KList<File> folders) {
|
private static void installExternalDataPacks(
|
||||||
|
KList<File> folders,
|
||||||
|
KMap<String, KList<File>> extraWorldDatapackFoldersByPack
|
||||||
|
) {
|
||||||
if (!IrisSettings.get().getGeneral().isImportExternalDatapacks()) {
|
if (!IrisSettings.get().getGeneral().isImportExternalDatapacks()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KList<ExternalDataPackPipeline.DatapackRequest> requests = collectExternalDatapackRequests();
|
KList<ExternalDataPackPipeline.DatapackRequest> requests = collectExternalDatapackRequests();
|
||||||
KMap<String, KList<File>> worldDatapackFoldersByPack = collectWorldDatapackFoldersByPack(folders);
|
KMap<String, KList<File>> worldDatapackFoldersByPack = collectWorldDatapackFoldersByPack(folders, extraWorldDatapackFoldersByPack);
|
||||||
ExternalDataPackPipeline.PipelineSummary summary = ExternalDataPackPipeline.processDatapacks(requests, worldDatapackFoldersByPack);
|
ExternalDataPackPipeline.PipelineSummary summary = ExternalDataPackPipeline.processDatapacks(requests, worldDatapackFoldersByPack);
|
||||||
if (summary.getLegacyDownloadRemovals() > 0) {
|
if (summary.getLegacyDownloadRemovals() > 0) {
|
||||||
Iris.verbose("Removed " + summary.getLegacyDownloadRemovals() + " legacy global datapack downloads.");
|
Iris.verbose("Removed " + summary.getLegacyDownloadRemovals() + " legacy global datapack downloads.");
|
||||||
@@ -315,6 +339,7 @@ public class ServerConfigurator {
|
|||||||
environment,
|
environment,
|
||||||
definition.isRequired(),
|
definition.isRequired(),
|
||||||
definition.isReplaceVanilla(),
|
definition.isReplaceVanilla(),
|
||||||
|
definition.isSupportSmartBore(),
|
||||||
definition.getReplaceTargets(),
|
definition.getReplaceTargets(),
|
||||||
definition.getStructurePatches(),
|
definition.getStructurePatches(),
|
||||||
Set.of(),
|
Set.of(),
|
||||||
@@ -343,6 +368,7 @@ public class ServerConfigurator {
|
|||||||
environment,
|
environment,
|
||||||
group.required(),
|
group.required(),
|
||||||
group.replaceVanilla(),
|
group.replaceVanilla(),
|
||||||
|
definition.isSupportSmartBore(),
|
||||||
definition.getReplaceTargets(),
|
definition.getReplaceTargets(),
|
||||||
definition.getStructurePatches(),
|
definition.getStructurePatches(),
|
||||||
group.forcedBiomeKeys(),
|
group.forcedBiomeKeys(),
|
||||||
@@ -871,7 +897,10 @@ public class ServerConfigurator {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KMap<String, KList<File>> collectWorldDatapackFoldersByPack(KList<File> fallbackFolders) {
|
private static KMap<String, KList<File>> collectWorldDatapackFoldersByPack(
|
||||||
|
KList<File> fallbackFolders,
|
||||||
|
KMap<String, KList<File>> extraWorldDatapackFoldersByPack
|
||||||
|
) {
|
||||||
KMap<String, KList<File>> foldersByPack = new KMap<>();
|
KMap<String, KList<File>> foldersByPack = new KMap<>();
|
||||||
KMap<String, String> mappedWorlds = IrisWorlds.get().getWorlds();
|
KMap<String, String> mappedWorlds = IrisWorlds.get().getWorlds();
|
||||||
|
|
||||||
@@ -905,6 +934,22 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extraWorldDatapackFoldersByPack != null && !extraWorldDatapackFoldersByPack.isEmpty()) {
|
||||||
|
for (Map.Entry<String, KList<File>> entry : extraWorldDatapackFoldersByPack.entrySet()) {
|
||||||
|
String packName = sanitizePackName(entry.getKey());
|
||||||
|
if (packName.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
KList<File> folders = entry.getValue();
|
||||||
|
if (folders == null || folders.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (File folder : folders) {
|
||||||
|
addWorldDatapackFolder(foldersByPack, packName, folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return foldersByPack;
|
return foldersByPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import art.arcane.volmlib.util.director.annotations.Director;
|
|||||||
import art.arcane.volmlib.util.director.annotations.Param;
|
import art.arcane.volmlib.util.director.annotations.Param;
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
import art.arcane.volmlib.util.matter.MatterMarker;
|
import art.arcane.volmlib.util.matter.MatterMarker;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.FluidCollisionMode;
|
import org.bukkit.FluidCollisionMode;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -161,7 +160,7 @@ public class CommandWhat implements DirectorExecutor {
|
|||||||
for (int zzz = c.getZ() - 4; zzz <= c.getZ() + 4; zzz++) {
|
for (int zzz = c.getZ() - 4; zzz <= c.getZ() + 4; zzz++) {
|
||||||
IrisToolbelt.access(c.getWorld()).getEngine().getMantle().findMarkers(xxx, zzz, new MatterMarker(marker))
|
IrisToolbelt.access(c.getWorld()).getEngine().getMantle().findMarkers(xxx, zzz, new MatterMarker(marker))
|
||||||
.convert((i) -> i.toLocation(c.getWorld())).forEach((i) -> {
|
.convert((i) -> i.toLocation(c.getWorld())).forEach((i) -> {
|
||||||
J.s(() -> BlockSignal.of(i.getBlock(), 100));
|
BlockSignal.of(i.getWorld(), i.getBlockX(), i.getBlockY(), i.getBlockZ(), 100);
|
||||||
v.incrementAndGet();
|
v.incrementAndGet();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,11 @@
|
|||||||
|
|
||||||
package art.arcane.iris.core.edit;
|
package art.arcane.iris.core.edit;
|
||||||
|
|
||||||
import art.arcane.iris.util.common.parallel.MultiBurst;
|
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.scheduling.SR;
|
import art.arcane.volmlib.util.scheduling.SR;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.entity.FallingBlock;
|
import org.bukkit.entity.FallingBlock;
|
||||||
@@ -46,26 +47,51 @@ public class BlockSignal {
|
|||||||
e.setSilent(true);
|
e.setSilent(true);
|
||||||
e.setTicksLived(1);
|
e.setTicksLived(1);
|
||||||
e.setVelocity(new Vector(0, 0, 0));
|
e.setVelocity(new Vector(0, 0, 0));
|
||||||
J.s(() -> {
|
Location blockLocation = block.getLocation();
|
||||||
|
Runnable removeTask = () -> {
|
||||||
|
if (!J.runEntity(e, e::remove) && !e.isDead()) {
|
||||||
e.remove();
|
e.remove();
|
||||||
active.decrementAndGet();
|
|
||||||
BlockData type = block.getBlockData();
|
|
||||||
MultiBurst.burst.lazy(() -> {
|
|
||||||
for (Player i : block.getWorld().getPlayers()) {
|
|
||||||
i.sendBlockChange(block.getLocation(), block.getBlockData());
|
|
||||||
}
|
}
|
||||||
});
|
active.decrementAndGet();
|
||||||
}, ticks);
|
sendBlockRefresh(block);
|
||||||
|
};
|
||||||
|
if (!J.runAt(blockLocation, removeTask, ticks)) {
|
||||||
|
if (!J.isFolia()) {
|
||||||
|
J.s(removeTask, ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void of(Block block, int ticks) {
|
public static void of(Block block, int ticks) {
|
||||||
new BlockSignal(block, ticks);
|
if (block == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
of(block.getWorld(), block.getX(), block.getY(), block.getZ(), ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void of(Block block) {
|
public static void of(Block block) {
|
||||||
of(block, 100);
|
of(block, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void of(World world, int x, int y, int z, int ticks) {
|
||||||
|
if (world == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location location = new Location(world, x, y, z);
|
||||||
|
Runnable createTask = () -> new BlockSignal(world.getBlockAt(x, y, z), ticks);
|
||||||
|
if (!J.runAt(location, createTask)) {
|
||||||
|
if (!J.isFolia()) {
|
||||||
|
J.s(createTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void of(World world, int x, int y, int z) {
|
||||||
|
of(world, x, y, z, 100);
|
||||||
|
}
|
||||||
|
|
||||||
public static Runnable forever(Block block) {
|
public static Runnable forever(Block block) {
|
||||||
Location tg = block.getLocation().clone().add(0.5, 0, 0.5).clone();
|
Location tg = block.getLocation().clone().add(0.5, 0, 0.5).clone();
|
||||||
FallingBlock e = block.getWorld().spawnFallingBlock(tg.clone(), block.getBlockData());
|
FallingBlock e = block.getWorld().spawnFallingBlock(tg.clone(), block.getBlockData());
|
||||||
@@ -82,6 +108,7 @@ public class BlockSignal {
|
|||||||
new SR(20) {
|
new SR(20) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
if (!J.runEntity(e, () -> {
|
||||||
if (e.isDead()) {
|
if (e.isDead()) {
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
@@ -90,18 +117,37 @@ public class BlockSignal {
|
|||||||
e.setTicksLived(1);
|
e.setTicksLived(1);
|
||||||
e.teleport(tg.clone());
|
e.teleport(tg.clone());
|
||||||
e.setVelocity(new Vector(0, 0, 0));
|
e.setVelocity(new Vector(0, 0, 0));
|
||||||
|
})) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return () -> {
|
return () -> {
|
||||||
|
if (!J.runEntity(e, e::remove) && !e.isDead()) {
|
||||||
e.remove();
|
e.remove();
|
||||||
BlockData type = block.getBlockData();
|
|
||||||
|
|
||||||
MultiBurst.burst.lazy(() -> {
|
|
||||||
for (Player i : block.getWorld().getPlayers()) {
|
|
||||||
i.sendBlockChange(block.getLocation(), block.getBlockData());
|
|
||||||
}
|
}
|
||||||
});
|
Location blockLocation = block.getLocation();
|
||||||
|
Runnable refreshTask = () -> sendBlockRefresh(block);
|
||||||
|
if (!J.runAt(blockLocation, refreshTask)) {
|
||||||
|
refreshTask.run();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void sendBlockRefresh(Block block) {
|
||||||
|
if (block == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location location = block.getLocation();
|
||||||
|
BlockData blockData = block.getBlockData();
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (!player.getWorld().equals(location.getWorld())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
J.runEntity(player, () -> player.sendBlockChange(location, blockData));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import art.arcane.volmlib.util.math.RNG;
|
|||||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
@@ -48,8 +49,9 @@ public class DustRevealer {
|
|||||||
this.key = key;
|
this.key = key;
|
||||||
this.hits = hits;
|
this.hits = hits;
|
||||||
|
|
||||||
J.s(() -> {
|
Location blockLocation = block.toBlock(world).getLocation();
|
||||||
new BlockSignal(world.getBlockAt(block.getX(), block.getY(), block.getZ()), 10);
|
Runnable revealTask = () -> {
|
||||||
|
BlockSignal.of(world, block.getX(), block.getY(), block.getZ(), 10);
|
||||||
if (M.r(0.25)) {
|
if (M.r(0.25)) {
|
||||||
world.playSound(block.toBlock(world).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 1f, RNG.r.f(0.2f, 2f));
|
world.playSound(block.toBlock(world).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 1f, RNG.r.f(0.2f, 2f));
|
||||||
}
|
}
|
||||||
@@ -90,7 +92,13 @@ public class DustRevealer {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, RNG.r.i(2, 8));
|
};
|
||||||
|
int delay = RNG.r.i(2, 8);
|
||||||
|
if (!J.runAt(blockLocation, revealTask, delay)) {
|
||||||
|
if (!J.isFolia()) {
|
||||||
|
J.s(revealTask, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void spawn(Block block, VolmitSender sender) {
|
public static void spawn(Block block, VolmitSender sender) {
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ import art.arcane.iris.engine.IrisNoisemapPrebakePipeline;
|
|||||||
import art.arcane.iris.engine.framework.SeedManager;
|
import art.arcane.iris.engine.framework.SeedManager;
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import art.arcane.volmlib.util.exceptions.IrisException;
|
import art.arcane.volmlib.util.exceptions.IrisException;
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
import art.arcane.volmlib.util.format.Form;
|
import art.arcane.volmlib.util.format.Form;
|
||||||
@@ -166,8 +168,16 @@ public class IrisCreator {
|
|||||||
IrisWorlds.get().put(name(), dimension());
|
IrisWorlds.get().put(name(), dimension());
|
||||||
}
|
}
|
||||||
boolean verifyDataPacks = !studio();
|
boolean verifyDataPacks = !studio();
|
||||||
boolean includeExternalDataPacks = !studio();
|
boolean includeExternalDataPacks = true;
|
||||||
if (ServerConfigurator.installDataPacks(verifyDataPacks, includeExternalDataPacks)) {
|
KMap<String, KList<File>> extraWorldDatapackFoldersByPack = null;
|
||||||
|
if (studio()) {
|
||||||
|
File studioDatapackFolder = new File(new File(Bukkit.getWorldContainer(), name()), "datapacks");
|
||||||
|
KList<File> studioDatapackFolders = new KList<>();
|
||||||
|
studioDatapackFolders.add(studioDatapackFolder);
|
||||||
|
extraWorldDatapackFoldersByPack = new KMap<>();
|
||||||
|
extraWorldDatapackFoldersByPack.put(d.getLoadKey(), studioDatapackFolders);
|
||||||
|
}
|
||||||
|
if (ServerConfigurator.installDataPacks(verifyDataPacks, includeExternalDataPacks, extraWorldDatapackFoldersByPack)) {
|
||||||
throw new IrisException("Datapacks were missing!");
|
throw new IrisException("Datapacks were missing!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +305,13 @@ public class IrisCreator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (studio() && !benchmark) {
|
||||||
|
boolean startupPrebakeReady = IrisNoisemapPrebakePipeline.awaitInstalledPacksPrebakeForStudio();
|
||||||
|
if (startupPrebakeReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File targetDataFolder = new File(Bukkit.getWorldContainer(), name());
|
File targetDataFolder = new File(Bukkit.getWorldContainer(), name());
|
||||||
if (studio() && !benchmark) {
|
if (studio() && !benchmark) {
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import java.util.Map;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletionService;
|
import java.util.concurrent.CompletionService;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorCompletionService;
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@@ -45,7 +47,9 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
public final class IrisNoisemapPrebakePipeline {
|
public final class IrisNoisemapPrebakePipeline {
|
||||||
@@ -53,7 +57,10 @@ public final class IrisNoisemapPrebakePipeline {
|
|||||||
private static final long STARTUP_PROGRESS_INTERVAL_MS = Long.getLong("iris.prebake.progress.interval", 30000L);
|
private static final long STARTUP_PROGRESS_INTERVAL_MS = Long.getLong("iris.prebake.progress.interval", 30000L);
|
||||||
private static final int STATE_VERSION = 1;
|
private static final int STATE_VERSION = 1;
|
||||||
private static final String STATE_FILE = "noisemap-prebake.state";
|
private static final String STATE_FILE = "noisemap-prebake.state";
|
||||||
|
private static final AtomicBoolean STARTUP_PREBAKE_SCHEDULED = new AtomicBoolean(false);
|
||||||
|
private static final AtomicBoolean STARTUP_PREBAKE_FAILURE_REPORTED = new AtomicBoolean(false);
|
||||||
private static final AtomicInteger STARTUP_WORKER_SEQUENCE = new AtomicInteger();
|
private static final AtomicInteger STARTUP_WORKER_SEQUENCE = new AtomicInteger();
|
||||||
|
private static final AtomicReference<CompletableFuture<Void>> STARTUP_PREBAKE_COMPLETION = new AtomicReference<>();
|
||||||
private static final ConcurrentHashMap<Class<?>, Field[]> FIELD_CACHE = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Class<?>, Field[]> FIELD_CACHE = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<String, Boolean> SKIP_ONCE = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<String, Boolean> SKIP_ONCE = new ConcurrentHashMap<>();
|
||||||
private static final Set<String> PREBAKE_LOADERS = Set.of(
|
private static final Set<String> PREBAKE_LOADERS = Set.of(
|
||||||
@@ -83,9 +90,64 @@ public final class IrisNoisemapPrebakePipeline {
|
|||||||
private IrisNoisemapPrebakePipeline() {
|
private IrisNoisemapPrebakePipeline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void prebakeInstalledPacksAtStartup() {
|
public static void scheduleInstalledPacksPrebakeAsync() {
|
||||||
IrisSettings.IrisSettingsPregen settings = IrisSettings.get().getPregen();
|
if (!IrisSettings.get().getPregen().isStartupNoisemapPrebake()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STARTUP_PREBAKE_SCHEDULED.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<Void> completion = new CompletableFuture<>();
|
||||||
|
STARTUP_PREBAKE_COMPLETION.set(completion);
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
prebakeInstalledPacksAtStartup();
|
||||||
|
completion.complete(null);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
completion.completeExceptionally(throwable);
|
||||||
|
if (STARTUP_PREBAKE_FAILURE_REPORTED.compareAndSet(false, true)) {
|
||||||
|
Iris.warn("Startup noisemap pre-bake failed.");
|
||||||
|
Iris.reportError(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "Iris-StartupNoisemapPrebake");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean awaitInstalledPacksPrebakeForStudio() {
|
||||||
|
if (!IrisSettings.get().getPregen().isStartupNoisemapPrebake()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleInstalledPacksPrebakeAsync();
|
||||||
|
CompletableFuture<Void> completion = STARTUP_PREBAKE_COMPLETION.get();
|
||||||
|
if (completion == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
completion.join();
|
||||||
|
return true;
|
||||||
|
} catch (CompletionException e) {
|
||||||
|
Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||||
|
if (STARTUP_PREBAKE_FAILURE_REPORTED.compareAndSet(false, true)) {
|
||||||
|
Iris.warn("Startup noisemap pre-bake failed.");
|
||||||
|
Iris.reportError(cause);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
if (STARTUP_PREBAKE_FAILURE_REPORTED.compareAndSet(false, true)) {
|
||||||
|
Iris.warn("Startup noisemap pre-bake failed.");
|
||||||
|
Iris.reportError(throwable);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void prebakeInstalledPacksAtStartup() {
|
||||||
List<PrebakeTarget> targets = collectStartupTargets();
|
List<PrebakeTarget> targets = collectStartupTargets();
|
||||||
if (targets.isEmpty()) {
|
if (targets.isEmpty()) {
|
||||||
Iris.info("Startup noisemap pre-bake skipped (no installed or self-contained packs found).");
|
Iris.info("Startup noisemap pre-bake skipped (no installed or self-contained packs found).");
|
||||||
|
|||||||
@@ -213,8 +213,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
J.s(() -> {
|
for (Player player : getEngine().getWorld().getPlayers()) {
|
||||||
for (Player player : world.getPlayers()) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
if (player == null || !player.isOnline()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -232,7 +231,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void raiseDiscoveredChunkFlag(World world, int chunkX, int chunkZ) {
|
private void raiseDiscoveredChunkFlag(World world, int chunkX, int chunkZ) {
|
||||||
@@ -274,8 +272,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
J.s(() -> {
|
for (Player player : getEngine().getWorld().getPlayers()) {
|
||||||
for (Player player : world.getPlayers()) {
|
|
||||||
if (player == null || !player.isOnline()) {
|
if (player == null || !player.isOnline()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -294,7 +291,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChunkRegion(World world, int chunkX, int chunkZ) {
|
private void updateChunkRegion(World world, int chunkX, int chunkZ) {
|
||||||
@@ -432,7 +428,22 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
if (cl.flip()) {
|
if (cl.flip()) {
|
||||||
try {
|
try {
|
||||||
J.s(() -> precount = getEngine().getWorld().realWorld().getEntities());
|
World realWorld = getEngine().getWorld().realWorld();
|
||||||
|
if (realWorld == null) {
|
||||||
|
precount = new KList<>();
|
||||||
|
} else if (J.isFolia()) {
|
||||||
|
precount = getFoliaEntitySnapshot(realWorld);
|
||||||
|
} else {
|
||||||
|
CompletableFuture<List<Entity>> future = new CompletableFuture<>();
|
||||||
|
J.s(() -> {
|
||||||
|
try {
|
||||||
|
future.complete(realWorld.getEntities());
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
future.completeExceptionally(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
precount = future.get(2, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -499,6 +510,47 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Entity> getFoliaEntitySnapshot(World world) {
|
||||||
|
Map<String, Entity> snapshot = new ConcurrentHashMap<>();
|
||||||
|
List<Player> players = getEngine().getWorld().getPlayers();
|
||||||
|
if (players == null || players.isEmpty()) {
|
||||||
|
return new KList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(players.size());
|
||||||
|
for (Player player : players) {
|
||||||
|
if (player == null || !player.isOnline() || !world.equals(player.getWorld())) {
|
||||||
|
latch.countDown();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!J.runEntity(player, () -> {
|
||||||
|
try {
|
||||||
|
snapshot.put(player.getUniqueId().toString(), player);
|
||||||
|
for (Entity nearby : player.getNearbyEntities(64, 64, 64)) {
|
||||||
|
if (nearby != null && world.equals(nearby.getWorld())) {
|
||||||
|
snapshot.put(nearby.getUniqueId().toString(), nearby);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
latch.await(2, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
KList<Entity> entities = new KList<>();
|
||||||
|
entities.addAll(snapshot.values());
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
private void spawnChunkSafely(World world, int chunkX, int chunkZ, boolean initial) {
|
private void spawnChunkSafely(World world, int chunkX, int chunkZ, boolean initial) {
|
||||||
if (world == null) {
|
if (world == null) {
|
||||||
return;
|
return;
|
||||||
@@ -756,7 +808,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
public void teleportAsync(PlayerTeleportEvent e) {
|
public void teleportAsync(PlayerTeleportEvent e) {
|
||||||
if (IrisSettings.get().getWorld().getAsyncTeleport().isEnabled()) {
|
if (IrisSettings.get().getWorld().getAsyncTeleport().isEnabled()) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.s(() -> {
|
warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.runEntity(e.getPlayer(), () -> {
|
||||||
ignoreTP.set(true);
|
ignoreTP.set(true);
|
||||||
e.getPlayer().teleport(e.getTo(), e.getCause());
|
e.getPlayer().teleport(e.getTo(), e.getCause());
|
||||||
ignoreTP.set(false);
|
ignoreTP.set(false);
|
||||||
@@ -1018,7 +1070,13 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
if (d.isNotEmpty()) {
|
if (d.isNotEmpty()) {
|
||||||
World w = e.getBlock().getWorld();
|
World w = e.getBlock().getWorld();
|
||||||
J.s(() -> d.forEach(item -> w.dropItemNaturally(e.getBlock().getLocation().clone().add(.5, .5, .5), item)));
|
Location dropLocation = e.getBlock().getLocation().clone().add(.5, .5, .5);
|
||||||
|
Runnable dropTask = () -> d.forEach(item -> w.dropItemNaturally(dropLocation, item));
|
||||||
|
if (!J.runAt(dropLocation, dropTask)) {
|
||||||
|
if (!J.isFolia()) {
|
||||||
|
J.s(dropTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.engine.framework;
|
package art.arcane.iris.engine.framework;
|
||||||
|
|
||||||
|
import art.arcane.iris.Iris;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.nms.container.BlockPos;
|
import art.arcane.iris.core.nms.container.BlockPos;
|
||||||
import art.arcane.iris.core.nms.container.Pair;
|
import art.arcane.iris.core.nms.container.Pair;
|
||||||
@@ -38,11 +39,14 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
|
|||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||||
import art.arcane.iris.util.common.scheduling.jobs.SingleJob;
|
import art.arcane.iris.util.common.scheduling.jobs.SingleJob;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -106,7 +110,7 @@ public interface Locator<T> {
|
|||||||
default void find(Player player, boolean teleport, String message) {
|
default void find(Player player, boolean teleport, String message) {
|
||||||
find(player, location -> {
|
find(player, location -> {
|
||||||
if (teleport) {
|
if (teleport) {
|
||||||
J.s(() -> player.teleport(location));
|
J.runEntity(player, () -> teleportAsyncSafely(player, location));
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||||
}
|
}
|
||||||
@@ -206,4 +210,39 @@ public interface Locator<T> {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void teleportAsyncSafely(Player player, Location location) {
|
||||||
|
if (player == null || location == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invokeNativeTeleportAsync(player, location)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
CompletableFuture<Boolean> teleportFuture = PaperLib.teleportAsync(player, location);
|
||||||
|
if (teleportFuture != null) {
|
||||||
|
teleportFuture.exceptionally(throwable -> {
|
||||||
|
Iris.reportError(throwable);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
Iris.reportError(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean invokeNativeTeleportAsync(Player player, Location location) {
|
||||||
|
try {
|
||||||
|
Method teleportAsyncMethod = player.getClass().getMethod("teleportAsync", Location.class);
|
||||||
|
teleportAsyncMethod.invoke(player, location);
|
||||||
|
return true;
|
||||||
|
} catch (NoSuchMethodException ignored) {
|
||||||
|
return false;
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
Iris.reportError(throwable);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
public class IrisCaveCarver3D {
|
public class IrisCaveCarver3D {
|
||||||
private static final byte LIQUID_AIR = 0;
|
private static final byte LIQUID_AIR = 0;
|
||||||
private static final byte LIQUID_WATER = 1;
|
|
||||||
private static final byte LIQUID_LAVA = 2;
|
private static final byte LIQUID_LAVA = 2;
|
||||||
private static final byte LIQUID_FORCED_AIR = 3;
|
private static final byte LIQUID_FORCED_AIR = 3;
|
||||||
|
|
||||||
@@ -48,7 +47,6 @@ public class IrisCaveCarver3D {
|
|||||||
private final KList<ModuleState> modules;
|
private final KList<ModuleState> modules;
|
||||||
private final double normalization;
|
private final double normalization;
|
||||||
private final MatterCavern carveAir;
|
private final MatterCavern carveAir;
|
||||||
private final MatterCavern carveWater;
|
|
||||||
private final MatterCavern carveLava;
|
private final MatterCavern carveLava;
|
||||||
private final MatterCavern carveForcedAir;
|
private final MatterCavern carveForcedAir;
|
||||||
|
|
||||||
@@ -57,7 +55,6 @@ public class IrisCaveCarver3D {
|
|||||||
this.data = engine.getData();
|
this.data = engine.getData();
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
this.carveAir = new MatterCavern(true, "", LIQUID_AIR);
|
this.carveAir = new MatterCavern(true, "", LIQUID_AIR);
|
||||||
this.carveWater = new MatterCavern(true, "", LIQUID_WATER);
|
|
||||||
this.carveLava = new MatterCavern(true, "", LIQUID_LAVA);
|
this.carveLava = new MatterCavern(true, "", LIQUID_LAVA);
|
||||||
this.carveForcedAir = new MatterCavern(true, "", LIQUID_FORCED_AIR);
|
this.carveForcedAir = new MatterCavern(true, "", LIQUID_FORCED_AIR);
|
||||||
this.modules = new KList<>();
|
this.modules = new KList<>();
|
||||||
@@ -352,24 +349,9 @@ public class IrisCaveCarver3D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (profile.isAllowWater() && y <= fluidHeight) {
|
if (profile.isAllowWater() && y <= fluidHeight) {
|
||||||
if (surfaceY - y < waterMinDepthBelowSurface) {
|
|
||||||
return carveAir;
|
return carveAir;
|
||||||
}
|
}
|
||||||
|
|
||||||
double depthFactor = Math.max(0, Math.min(1.5, (fluidHeight - y) / 48D));
|
|
||||||
double cutoff = 0.35 + (depthFactor * 0.2);
|
|
||||||
double aquifer = signed(detailDensity.noise(x, y * 0.5D, z));
|
|
||||||
if (aquifer <= cutoff) {
|
|
||||||
return carveAir;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waterRequiresFloor && !hasAquiferCupSupport(x, y, z, localThreshold)) {
|
|
||||||
return carveAir;
|
|
||||||
}
|
|
||||||
|
|
||||||
return carveWater;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!profile.isAllowLava() && y <= lavaHeight) {
|
if (!profile.isAllowLava() && y <= lavaHeight) {
|
||||||
return carveForcedAir;
|
return carveForcedAir;
|
||||||
}
|
}
|
||||||
@@ -377,38 +359,6 @@ public class IrisCaveCarver3D {
|
|||||||
return carveAir;
|
return carveAir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAquiferCupSupport(int x, int y, int z, double threshold) {
|
|
||||||
int floorY = Math.max(0, y - 1);
|
|
||||||
int deepFloorY = Math.max(0, y - 2);
|
|
||||||
if (!isDensitySolid(x, floorY, z, threshold)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDensitySolid(x, deepFloorY, z, threshold - 0.05D)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int support = 0;
|
|
||||||
if (isDensitySolid(x + 1, y, z, threshold)) {
|
|
||||||
support++;
|
|
||||||
}
|
|
||||||
if (isDensitySolid(x - 1, y, z, threshold)) {
|
|
||||||
support++;
|
|
||||||
}
|
|
||||||
if (isDensitySolid(x, y, z + 1, threshold)) {
|
|
||||||
support++;
|
|
||||||
}
|
|
||||||
if (isDensitySolid(x, y, z - 1, threshold)) {
|
|
||||||
support++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return support >= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDensitySolid(int x, int y, int z, double threshold) {
|
|
||||||
return sampleDensity(x, y, z) > threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double clampColumnWeight(double weight) {
|
private double clampColumnWeight(double weight) {
|
||||||
if (Double.isNaN(weight) || Double.isInfinite(weight)) {
|
if (Double.isNaN(weight) || Double.isInfinite(weight)) {
|
||||||
return 0D;
|
return 0D;
|
||||||
|
|||||||
+218
-14
@@ -48,10 +48,15 @@ import java.io.IOException;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
@ComponentFlag(ReservedFlag.OBJECT)
|
@ComponentFlag(ReservedFlag.OBJECT)
|
||||||
public class MantleObjectComponent extends IrisMantleComponent {
|
public class MantleObjectComponent extends IrisMantleComponent {
|
||||||
|
private static final long CAVE_REJECT_LOG_THROTTLE_MS = 5000L;
|
||||||
|
private static final Map<String, CaveRejectLogState> CAVE_REJECT_LOG_STATE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public MantleObjectComponent(EngineMantle engineMantle) {
|
public MantleObjectComponent(EngineMantle engineMantle) {
|
||||||
super(engineMantle, ReservedFlag.OBJECT, 1);
|
super(engineMantle, ReservedFlag.OBJECT, 1);
|
||||||
@@ -66,11 +71,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
|
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
|
||||||
IrisBiome surfaceBiome = getComplex().getTrueBiomeStream().get(xxx, zzz);
|
IrisBiome surfaceBiome = getComplex().getTrueBiomeStream().get(xxx, zzz);
|
||||||
int surfaceY = getEngineMantle().getEngine().getHeight(xxx, zzz, true);
|
int surfaceY = getEngineMantle().getEngine().getHeight(xxx, zzz, true);
|
||||||
int sampleY = Math.max(1, surfaceY - 48);
|
IrisBiome caveBiome = resolveCaveObjectBiome(xxx, zzz, surfaceY, surfaceBiome);
|
||||||
IrisBiome caveBiome = getEngineMantle().getEngine().getCaveBiome(xxx, sampleY, zzz);
|
|
||||||
if (caveBiome == null) {
|
|
||||||
caveBiome = surfaceBiome;
|
|
||||||
}
|
|
||||||
if (traceRegen) {
|
if (traceRegen) {
|
||||||
Iris.info("Regen object layer start: chunk=" + x + "," + z
|
Iris.info("Regen object layer start: chunk=" + x + "," + z
|
||||||
+ " surfaceBiome=" + surfaceBiome.getLoadKey()
|
+ " surfaceBiome=" + surfaceBiome.getLoadKey()
|
||||||
@@ -105,6 +106,41 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
return new RNG((long) (seed * noise.noise(x, z)));
|
return new RNG((long) (seed * noise.noise(x, z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IrisBiome resolveCaveObjectBiome(int x, int z, int surfaceY, IrisBiome surfaceBiome) {
|
||||||
|
int legacySampleY = Math.max(1, surfaceY - 48);
|
||||||
|
IrisBiome legacyCaveBiome = getEngineMantle().getEngine().getCaveBiome(x, legacySampleY, z);
|
||||||
|
if (legacyCaveBiome == null) {
|
||||||
|
legacyCaveBiome = surfaceBiome;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] sampleDepths = new int[]{48, 80, 112};
|
||||||
|
IrisBiome ladderChoice = null;
|
||||||
|
for (int sampleDepth : sampleDepths) {
|
||||||
|
int sampleY = Math.max(1, surfaceY - sampleDepth);
|
||||||
|
IrisBiome sampled = getEngineMantle().getEngine().getCaveBiome(x, sampleY, z);
|
||||||
|
boolean sameSurface = sampled == surfaceBiome;
|
||||||
|
if (!sameSurface && sampled != null && surfaceBiome != null) {
|
||||||
|
String sampledKey = sampled.getLoadKey();
|
||||||
|
String surfaceKey = surfaceBiome.getLoadKey();
|
||||||
|
sameSurface = sampledKey != null && sampledKey.equals(surfaceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sampled == null || sameSurface) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sampled.getCarvingObjects().isEmpty()) {
|
||||||
|
ladderChoice = sampled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ladderChoice != null) {
|
||||||
|
return ladderChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
return legacyCaveBiome;
|
||||||
|
}
|
||||||
|
|
||||||
@ChunkCoordinates
|
@ChunkCoordinates
|
||||||
private ObjectPlacementSummary placeObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome surfaceBiome, IrisBiome caveBiome, IrisRegion region, boolean traceRegen) {
|
private ObjectPlacementSummary placeObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome surfaceBiome, IrisBiome caveBiome, IrisRegion region, boolean traceRegen) {
|
||||||
int biomeSurfaceChecked = 0;
|
int biomeSurfaceChecked = 0;
|
||||||
@@ -393,6 +429,22 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
+ " density=" + density
|
+ " density=" + density
|
||||||
+ " placementKeys=" + objectPlacement.getPlace().toString(","));
|
+ " placementKeys=" + objectPlacement.getPlace().toString(","));
|
||||||
}
|
}
|
||||||
|
logCaveReject(
|
||||||
|
scope,
|
||||||
|
"NULL_OBJECT",
|
||||||
|
metricChunkX,
|
||||||
|
metricChunkZ,
|
||||||
|
objectPlacement,
|
||||||
|
null,
|
||||||
|
i,
|
||||||
|
density,
|
||||||
|
anchorMode,
|
||||||
|
anchorSearchAttempts,
|
||||||
|
anchorScanStep,
|
||||||
|
objectMinDepthBelowSurface,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,24 +467,59 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
|
|
||||||
if (y < 0) {
|
if (y < 0) {
|
||||||
rejected++;
|
rejected++;
|
||||||
|
logCaveReject(
|
||||||
|
scope,
|
||||||
|
"NO_ANCHOR",
|
||||||
|
metricChunkX,
|
||||||
|
metricChunkZ,
|
||||||
|
objectPlacement,
|
||||||
|
object,
|
||||||
|
i,
|
||||||
|
density,
|
||||||
|
anchorMode,
|
||||||
|
anchorSearchAttempts,
|
||||||
|
anchorScanStep,
|
||||||
|
objectMinDepthBelowSurface,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = rng.i(0, Integer.MAX_VALUE);
|
int id = rng.i(0, Integer.MAX_VALUE);
|
||||||
IrisObjectPlacement effectivePlacement = resolveEffectivePlacement(objectPlacement, object);
|
IrisObjectPlacement effectivePlacement = resolveEffectivePlacement(objectPlacement, object);
|
||||||
|
AtomicBoolean wrotePlacementData = new AtomicBoolean(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int result = object.place(x, y, z, writer, effectivePlacement, rng, (b, data) -> {
|
int result = object.place(x, y, z, writer, effectivePlacement, rng, (b, data) -> {
|
||||||
|
wrotePlacementData.set(true);
|
||||||
writer.setData(b.getX(), b.getY(), b.getZ(), object.getLoadKey() + "@" + id);
|
writer.setData(b.getX(), b.getY(), b.getZ(), object.getLoadKey() + "@" + id);
|
||||||
if (effectivePlacement.isDolphinTarget() && effectivePlacement.isUnderwater() && B.isStorageChest(data)) {
|
if (effectivePlacement.isDolphinTarget() && effectivePlacement.isUnderwater() && B.isStorageChest(data)) {
|
||||||
writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE);
|
writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE);
|
||||||
}
|
}
|
||||||
}, null, getData());
|
}, null, getData());
|
||||||
|
|
||||||
if (result >= 0) {
|
boolean wroteBlocks = wrotePlacementData.get();
|
||||||
|
if (wroteBlocks) {
|
||||||
placed++;
|
placed++;
|
||||||
} else {
|
} else if (result < 0) {
|
||||||
rejected++;
|
rejected++;
|
||||||
|
logCaveReject(
|
||||||
|
scope,
|
||||||
|
"PLACE_NEGATIVE",
|
||||||
|
metricChunkX,
|
||||||
|
metricChunkZ,
|
||||||
|
objectPlacement,
|
||||||
|
object,
|
||||||
|
i,
|
||||||
|
density,
|
||||||
|
anchorMode,
|
||||||
|
anchorSearchAttempts,
|
||||||
|
anchorScanStep,
|
||||||
|
objectMinDepthBelowSurface,
|
||||||
|
y,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (traceRegen) {
|
if (traceRegen) {
|
||||||
@@ -443,6 +530,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
+ " anchorY=" + y
|
+ " anchorY=" + y
|
||||||
+ " px=" + x
|
+ " px=" + x
|
||||||
+ " pz=" + z
|
+ " pz=" + z
|
||||||
|
+ " wroteBlocks=" + wroteBlocks
|
||||||
+ " densityIndex=" + i
|
+ " densityIndex=" + i
|
||||||
+ " density=" + density);
|
+ " density=" + density);
|
||||||
}
|
}
|
||||||
@@ -455,13 +543,87 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
+ " densityIndex=" + i
|
+ " densityIndex=" + i
|
||||||
+ " density=" + density
|
+ " density=" + density
|
||||||
+ " error=" + e.getClass().getSimpleName() + ":" + e.getMessage());
|
+ " error=" + e.getClass().getSimpleName() + ":" + e.getMessage());
|
||||||
|
logCaveReject(
|
||||||
|
scope,
|
||||||
|
"EXCEPTION",
|
||||||
|
metricChunkX,
|
||||||
|
metricChunkZ,
|
||||||
|
objectPlacement,
|
||||||
|
object,
|
||||||
|
i,
|
||||||
|
density,
|
||||||
|
anchorMode,
|
||||||
|
anchorSearchAttempts,
|
||||||
|
anchorScanStep,
|
||||||
|
objectMinDepthBelowSurface,
|
||||||
|
y,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ObjectPlacementResult(attempts, placed, rejected, nullObjects, errors);
|
return new ObjectPlacementResult(attempts, placed, rejected, nullObjects, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IrisObjectPlacement resolveEffectivePlacement(IrisObjectPlacement objectPlacement, IrisObject object) {
|
private void logCaveReject(
|
||||||
|
String scope,
|
||||||
|
String reason,
|
||||||
|
int chunkX,
|
||||||
|
int chunkZ,
|
||||||
|
IrisObjectPlacement objectPlacement,
|
||||||
|
IrisObject object,
|
||||||
|
int densityIndex,
|
||||||
|
int density,
|
||||||
|
IrisCaveAnchorMode anchorMode,
|
||||||
|
int anchorSearchAttempts,
|
||||||
|
int anchorScanStep,
|
||||||
|
int objectMinDepthBelowSurface,
|
||||||
|
Integer anchorY,
|
||||||
|
Throwable error
|
||||||
|
) {
|
||||||
|
if (!IrisSettings.get().getGeneral().isDebug()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String placementKeys = objectPlacement == null ? "none" : objectPlacement.getPlace().toString(",");
|
||||||
|
String objectKey = object == null ? "null" : object.getLoadKey();
|
||||||
|
String throttleKey = scope + "|" + reason + "|" + placementKeys + "|" + objectKey;
|
||||||
|
CaveRejectLogState state = CAVE_REJECT_LOG_STATE.computeIfAbsent(throttleKey, (k) -> new CaveRejectLogState());
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long last = state.lastLogMs.get();
|
||||||
|
if ((now - last) < CAVE_REJECT_LOG_THROTTLE_MS) {
|
||||||
|
state.suppressed.incrementAndGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.lastLogMs.compareAndSet(last, now)) {
|
||||||
|
state.suppressed.incrementAndGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int suppressed = state.suppressed.getAndSet(0);
|
||||||
|
String anchorYText = anchorY == null ? "none" : String.valueOf(anchorY);
|
||||||
|
String errorText = error == null ? "none" : error.getClass().getSimpleName() + ":" + String.valueOf(error.getMessage());
|
||||||
|
Iris.warn("Cave object reject: scope=" + scope
|
||||||
|
+ " reason=" + reason
|
||||||
|
+ " chunk=" + chunkX + "," + chunkZ
|
||||||
|
+ " object=" + objectKey
|
||||||
|
+ " placements=" + placementKeys
|
||||||
|
+ " densityIndex=" + densityIndex
|
||||||
|
+ " density=" + density
|
||||||
|
+ " anchorMode=" + anchorMode
|
||||||
|
+ " anchorSearchAttempts=" + anchorSearchAttempts
|
||||||
|
+ " anchorScanStep=" + anchorScanStep
|
||||||
|
+ " minDepthBelowSurface=" + objectMinDepthBelowSurface
|
||||||
|
+ " anchorY=" + anchorYText
|
||||||
|
+ " forcePlace=" + (objectPlacement != null && objectPlacement.isForcePlace())
|
||||||
|
+ " carvingSupport=" + (objectPlacement == null ? "none" : objectPlacement.getCarvingSupport())
|
||||||
|
+ " bottom=" + (objectPlacement != null && objectPlacement.isBottom())
|
||||||
|
+ " suppressed=" + suppressed
|
||||||
|
+ " error=" + errorText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IrisObjectPlacement resolveEffectivePlacement(IrisObjectPlacement objectPlacement, IrisObject object) {
|
||||||
if (objectPlacement == null || object == null) {
|
if (objectPlacement == null || object == null) {
|
||||||
return objectPlacement;
|
return objectPlacement;
|
||||||
}
|
}
|
||||||
@@ -472,19 +634,20 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String normalized = loadKey.toLowerCase(Locale.ROOT);
|
String normalized = loadKey.toLowerCase(Locale.ROOT);
|
||||||
boolean imported = normalized.startsWith("imports/")
|
boolean legacyImported = normalized.startsWith("imports/")
|
||||||
|| normalized.contains("/imports/")
|
|| normalized.contains("/imports/")
|
||||||
|| normalized.contains("imports/");
|
|| normalized.contains("imports/");
|
||||||
|
IrisExternalDatapack externalDatapack = resolveExternalDatapackForObjectKey(normalized);
|
||||||
|
boolean externalImported = externalDatapack != null;
|
||||||
|
boolean imported = legacyImported || externalImported;
|
||||||
|
|
||||||
if (!imported) {
|
if (!imported) {
|
||||||
return objectPlacement;
|
return objectPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPlaceMode mode = objectPlacement.getMode();
|
ObjectPlaceMode mode = objectPlacement.getMode();
|
||||||
if (mode == ObjectPlaceMode.STILT
|
boolean needsModeChange = mode != ObjectPlaceMode.FAST_MIN_STILT;
|
||||||
|| mode == ObjectPlaceMode.FAST_STILT
|
if (!needsModeChange) {
|
||||||
|| mode == ObjectPlaceMode.MIN_STILT
|
|
||||||
|| mode == ObjectPlaceMode.FAST_MIN_STILT
|
|
||||||
|| mode == ObjectPlaceMode.CENTER_STILT) {
|
|
||||||
return objectPlacement;
|
return objectPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,6 +656,42 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
return effectivePlacement;
|
return effectivePlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IrisExternalDatapack resolveExternalDatapackForObjectKey(String normalizedLoadKey) {
|
||||||
|
if (normalizedLoadKey == null || normalizedLoadKey.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slash = normalizedLoadKey.indexOf('/');
|
||||||
|
if (slash <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String candidateId = normalizedLoadKey.substring(0, slash);
|
||||||
|
if (candidateId.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrisDimension dimension = getDimension();
|
||||||
|
if (dimension == null || dimension.getExternalDatapacks() == null || dimension.getExternalDatapacks().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IrisExternalDatapack externalDatapack : dimension.getExternalDatapacks()) {
|
||||||
|
if (externalDatapack == null || !externalDatapack.isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = externalDatapack.getId();
|
||||||
|
if (id == null || id.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (candidateId.equals(id.toLowerCase(Locale.ROOT))) {
|
||||||
|
return externalDatapack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private int findCaveAnchorY(MantleWriter writer, RNG rng, int x, int z, IrisCaveAnchorMode anchorMode, int anchorScanStep, int objectMinDepthBelowSurface, KMap<Long, KList<Integer>> anchorCache) {
|
private int findCaveAnchorY(MantleWriter writer, RNG rng, int x, int z, IrisCaveAnchorMode anchorMode, int anchorScanStep, int objectMinDepthBelowSurface, KMap<Long, KList<Integer>> anchorCache) {
|
||||||
long key = Cache.key(x, z);
|
long key = Cache.key(x, z);
|
||||||
KList<Integer> anchors = anchorCache.computeIfAbsent(key, (k) -> scanCaveAnchorColumn(writer, anchorMode, anchorScanStep, objectMinDepthBelowSurface, x, z));
|
KList<Integer> anchors = anchorCache.computeIfAbsent(key, (k) -> scanCaveAnchorColumn(writer, anchorMode, anchorScanStep, objectMinDepthBelowSurface, x, z));
|
||||||
@@ -662,6 +861,11 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
private record ObjectPlacementResult(int attempts, int placed, int rejected, int nullObjects, int errors) {
|
private record ObjectPlacementResult(int attempts, int placed, int rejected, int nullObjects, int errors) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class CaveRejectLogState {
|
||||||
|
private final AtomicLong lastLogMs = new AtomicLong(0L);
|
||||||
|
private final AtomicInteger suppressed = new AtomicInteger(0);
|
||||||
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
private Set<String> guessPlacedKeys(RNG rng, int x, int z, IrisObjectPlacement objectPlacement) {
|
private Set<String> guessPlacedKeys(RNG rng, int x, int z, IrisObjectPlacement objectPlacement) {
|
||||||
Set<String> f = new KSet<>();
|
Set<String> f = new KSet<>();
|
||||||
|
|||||||
@@ -242,8 +242,14 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
int gg = 0;
|
int gg = 0;
|
||||||
for (IrisEntity i : passengers) {
|
for (IrisEntity i : passengers) {
|
||||||
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
|
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
|
||||||
if (!Bukkit.isPrimaryThread()) {
|
if (passenger == null) {
|
||||||
J.s(() -> e.addPassenger(passenger));
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Bukkit.isPrimaryThread()) {
|
||||||
|
e.addPassenger(passenger);
|
||||||
|
} else {
|
||||||
|
J.runEntity(e, () -> e.addPassenger(passenger));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +344,7 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
if (e instanceof Villager) {
|
if (e instanceof Villager) {
|
||||||
Villager villager = (Villager) e;
|
Villager villager = (Villager) e;
|
||||||
villager.setRemoveWhenFarAway(false);
|
villager.setRemoveWhenFarAway(false);
|
||||||
J.s(() -> villager.setPersistent(true), 1);
|
J.runEntity(villager, () -> villager.setPersistent(true), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof Mob) {
|
if (e instanceof Mob) {
|
||||||
@@ -365,7 +371,7 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
|
|
||||||
Location finalAt1 = at;
|
Location finalAt1 = at;
|
||||||
|
|
||||||
J.s(() -> {
|
J.runEntity(e, () -> {
|
||||||
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) {
|
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) {
|
||||||
Location start = finalAt1.clone();
|
Location start = finalAt1.clone();
|
||||||
e.setInvulnerable(true);
|
e.setInvulnerable(true);
|
||||||
@@ -373,10 +379,13 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
((LivingEntity) e).setCollidable(false);
|
((LivingEntity) e).setCollidable(false);
|
||||||
((LivingEntity) e).setNoDamageTicks(100000);
|
((LivingEntity) e).setNoDamageTicks(100000);
|
||||||
AtomicInteger t = new AtomicInteger(0);
|
AtomicInteger t = new AtomicInteger(0);
|
||||||
AtomicInteger v = new AtomicInteger(0);
|
Runnable[] loop = new Runnable[1];
|
||||||
v.set(J.sr(() -> {
|
loop[0] = () -> {
|
||||||
if (t.get() > 100) {
|
if (t.get() > 100 || e.isDead()) {
|
||||||
J.csr(v.get());
|
((LivingEntity) e).setNoDamageTicks(0);
|
||||||
|
((LivingEntity) e).setCollidable(true);
|
||||||
|
((LivingEntity) e).setAI(true);
|
||||||
|
e.setInvulnerable(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,14 +397,20 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
if (M.r(0.2)) {
|
if (M.r(0.2)) {
|
||||||
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
|
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
|
||||||
}
|
}
|
||||||
} else {
|
if (!J.runEntity(e, loop[0], 1)) {
|
||||||
J.csr(v.get());
|
|
||||||
((LivingEntity) e).setNoDamageTicks(0);
|
((LivingEntity) e).setNoDamageTicks(0);
|
||||||
((LivingEntity) e).setCollidable(true);
|
((LivingEntity) e).setCollidable(true);
|
||||||
((LivingEntity) e).setAI(true);
|
((LivingEntity) e).setAI(true);
|
||||||
e.setInvulnerable(false);
|
e.setInvulnerable(false);
|
||||||
}
|
}
|
||||||
}, 0));
|
} else {
|
||||||
|
((LivingEntity) e).setNoDamageTicks(0);
|
||||||
|
((LivingEntity) e).setCollidable(true);
|
||||||
|
((LivingEntity) e).setAI(true);
|
||||||
|
e.setInvulnerable(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
J.runEntity(e, loop[0]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -437,7 +452,9 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
AtomicReference<Entity> ae = new AtomicReference<>();
|
AtomicReference<Entity> ae = new AtomicReference<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
J.s(() -> ae.set(doSpawn(at)));
|
if (!J.runAt(at, () -> ae.set(doSpawn(at)))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ public class IrisExternalDatapack {
|
|||||||
@Desc("If true, minecraft namespace worldgen assets may replace vanilla targets listed in replaceTargets")
|
@Desc("If true, minecraft namespace worldgen assets may replace vanilla targets listed in replaceTargets")
|
||||||
private boolean replaceVanilla = false;
|
private boolean replaceVanilla = false;
|
||||||
|
|
||||||
|
@Desc("If true, structures projected from this datapack id receive smartbore foundation extension during generation")
|
||||||
|
private boolean supportSmartBore = true;
|
||||||
|
|
||||||
@Desc("Explicit replacement targets for minecraft namespace assets")
|
@Desc("Explicit replacement targets for minecraft namespace assets")
|
||||||
private IrisExternalDatapackReplaceTargets replaceTargets = new IrisExternalDatapackReplaceTargets();
|
private IrisExternalDatapackReplaceTargets replaceTargets = new IrisExternalDatapackReplaceTargets();
|
||||||
|
|
||||||
|
|||||||
@@ -954,7 +954,7 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone();
|
i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone();
|
||||||
i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone();
|
i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone();
|
||||||
|
|
||||||
if (stilting && i.getBlockY() < lowest && !B.isAir(data)) {
|
if (stilting && i.getBlockY() < lowest && B.isSolid(data)) {
|
||||||
lowest = i.getBlockY();
|
lowest = i.getBlockY();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1013,8 +1013,7 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((config.isWaterloggable() || config.isUnderwater()) && yy <= placer.getFluidHeight() && data instanceof Waterlogged) {
|
if (data instanceof Waterlogged && shouldAutoWaterlogBlock(placer, config, yv, xx, yy, zz)) {
|
||||||
// TODO Here
|
|
||||||
((Waterlogged) data).setWaterlogged(true);
|
((Waterlogged) data).setWaterlogged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,24 +1055,28 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
readLock.lock();
|
readLock.lock();
|
||||||
IrisStiltSettings settings = config.getStiltSettings();
|
IrisStiltSettings settings = config.getStiltSettings();
|
||||||
for (BlockVector g : blocks.keys()) {
|
for (BlockVector g : blocks.keys()) {
|
||||||
BlockData d;
|
BlockData sourceData;
|
||||||
|
|
||||||
if (settings == null || settings.getPalette() == null) {
|
|
||||||
try {
|
try {
|
||||||
d = blocks.get(g);
|
sourceData = blocks.get(g);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)");
|
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)");
|
||||||
d = AIR;
|
sourceData = AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d == null) {
|
if (sourceData == null) {
|
||||||
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt null)");
|
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt null)");
|
||||||
d = AIR;
|
sourceData = AIR;
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
d = config.getStiltSettings().getPalette().get(rng, x, y, z, rdata);
|
|
||||||
|
|
||||||
|
if (!B.isSolid(sourceData)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockData d = sourceData;
|
||||||
|
if (settings != null && settings.getPalette() != null) {
|
||||||
|
d = config.getStiltSettings().getPalette().get(rng, x, y, z, rdata);
|
||||||
|
}
|
||||||
|
|
||||||
BlockVector i = g.clone();
|
BlockVector i = g.clone();
|
||||||
i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone();
|
i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone();
|
||||||
@@ -1099,7 +1102,7 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d == null || B.isAir(d))
|
if (d == null || !B.isSolid(d))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
xx = x + (int) Math.round(i.getX());
|
xx = x + (int) Math.round(i.getX());
|
||||||
@@ -1112,7 +1115,7 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
|
|
||||||
int highest = placer.getHighest(xx, zz, getLoader(), true);
|
int highest = placer.getHighest(xx, zz, getLoader(), true);
|
||||||
|
|
||||||
if ((config.isWaterloggable() || config.isUnderwater()) && highest <= placer.getFluidHeight() && d instanceof Waterlogged)
|
if (d instanceof Waterlogged && shouldAutoWaterlogBlock(placer, config, yv, xx, highest, zz))
|
||||||
((Waterlogged) d).setWaterlogged(true);
|
((Waterlogged) d).setWaterlogged(true);
|
||||||
|
|
||||||
if (yv >= 0 && config.isBottom())
|
if (yv >= 0 && config.isBottom())
|
||||||
@@ -1177,6 +1180,23 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
|| placer.isCarved(x, y - 3, z);
|
|| placer.isCarved(x, y - 3, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldAutoWaterlogBlock(IObjectPlacer placer, IrisObjectPlacement placement, int yv, int x, int y, int z) {
|
||||||
|
if (!(placement.isWaterloggable() || placement.isUnderwater())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yv >= 0 && placement.getCarvingSupport().equals(CarvingMode.CARVING_ONLY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockData existing = placer.get(x, y, z);
|
||||||
|
if (existing == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B.isWater(existing) || B.isWaterLogged(existing);
|
||||||
|
}
|
||||||
|
|
||||||
public IrisObject rotateCopy(IrisObjectRotation rt) {
|
public IrisObject rotateCopy(IrisObjectRotation rt) {
|
||||||
IrisObject copy = copy();
|
IrisObject copy = copy();
|
||||||
copy.rotate(rt, 0, 0, 0);
|
copy.rotate(rt, 0, 0, 0);
|
||||||
|
|||||||
+25
-5
@@ -201,7 +201,8 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
List<StructureStart> starts = new ArrayList<>(structureManager.startsForStructure(chunkAccess.getPos(), structure -> true));
|
List<StructureStart> starts = new ArrayList<>(structureManager.startsForStructure(chunkAccess.getPos(), structure -> true));
|
||||||
starts.sort(Comparator.comparingInt(start -> structureOrder.getOrDefault(start.getStructure(), Integer.MAX_VALUE)));
|
starts.sort(Comparator.comparingInt(start -> structureOrder.getOrDefault(start.getStructure(), Integer.MAX_VALUE)));
|
||||||
Set<String> externalLocateStructures = ExternalDataPackPipeline.snapshotLocateStructureKeys();
|
Set<String> externalSmartBoreStructures = ExternalDataPackPipeline.snapshotSmartBoreStructureKeys();
|
||||||
|
Set<String> suppressedVanillaStructures = ExternalDataPackPipeline.snapshotSuppressedVanillaStructureKeys();
|
||||||
|
|
||||||
int seededStructureIndex = Integer.MIN_VALUE;
|
int seededStructureIndex = Integer.MIN_VALUE;
|
||||||
for (int j = 0; j < starts.size(); j++) {
|
for (int j = 0; j < starts.size(); j++) {
|
||||||
@@ -213,17 +214,20 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
seededStructureIndex = structureIndex;
|
seededStructureIndex = structureIndex;
|
||||||
}
|
}
|
||||||
Supplier<String> supplier = () -> structureRegistry.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
Supplier<String> supplier = () -> structureRegistry.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
String structureKey = supplier.get().toLowerCase(Locale.ROOT);
|
String structureKey = resolveStructureKey(structureRegistry, structure);
|
||||||
boolean isExternalLocateStructure = externalLocateStructures.contains(structureKey);
|
if (suppressedVanillaStructures.contains(structureKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean isExternalSmartBoreStructure = externalSmartBoreStructures.contains(structureKey);
|
||||||
BitSet[] beforeSolidColumns = null;
|
BitSet[] beforeSolidColumns = null;
|
||||||
if (isExternalLocateStructure) {
|
if (isExternalSmartBoreStructure) {
|
||||||
beforeSolidColumns = snapshotChunkSolidColumns(level, chunkAccess);
|
beforeSolidColumns = snapshotChunkSolidColumns(level, chunkAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
level.setCurrentlyGenerating(supplier);
|
level.setCurrentlyGenerating(supplier);
|
||||||
start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos());
|
start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos());
|
||||||
if (isExternalLocateStructure && beforeSolidColumns != null) {
|
if (isExternalSmartBoreStructure && beforeSolidColumns != null) {
|
||||||
applyExternalStructureFoundations(level, chunkAccess, beforeSolidColumns, EXTERNAL_FOUNDATION_MAX_DEPTH);
|
applyExternalStructureFoundations(level, chunkAccess, beforeSolidColumns, EXTERNAL_FOUNDATION_MAX_DEPTH);
|
||||||
}
|
}
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
@@ -237,6 +241,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String resolveStructureKey(Registry<Structure> structureRegistry, Structure structure) {
|
||||||
|
Identifier directKey = structureRegistry.getKey(structure);
|
||||||
|
if (directKey != null) {
|
||||||
|
return directKey.toString().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
String fallback = String.valueOf(structure);
|
||||||
|
int slash = fallback.lastIndexOf('/');
|
||||||
|
int end = fallback.lastIndexOf(']');
|
||||||
|
if (slash >= 0 && end > slash) {
|
||||||
|
return fallback.substring(slash + 1, end).toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback.toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
ChunkPos chunkPos = ichunkaccess.getPos();
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
int minX = chunkPos.getMinBlockX();
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
|||||||
Reference in New Issue
Block a user