Compare commits

...

37 Commits

Author SHA1 Message Date
Sofiane H. Djerbi
55012f8ddd Internal compression introduction 2023-03-06 06:30:06 +02:00
Sofiane H. Djerbi
b516d47aeb Merge branch 'ver/1.19.3' of github.com:KaiijuMC/Kaiiju into ver/1.19.3 2023-03-05 21:22:31 +02:00
Sofiane H. Djerbi
4dfd98f9b9 Update gradle wrapper / dependencies 2023-03-05 21:06:14 +02:00
Sofiane H. Djerbi
ac5e38e86e Linear file format rework / Per world file format / Polyglot server
- Per world region format settings
- Polyglot: server can read both ANVIL and LINEAR files at the same time, and save using format specified in config
2023-03-05 18:59:58 +01:00
Sofiane H. Djerbi
dbbc862af3 Polyglot server 2023-03-05 19:49:45 +02:00
Sofiane H. Djerbi
784e2baf7a Per world region file format 2023-03-04 09:42:46 +02:00
Sofiane H. Djerbi
94ca13f790 Merge pull request #17 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-27 18:44:44 +01:00
kugge
963286ac7e Update Upstream (Purpur) 2023-02-27 15:18:38 +00:00
Sofiane H. Djerbi
0383ff6961 Release on push 2023-02-26 23:22:35 +01:00
Sofiane H. Djerbi
8e1bfd6c3c Merge pull request #16 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-26 23:21:40 +01:00
kugge
1638fe6b97 Update Upstream (Purpur) 2023-02-26 15:17:34 +00:00
Sofiane H. Djerbi
d5699419e4 Merge pull request #14 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-25 01:17:25 +01:00
kugge
d57758c9f8 Update Upstream (Purpur) 2023-02-23 15:13:37 +00:00
Sofiane H. Djerbi
63d893a0e4 Merge pull request #12 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-22 23:15:01 +01:00
kugge
08892016f5 Update Upstream (Purpur) 2023-02-22 15:14:39 +00:00
Sofiane H. Djerbi
32ac7246a3 Quick refactoring 2023-02-22 00:52:27 +02:00
Sofiane H. Djerbi
4caf0ff2bd Update README.md 2023-02-21 23:47:54 +01:00
Sofiane H. Djerbi
d4ca1a3765 Merge pull request #10 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-21 23:37:10 +01:00
kugge
842d7fa834 Update Upstream (Purpur) 2023-02-21 15:13:38 +00:00
Sofiane H. Djerbi
ecad700a9e Merge pull request #9 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-20 16:40:44 +01:00
kugge
1190cfc22a Update Upstream (Purpur) 2023-02-20 15:13:51 +00:00
Sofiane H. Djerbi
0284282d7f Fix raid farm not working bug 2023-02-18 01:30:56 +02:00
kugge
229675335e Dependencies fix 2023-02-17 20:38:18 +01:00
kugge
620e5d7176 Update paperweight 2023-02-17 19:21:42 +01:00
Sofiane H. Djerbi
41dd32edac Merge pull request #8 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-17 16:21:35 +01:00
kugge
a32479ac64 Update Upstream (Purpur) 2023-02-17 15:19:23 +00:00
kugge
cf6cc82ebc Add link to wiki in config 2023-02-17 12:45:20 +01:00
kugge
6c6f02d305 Add logo 2023-02-17 12:38:21 +01:00
Sofiane H. Djerbi
12f555aa4d Optimized sinus by lithium 2023-02-17 00:40:15 +02:00
Sofiane H. Djerbi
2d37d7141c Compress logo 2023-02-16 23:31:47 +02:00
Sofiane H. Djerbi
363fcaec61 Merge branch 'ver/1.19.3' of github.com:kugge/Kaiiju into ver/1.19.3 2023-02-16 23:29:16 +02:00
Sofiane H. Djerbi
a7419fafc9 Adding lithium math fast util 2023-02-16 23:29:00 +02:00
Sofiane H. Djerbi
c06b0d77a1 Merge pull request #7 from KaiijuMC/update-upstream
Update Upstream (Purpur)
2023-02-16 16:28:02 +01:00
kugge
f07107ec59 Update Upstream (Purpur) 2023-02-16 15:15:37 +00:00
Sofiane H. Djerbi
3ef59980e7 Update paperweight 2023-02-16 04:34:37 +02:00
Sofiane H. Djerbi
e2af449239 Add purpur patch don't send useless entity packets 2023-02-16 02:15:59 +02:00
Sofiane H. Djerbi
41c0116446 Add compression level to linear region format 2023-02-16 01:34:13 +02:00
18 changed files with 1277 additions and 262 deletions

View File

@@ -1,5 +1,5 @@
name: Release Jars name: Release Jars
on: workflow_dispatch on: [push, workflow_dispatch]
env: env:
version: '1.19.3' version: '1.19.3'
branch: ver/1.19.3 branch: ver/1.19.3

View File

@@ -17,6 +17,11 @@
- **Xymb Linear Format**: Saves about 50% of disk space in OW and Nether and 95% in The End. - **Xymb Linear Format**: Saves about 50% of disk space in OW and Nether and 95% in The End.
- **Lobotomize**: Lobotomize mobs and villagers without breaking vanilla mechanics. - **Lobotomize**: Lobotomize mobs and villagers without breaking vanilla mechanics.
### Roadmap
- **Lithium**: Full implementation of Lithium.
- **C2ME**: Full implementation of C2ME.
- **VMP**: Full implementation of VMP.
## Building ## Building
In order to distribute and use this server software, you need a paperclip file: In order to distribute and use this server software, you need a paperclip file:

View File

@@ -4,25 +4,11 @@ import io.papermc.paperweight.util.constants.*
plugins { plugins {
java java
id("com.github.johnrengelman.shadow") version "7.1.2" id("com.github.johnrengelman.shadow") version "7.1.2"
id("io.papermc.paperweight.patcher") version "1.4.1" id("io.papermc.paperweight.patcher") version "1.5.1"
}
repositories {
mavenCentral()
maven("https://papermc.io/repo/repository/maven-public/") {
content { onlyForConfigurations(PAPERCLIP_CONFIG) }
}
}
dependencies {
remapper("net.fabricmc:tiny-remapper:0.8.6:fat")
decompiler("net.minecraftforge:forgeflower:2.0.605.1")
paperclip("io.papermc:paperclip:3.0.2")
} }
allprojects { allprojects {
apply(plugin = "java") apply(plugin = "java")
apply(plugin = "maven-publish")
java { java {
toolchain { toolchain {
@@ -31,8 +17,25 @@ allprojects {
} }
} }
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
repositories {
mavenCentral()
maven(paperMavenPublicUrl) {
content {
onlyForConfigurations(PAPERCLIP_CONFIG)
}
}
}
dependencies {
remapper("net.fabricmc:tiny-remapper:0.8.6:fat")
decompiler("net.minecraftforge:forgeflower:2.0.627.2")
paperclip("io.papermc:paperclip:3.0.2")
}
subprojects { subprojects {
tasks.withType<JavaCompile> { tasks.withType<JavaCompile>().configureEach {
options.encoding = Charsets.UTF_8.name() options.encoding = Charsets.UTF_8.name()
options.release.set(17) options.release.set(17)
} }
@@ -42,15 +45,9 @@ subprojects {
tasks.withType<ProcessResources> { tasks.withType<ProcessResources> {
filteringCharset = Charsets.UTF_8.name() filteringCharset = Charsets.UTF_8.name()
} }
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://oss.sonatype.org/content/groups/public/") maven(paperMavenPublicUrl)
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://ci.emc.gs/nexus/content/groups/aikar/")
maven("https://repo.aikar.co/content/groups/aikar")
maven("https://repo.md-5.net/content/repositories/releases/")
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
maven("https://jitpack.io") maven("https://jitpack.io")
} }
} }
@@ -58,8 +55,8 @@ subprojects {
paperweight { paperweight {
serverProject.set(project(":kaiiju-server")) serverProject.set(project(":kaiiju-server"))
remapRepo.set("https://maven.fabricmc.net/") remapRepo.set(paperMavenPublicUrl)
decompileRepo.set("https://maven.quiltmc.org") decompileRepo.set(paperMavenPublicUrl)
useStandardUpstream("Purpur") { useStandardUpstream("Purpur") {
url.set(github("PurpurMC", "Purpur")) url.set(github("PurpurMC", "Purpur"))
@@ -77,7 +74,7 @@ paperweight {
} }
tasks.register("purpurRefLatest") { tasks.register("purpurRefLatest") {
// Update the paperRef in gradle.properties to be the latest commit.3 // Update the purpurRef in gradle.properties to be the latest commit.
val tempDir = layout.cacheDir("purpurRefLatest"); val tempDir = layout.cacheDir("purpurRefLatest");
val file = "gradle.properties"; val file = "gradle.properties";

View File

@@ -2,7 +2,7 @@ group = dev.kaiijumc.kaiiju
version = 1.19.3-R0.1-SNAPSHOT version = 1.19.3-R0.1-SNAPSHOT
mcVersion = 1.19.3 mcVersion = 1.19.3
purpurRef = 08aa4dccaad7e5d31ca51b53489d2d413e49748d purpurRef = ade1ed1d98e936bfce92cc50ba0444d05310add4
org.gradle.caching=true org.gradle.caching=true
org.gradle.parallel=true org.gradle.parallel=true

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 MiB

After

Width:  |  Height:  |  Size: 879 KiB

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Kaiiju Rebranding
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index 020927dfe9624453311d1d171a10f44344ec8710..c6a4c48b14a8c927284720b79b93ee1aa9df7da6 100644 index f25c0557cf984b97e0ab361f579eccbf46f82170..7f1f4988a25a5ebac36c25c045c51eefecab6862 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -7,7 +7,7 @@ plugins { @@ -7,7 +7,7 @@ plugins {
@@ -17,7 +17,7 @@ index 020927dfe9624453311d1d171a10f44344ec8710..c6a4c48b14a8c927284720b79b93ee1a
// Pufferfish start // Pufferfish start
implementation("io.papermc.paper:paper-mojangapi:1.19.3-R0.1-SNAPSHOT") { implementation("io.papermc.paper:paper-mojangapi:1.19.3-R0.1-SNAPSHOT") {
exclude("io.papermc.paper", "paper-api") exclude("io.papermc.paper", "paper-api")
@@ -83,7 +83,7 @@ tasks.jar { @@ -84,7 +84,7 @@ tasks.jar {
attributes( attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main", "Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit", "Implementation-Title" to "CraftBukkit",
@@ -141,10 +141,10 @@ index cea4447aad2d64db56a76e4ba180dc7326d2e13b..40b4bd2f1a61c2d9a59c9c09b7271340
this.getRunningThread().stop(); this.getRunningThread().stop();
try { try {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 4a8aafd341fdad4b5ae326c4759b3381f5061fb5..caf1237491649205f7b3c7ea4fe1d31d567bbafe 100644 index c32e32005968b46d1f7d5162ab15c61e36f398f5..23f4edebbfa045716f956128703b58baced58f49 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -262,7 +262,7 @@ import javax.annotation.Nullable; // Paper @@ -261,7 +261,7 @@ import javax.annotation.Nullable; // Paper
import javax.annotation.Nonnull; // Paper import javax.annotation.Nonnull; // Paper
public final class CraftServer implements Server { public final class CraftServer implements Server {
@@ -251,3 +251,525 @@ index a810bfd3b8d6bd4d8f2ef8797e4281ae4fe8a67f..7e92d77edb448f2ec818bf4b876d3df5
} }
log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "------------------------------" );
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..d51e050fef81600d005e153c6a2a4c6ba7ff3388 100644
GIT binary patch
literal 17586
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
Ef}Ok25&!@I
literal 9260
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
HqBZh=dic2S

View File

@@ -6,10 +6,10 @@ Subject: [PATCH] Kaiiju Configuration
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..da7e04a93664e20b9187292ddb7c1f935f5f2883 index 0000000000000000000000000000000000000000..7da7e0aeb5eac9ac73a3570e716f1ceb11fd7027
--- /dev/null --- /dev/null
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java +++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -0,0 +1,193 @@ @@ -0,0 +1,195 @@
+package dev.kaiijumc.kaiiju; +package dev.kaiijumc.kaiiju;
+ +
+import com.google.common.base.Throwables; +import com.google.common.base.Throwables;
@@ -27,6 +27,7 @@ index 0000000000000000000000000000000000000000..da7e04a93664e20b9187292ddb7c1f93
+import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method; +import java.lang.reflect.Method;
+import java.lang.reflect.Modifier; +import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashMap; +import java.util.HashMap;
+import java.util.List; +import java.util.List;
+import java.util.Map; +import java.util.Map;
@@ -37,7 +38,8 @@ index 0000000000000000000000000000000000000000..da7e04a93664e20b9187292ddb7c1f93
+ protected static final String HEADER = "This is the main configuration file for Kaiiju.\n" + protected static final String HEADER = "This is the main configuration file for Kaiiju.\n"
+ + "Some options may impact gameplay, so use with caution.\n" + + "Some options may impact gameplay, so use with caution.\n"
+ + "If you need help or have any questions related to Kaiiju,\n" + + "If you need help or have any questions related to Kaiiju,\n"
+ + "Join our Discord server: https://discord.com/invite/qagZRAepb7"; + + "Join our Discord server: https://discord.com/invite/qagZRAepb7\n"
+ + "Documentation: https://github.com/KaiijuMC/Kaiiju/wiki/Configuration";
+ protected static File CONFIG_FILE; + protected static File CONFIG_FILE;
+ public static YamlConfiguration config; + public static YamlConfiguration config;
+ +
@@ -203,7 +205,6 @@ index 0000000000000000000000000000000000000000..da7e04a93664e20b9187292ddb7c1f93
+ return builder.build(); + return builder.build();
+ } + }
+} +}
\ No newline at end of file
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..dd4c3ca77acb3aeefc69b8eb948b8b202ff87a19 index 0000000000000000000000000000000000000000..dd4c3ca77acb3aeefc69b8eb948b8b202ff87a19
@@ -432,7 +433,7 @@ index fd1b0564d2d2b45128e6f2556fb93ee56bd683b5..948ae5f96b1d54e69b49f6314d11078f
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
// Paper end // Paper end
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index a9289072b048095330ea32d7c965e8dda61a36fc..bffd82b3d89e12f2c3d6a7e89f5a8ecd12dedc34 100644 index fef709fce7309795b6d62d33a220a2be2399efd3..213665dc92e572d7efc6e28d3ceaa74c733bc291 100644
--- a/src/main/java/net/minecraft/world/level/Level.java --- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -174,6 +174,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -174,6 +174,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -452,10 +453,10 @@ index a9289072b048095330ea32d7c965e8dda61a36fc..bffd82b3d89e12f2c3d6a7e89f5a8ecd
this.generator = gen; this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index caf1237491649205f7b3c7ea4fe1d31d567bbafe..5fd8e45d9a982e4f6aad06440110bc3c9d00bd99 100644 index e9cc9ff401233f50279bbc622050fd0894968ae1..a52ff5f8f883ba21f036b7d6830f7470567fe2b6 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1032,6 +1032,7 @@ public final class CraftServer implements Server { @@ -976,6 +976,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
this.console.paperConfigurations.reloadConfigs(this.console); this.console.paperConfigurations.reloadConfigs(this.console);
org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur
@@ -463,7 +464,7 @@ index caf1237491649205f7b3c7ea4fe1d31d567bbafe..5fd8e45d9a982e4f6aad06440110bc3c
for (ServerLevel world : this.console.getAllLevels()) { for (ServerLevel world : this.console.getAllLevels()) {
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
@@ -1048,6 +1049,7 @@ public final class CraftServer implements Server { @@ -992,6 +993,7 @@ public final class CraftServer implements Server {
} }
world.spigotConfig.init(); // Spigot world.spigotConfig.init(); // Spigot
world.purpurConfig.init(); // Purpur world.purpurConfig.init(); // Purpur
@@ -471,7 +472,7 @@ index caf1237491649205f7b3c7ea4fe1d31d567bbafe..5fd8e45d9a982e4f6aad06440110bc3c
} }
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -1064,6 +1066,7 @@ public final class CraftServer implements Server { @@ -1008,6 +1010,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.registerCommands(); // Spigot org.spigotmc.SpigotConfig.registerCommands(); // Spigot
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur
@@ -479,7 +480,7 @@ index caf1237491649205f7b3c7ea4fe1d31d567bbafe..5fd8e45d9a982e4f6aad06440110bc3c
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -2885,6 +2888,13 @@ public final class CraftServer implements Server { @@ -2830,6 +2833,13 @@ public final class CraftServer implements Server {
} }
// Purpur end // Purpur end

View File

@@ -4,37 +4,56 @@ Date: Fri, 10 Feb 2023 20:03:58 +0200
Subject: [PATCH] Kaiiju RegionFormat Configuration Subject: [PATCH] Kaiiju RegionFormat Configuration
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
index da7e04a93664e20b9187292ddb7c1f935f5f2883..66bbab7ebe1738cd937963b35fad9cdda763fa88 100644 index dd4c3ca77acb3aeefc69b8eb948b8b202ff87a19..1b180af49adee16c2d8305d01cf213322c4d721b 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java --- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java +++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
@@ -15,6 +15,7 @@ import java.io.IOException; @@ -4,9 +4,11 @@ import org.apache.commons.lang.BooleanUtils;
import java.lang.reflect.InvocationTargetException; import org.bukkit.World;
import java.lang.reflect.Method; import org.bukkit.configuration.ConfigurationSection;
import java.lang.reflect.Modifier;
+import java.util.Arrays; +import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -190,4 +191,15 @@ public class KaiijuConfig { import java.util.function.Predicate;
} +import java.util.logging.Level;
return builder.build();
import static dev.kaiijumc.kaiiju.KaiijuConfig.log;
@@ -122,4 +124,30 @@ public class KaiijuWorldConfig {
final Map<String, Object> value = getMap("world-settings." + worldName + "." + path, null);
return value.isEmpty() ? fallback : value;
} }
+ +
+ public static List<String> regionFormatList = Arrays.asList("ANVIL"); + public List<String> regionFormatList = Arrays.asList("ANVIL", "LINEAR");
+ public static String regionFormatName = "ANVIL"; + public String regionFormatName = "ANVIL";
+ public int regionFormatLinearCompressionLevel = 1;
+ public int regionFormatLinearInternalCompressionLevel = 1;
+ +
+ private static void regionFormatSettings() { + private void regionFormatSettings() {
+ regionFormatName = getString("region-format.format", regionFormatName).toUpperCase(); + regionFormatName = getString("region-format.format", regionFormatName).toUpperCase();
+ if (!regionFormatList.contains(regionFormatName)) { + if (!regionFormatList.contains(regionFormatName)) {
+ Bukkit.getLogger().log(Level.SEVERE, "Unknown region format in fusion.yml: " + regionFormatName); + log(Level.SEVERE, "Unknown region format in kaiiju.yml: " + regionFormatName);
+ Bukkit.getLogger().log(Level.SEVERE, "Falling back to ANVIL region file format."); + log(Level.SEVERE, "Falling back to ANVIL region file format.");
+ regionFormatName = "ANVIL";
+ }
+ regionFormatLinearCompressionLevel = getInt("region-format.linear.compression-level", regionFormatLinearCompressionLevel);
+ regionFormatLinearInternalCompressionLevel = getInt("region-format.linear.internal-compression-level", regionFormatLinearInternalCompressionLevel);
+ if (regionFormatLinearCompressionLevel > 23 || regionFormatLinearCompressionLevel < 1) {
+ log(Level.SEVERE, "Linear region compression level should be between 1 and 22 in kaiiju.yml: " + regionFormatLinearCompressionLevel);
+ log(Level.SEVERE, "Falling back to compression level 1.");
+ regionFormatLinearCompressionLevel = 1;
+ }
+ if (regionFormatLinearInternalCompressionLevel > 23 || regionFormatLinearInternalCompressionLevel < 1) {
+ log(Level.SEVERE, "Linear region compression level should be between 1 and 22 in kaiiju.yml: " + regionFormatLinearCompressionLevel);
+ log(Level.SEVERE, "Falling back to compression level 1.");
+ regionFormatLinearCompressionLevel = 1;
+ } + }
+ } + }
} }
\ No newline at end of file \ No newline at end of file
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 40b4bd2f1a61c2d9a59c9c09b72713401969460b..b9998c288c4e8b6a244722915e44250b6550fd7e 100644 index c1b88ae704b3d2b8ebbad28c0291a4ad12e6d5d9..ae4dd7db4e4e32fe8100309d770307fccf31110d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -855,7 +855,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -855,7 +855,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -8,7 +8,7 @@ Copyright xymb@endcrystal.me
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index c6a4c48b14a8c927284720b79b93ee1aa9df7da6..2ea3d2f26d4547ea5094cc63d492ea1406ffbd44 100644 index abfd4d5faf23511284b4efac771ef79da0ef72da..0a6549d0f545e81ae95527797333f2e2da85e1f1 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -13,6 +13,10 @@ dependencies { @@ -13,6 +13,10 @@ dependencies {
@@ -16,7 +16,7 @@ index c6a4c48b14a8c927284720b79b93ee1aa9df7da6..2ea3d2f26d4547ea5094cc63d492ea14
} }
// Pufferfish end // Pufferfish end
+ // Kaiiju start - Linear format + // Kaiiju start - Linear format
+ implementation("com.github.luben:zstd-jni:1.5.2-5") + implementation("com.github.luben:zstd-jni:1.5.4-1")
+ implementation("org.lz4:lz4-java:1.8.0") + implementation("org.lz4:lz4-java:1.8.0")
+ // Kaiiju end + // Kaiiju end
// Paper start // Paper start
@@ -37,25 +37,12 @@ index f2c27e0ac65be4b75c1d86ef6fd45fdb538d96ac..00724993d0448454d14a47652b039b88
public static final class InProgressWrite { public static final class InProgressWrite {
public long writeCounter; public long writeCounter;
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 66bbab7ebe1738cd937963b35fad9cdda763fa88..16ebf32e0c62025958c95216531f72cc418e8d14 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -192,7 +192,7 @@ public class KaiijuConfig {
return builder.build();
}
- public static List<String> regionFormatList = Arrays.asList("ANVIL");
+ public static List<String> regionFormatList = Arrays.asList("ANVIL", "LINEAR");
public static String regionFormatName = "ANVIL";
private static void regionFormatSettings() {
diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..70d53d80f474eb80acc93275ad6bf1da98ea8ae7 index 0000000000000000000000000000000000000000..249303116d3cfadd078ebf0ae6e44bf99eed6a47
--- /dev/null --- /dev/null
+++ b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java +++ b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java
@@ -0,0 +1,32 @@ @@ -0,0 +1,31 @@
+package dev.kaiijumc.kaiiju.region; +package dev.kaiijumc.kaiiju.region;
+ +
+import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.CompoundTag;
@@ -69,64 +56,55 @@ index 0000000000000000000000000000000000000000..70d53d80f474eb80acc93275ad6bf1da
+import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantLock;
+ +
+public interface AbstractRegionFile { +public interface AbstractRegionFile {
+ boolean doesChunkExist(ChunkPos pos) throws Exception;
+ void flush() throws IOException; + void flush() throws IOException;
+ void setStatus(int x, int z, ChunkStatus status);
+ void clear(ChunkPos pos) throws IOException; + void clear(ChunkPos pos) throws IOException;
+ boolean hasChunk(ChunkPos pos);
+ void close() throws IOException; + void close() throws IOException;
+ void setStatus(int x, int z, ChunkStatus status);
+ void setOversized(int x, int z, boolean b) throws IOException;
+
+ boolean hasChunk(ChunkPos pos);
+ boolean doesChunkExist(ChunkPos pos) throws Exception;
+ boolean isOversized(int x, int z);
+ boolean recalculateHeader() throws IOException;
+ +
+ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; + DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException;
+ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; + DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException;
+ ChunkStatus getStatusIfCached(int x, int z);
+
+ Path getRegionFile();
+ ReentrantLock getFileLock();
+
+ void setOversized(int x, int z, boolean b) throws IOException;
+ CompoundTag getOversizedData(int x, int z) throws IOException; + CompoundTag getOversizedData(int x, int z) throws IOException;
+ boolean isOversized(int x, int z); + ChunkStatus getStatusIfCached(int x, int z);
+ boolean recalculateHeader() throws IOException; + ReentrantLock getFileLock();
+ Path getRegionFile();
+} +}
diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0b84b1aa4b822bdcb783285e8ea99a4f25dbbaa3 index 0000000000000000000000000000000000000000..67991815a0ff9235a846ca8db817c90f094c4a58
--- /dev/null --- /dev/null
+++ b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java +++ b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFileFactory.java
@@ -0,0 +1,38 @@ @@ -0,0 +1,30 @@
+package dev.kaiijumc.kaiiju.region; +package dev.kaiijumc.kaiiju.region;
+ +
+import net.minecraft.world.level.chunk.storage.RegionFile; +import net.minecraft.world.level.chunk.storage.RegionFile;
+import net.minecraft.world.level.chunk.storage.RegionFileVersion; +import net.minecraft.world.level.chunk.storage.RegionFileVersion;
+ +
+import java.io.File;
+import java.io.IOException; +import java.io.IOException;
+import java.nio.file.Path; +import java.nio.file.Path;
+ +
+public class AbstractRegionFileFactory { +public class AbstractRegionFileFactory {
+ public static AbstractRegionFile getAbstractRegionFile(Path file, Path directory, boolean dsync) throws IOException { +
+ return getAbstractRegionFile(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync); + public static AbstractRegionFile getAbstractRegionFile(int linearCompression, int linearInternalCompression, Path file, Path directory, boolean dsync) throws IOException {
+ return getAbstractRegionFile(linearCompression, linearInternalCompression, file, directory, RegionFileVersion.VERSION_DEFLATE, dsync);
+ } + }
+ +
+ public static AbstractRegionFile getAbstractRegionFile(Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException { + public static AbstractRegionFile getAbstractRegionFile(int linearCompression, int linearInternalCompression, Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException {
+ return getAbstractRegionFile(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader); + return getAbstractRegionFile(linearCompression, linearInternalCompression, file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader);
+ } + }
+ +
+ public static AbstractRegionFile getAbstractRegionFile(File file, File directory, boolean dsync) throws IOException { + public static AbstractRegionFile getAbstractRegionFile(int linearCompression, int linearInternalCompression, Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException {
+ return getAbstractRegionFile(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); + return getAbstractRegionFile(linearCompression, linearInternalCompression, file, directory, outputChunkStreamVersion, dsync, false);
+ } + }
+ +
+ public static AbstractRegionFile getAbstractRegionFile(File file, File directory, boolean dsync, boolean canRecalcHeader) throws IOException { + public static AbstractRegionFile getAbstractRegionFile(int linearCompression, int linearInternalCompression, Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException {
+ return getAbstractRegionFile(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader); + if (file.toString().endsWith(".linear")) {
+ } + return new LinearRegionFile(file, linearCompression, linearInternalCompression);
+
+ public static AbstractRegionFile getAbstractRegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException {
+ return getAbstractRegionFile(file, directory, outputChunkStreamVersion, dsync, false);
+ }
+
+ public static AbstractRegionFile getAbstractRegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) {
+ return new LinearRegionFile(file, directory, outputChunkStreamVersion, dsync, canRecalcHeader);
+ } else { + } else {
+ return new RegionFile(file, directory, outputChunkStreamVersion, dsync, canRecalcHeader); + return new RegionFile(file, directory, outputChunkStreamVersion, dsync, canRecalcHeader);
+ } + }
@@ -134,23 +112,19 @@ index 0000000000000000000000000000000000000000..0b84b1aa4b822bdcb783285e8ea99a4f
+} +}
diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52573d1944 index 0000000000000000000000000000000000000000..df2edc187480aef6af1cbeb82824984e31672068
--- /dev/null --- /dev/null
+++ b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java +++ b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFile.java
@@ -0,0 +1,338 @@ @@ -0,0 +1,325 @@
+package dev.kaiijumc.kaiiju.region; +package dev.kaiijumc.kaiiju.region;
+ +
+import com.github.luben.zstd.ZstdInputStream; +import com.github.luben.zstd.Zstd;import com.github.luben.zstd.ZstdInputStream;
+import com.github.luben.zstd.ZstdOutputStream; +import com.github.luben.zstd.ZstdOutputStream;
+import com.mojang.logging.LogUtils; +import com.mojang.logging.LogUtils;
+import net.jpountz.lz4.LZ4Compressor;
+import net.jpountz.lz4.LZ4Factory;
+import net.jpountz.lz4.LZ4FastDecompressor;
+import net.jpountz.xxhash.XXHashFactory; +import net.jpountz.xxhash.XXHashFactory;
+import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.ChunkStatus;
+import net.minecraft.world.level.chunk.storage.RegionFileVersion;
+import org.slf4j.Logger; +import org.slf4j.Logger;
+ +
+import javax.annotation.Nullable; +import javax.annotation.Nullable;
@@ -160,6 +134,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+import java.nio.file.Path; +import java.nio.file.Path;
+import java.nio.file.StandardCopyOption; +import java.nio.file.StandardCopyOption;
+import java.util.ArrayList; +import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantLock;
+ +
+public class LinearRegionFile extends Thread implements AbstractRegionFile { +public class LinearRegionFile extends Thread implements AbstractRegionFile {
@@ -167,13 +142,17 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ private final byte[][] buffer = new byte[32*32][]; + private final byte[][] buffer = new byte[32*32][];
+ private final int[] bufferUncompressedSize = new int[32*32]; + private final int[] bufferUncompressedSize = new int[32*32];
+ +
+ private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
+ private boolean markedToSave = false;
+ private final Object markedToSaveLock = new Object(); + private final Object markedToSaveLock = new Object();
+ private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
+
+ private boolean markedToSave = false;
+ private boolean close = false; + private boolean close = false;
+ public Path regionFile; +
+ public final ReentrantLock fileLock = new ReentrantLock(true); + public final ReentrantLock fileLock = new ReentrantLock(true);
+ final byte COMPRESSION_LEVEL = 1; + public Path regionFile;
+
+ private final int compressionLevel;
+ private final int internalCompressionLevel;
+ +
+ public Path getRegionFile() { + public Path getRegionFile() {
+ return this.regionFile; + return this.regionFile;
@@ -183,13 +162,13 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ return this.fileLock; + return this.fileLock;
+ } + }
+ +
+ public LinearRegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException { + public LinearRegionFile(Path file, int compression, int internalCompression) throws IOException {
+ this.regionFile = file; + this.regionFile = file;
+ this.compressionLevel = compression;
+ this.internalCompressionLevel = internalCompression;
+ File regionFile = new File(this.regionFile.toString()); + File regionFile = new File(this.regionFile.toString());
+ +
+ LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor(); + for (int i = 0; i < 32 * 32; i++)
+
+ for (int i = 0 ; i < 32 * 32 ; i++)
+ this.bufferUncompressedSize[i] = 0; + this.bufferUncompressedSize[i] = 0;
+ +
+ if(regionFile.canRead()) { + if(regionFile.canRead()) {
@@ -205,17 +184,13 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ long superBlock = rawDataStream.readLong(); + long superBlock = rawDataStream.readLong();
+ +
+ if (superBlock != SUPERBLOCK) { + if (superBlock != SUPERBLOCK) {
+ System.out.println(file.toString()); + throw new IOException("SUPERBLOCK VERSION! " + file);
+ System.out.println("SUPERBLOCK INVALID!");
+ return;
+ } + }
+ +
+ byte version = rawDataStream.readByte(); + byte version = rawDataStream.readByte();
+ +
+ if (version != VERSION) { + if (version != VERSION) {
+ System.out.println(file.toString()); + throw new IOException("INVALID VERSION! " + file);
+ System.out.println("VERSION INVALID!");
+ return;
+ } + }
+ +
+ rawDataStream.readLong(); // newestTimestamp + rawDataStream.readLong(); // newestTimestamp
@@ -224,7 +199,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ int dataCount = rawDataStream.readInt(); + int dataCount = rawDataStream.readInt();
+ +
+ if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) { + if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) {
+ throw new IOException("File length invalid " + this.regionFile + " " + String.valueOf(fileLength) + " " + String.valueOf(HEADER_SIZE + dataCount + FOOTER_SIZE)); + throw new IOException("File length invalid " + this.regionFile + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
+ } + }
+ +
+ rawDataStream.readLong(); // Data Hash + rawDataStream.readLong(); // Data Hash
@@ -252,11 +227,10 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ byte[] b = new byte[size]; + byte[] b = new byte[size];
+ dataStream.readFully(b, 0, size); + dataStream.readFully(b, 0, size);
+ +
+ int maxCompressedLength = compressor.maxCompressedLength(size); + int maxCompressedLength = (int)Zstd.compressBound(size);
+ byte[] compressed = new byte[maxCompressedLength]; + byte[] compressed = new byte[maxCompressedLength];
+ int compressedLength = compressor.compress(b, 0, size, compressed, 0, maxCompressedLength); + long compressedLength = Zstd.compress(compressed, b, this.internalCompressionLevel);
+ b = new byte[compressedLength]; + b = Arrays.copyOfRange(compressed, 0, (int) compressedLength);
+ System.arraycopy(compressed, 0, b, 0, compressedLength);
+ +
+ this.buffer[i] = b; + this.buffer[i] = b;
+ this.bufferUncompressedSize[i] = size; + this.bufferUncompressedSize[i] = size;
@@ -289,7 +263,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ try { + try {
+ flush(); + flush();
+ } catch(IOException ex) { + } catch(IOException ex) {
+ LOGGER.error("Region file " + this.regionFile.toAbsolutePath() + " flush failed"); + LOGGER.error("Region file " + this.regionFile.toAbsolutePath() + " flush failed", ex);
+ } + }
+ } + }
+ for(int i = 0 ; i < 100 ; i++) { + for(int i = 0 ; i < 100 ; i++) {
@@ -319,7 +293,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ FileOutputStream fileStream = new FileOutputStream(tempFile); + FileOutputStream fileStream = new FileOutputStream(tempFile);
+ +
+ ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream(); + ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream();
+ ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, COMPRESSION_LEVEL); + ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel);
+ zstdStream.setChecksum(true); + zstdStream.setChecksum(true);
+ DataOutputStream zstdDataStream = new DataOutputStream(zstdStream); + DataOutputStream zstdDataStream = new DataOutputStream(zstdStream);
+ DataOutputStream dataStream = new DataOutputStream(fileStream); + DataOutputStream dataStream = new DataOutputStream(fileStream);
@@ -327,16 +301,14 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ dataStream.writeLong(SUPERBLOCK); + dataStream.writeLong(SUPERBLOCK);
+ dataStream.writeByte(VERSION); + dataStream.writeByte(VERSION);
+ dataStream.writeLong(timestamp); + dataStream.writeLong(timestamp);
+ dataStream.writeByte(COMPRESSION_LEVEL); + dataStream.writeByte(this.compressionLevel);
+ +
+ LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); + ArrayList<byte[]> byteBuffers = new ArrayList<>();
+
+ ArrayList<byte[]> byteBuffers = new ArrayList<byte[]>();
+ for(int i = 0 ; i < 32 * 32 ; i++) { + for(int i = 0 ; i < 32 * 32 ; i++) {
+ if(this.bufferUncompressedSize[i] != 0) { + if(this.bufferUncompressedSize[i] != 0) {
+ chunkCount += 1; + chunkCount += 1;
+ byte[] content = new byte[bufferUncompressedSize[i]]; + byte[] content = new byte[bufferUncompressedSize[i]];
+ decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]); + Zstd.decompress(content, buffer[i]);
+ +
+ byteBuffers.add(content); + byteBuffers.add(content);
+ } else byteBuffers.add(null); + } else byteBuffers.add(null);
@@ -372,27 +344,20 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ } + }
+ +
+ public synchronized void write(ChunkPos pos, ByteBuffer buffer) { + public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
+ LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
+ try { + try {
+ byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); + byte[] b = toByteArray(new ByteArrayInputStream(buffer.array()));
+ int uncompressedSize = b.length; + int uncompressedSize = b.length;
+ + byte[] compressed = Zstd.compress(b, this.internalCompressionLevel);
+ int maxCompressedLength = compressor.maxCompressedLength(b.length); + this.buffer[getChunkIndex(pos.x, pos.z)] = compressed;
+ byte[] compressed = new byte[maxCompressedLength];
+ int compressedLength = compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength);
+ b = new byte[compressedLength];
+ System.arraycopy(compressed, 0, b, 0, compressedLength);
+
+ this.buffer[getChunkIndex(pos.x, pos.z)] = b;
+ this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; + this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize;
+ } catch (IOException e) { + } catch (IOException e) {
+ LOGGER.error("Chunk write IOException " + e.toString() + " " + this.regionFile); + LOGGER.error("Chunk write IOException " + e + " " + this.regionFile);
+ } + }
+ +
+ markToSave(); + markToSave();
+ } + }
+ +
+ public DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException { + public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
+ return new DataOutputStream(new BufferedOutputStream(new LinearRegionFile.ChunkBuffer(pos))); + return new DataOutputStream(new BufferedOutputStream(new LinearRegionFile.ChunkBuffer(pos)));
+ } + }
+ +
@@ -424,11 +389,11 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ } + }
+ +
+ @Nullable + @Nullable
+ public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException { + public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
+ if(this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) { + if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
+ LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); + byte[] compressedData = this.buffer[getChunkIndex(pos.x, pos.z)];
+ byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]]; + byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]];
+ decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]); + Zstd.decompress(content, compressedData);
+ return new DataInputStream(new ByteArrayInputStream(content)); + return new DataInputStream(new ByteArrayInputStream(content));
+ } + }
+ return null; + return null;
@@ -454,7 +419,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ try { + try {
+ flush(); + flush();
+ } catch(IOException e) { + } catch(IOException e) {
+ throw new IOException("Region flush IOException " + e.toString() + " " + this.regionFile); + throw new IOException("Region flush IOException " + e + " " + this.regionFile);
+ } + }
+ } + }
+ +
@@ -462,7 +427,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ return (x & 31) + (z & 31) * 32; + return (x & 31) + (z & 31) * 32;
+ } + }
+ +
+ public boolean recalculateHeader() throws IOException { + public boolean recalculateHeader() {
+ return false; + return false;
+ } + }
+ +
@@ -477,7 +442,7 @@ index 0000000000000000000000000000000000000000..ba4910d564064a1367cb9d727e8fcc52
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
index a08cde4eefe879adcee7c4118bc38f98c5097ed0..77ce70697f2a634927fd02f2a103c91a7bf09d2a 100644 index a08cde4eefe879adcee7c4118bc38f98c5097ed0..1cfc20b7496f93aff1d6c2387dc5bb8bacab8dc8 100644
--- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java --- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
+++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java +++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
@@ -811,7 +811,7 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { @@ -811,7 +811,7 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread {
@@ -543,31 +508,50 @@ index a08cde4eefe879adcee7c4118bc38f98c5097ed0..77ce70697f2a634927fd02f2a103c91a
} }
} }
} }
@@ -1287,6 +1287,12 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
} catch (final ThreadDeath thr) { index 95cac7edae8ac64811fc6a2f6b97dd4a0fceb0b0..e340878efb93499acd7fdf83a66ead9b53210a76 100644
throw thr; --- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
} catch (final Throwable thr) { +++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
+ // Kaiiju start - Linear region format @@ -83,9 +83,15 @@ public class ThreadedWorldUpgrader {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) { }
+ failedWrite = thr instanceof IOException; LOGGER.info("Found " + regionFiles.length + " regionfiles to convert");
+ LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr); LOGGER.info("Starting conversion now for world " + this.worldName);
+ } else { -
+ // Kaiiju end + // Kaiiju start
if (thr instanceof RegionFileStorage.RegionFileSizeException) { + net.minecraft.server.level.ServerLevel level = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle();
final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024); + String formatName = level.kaiijuConfig.regionFormatName;
LOGGER.error("Chunk at (" + this.chunkX + "," + this.chunkZ + ") in '" + this.world.getWorld().getName() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk."); + int linearCompression = level.kaiijuConfig.regionFormatLinearCompressionLevel;
@@ -1294,6 +1300,7 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { + int internalLinearCompression = level.kaiijuConfig.regionFormatLinearInternalCompressionLevel;
failedWrite = thr instanceof IOException; + LOGGER.info("Using format " + formatName + " (" + linearCompression + ")");
LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr); + // Kaiiju end
} final WorldInfo info = new WorldInfo(() -> worldPersistentData,
+ } // Kaiiju - new ChunkStorage(regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey);
} + new ChunkStorage(formatName, linearCompression, internalLinearCompression, regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey); // Kaiiju
long expectedChunks = (long)regionFiles.length * (32L * 32L);
final boolean finalFailWrite = failedWrite;
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 75965afd7b4bed23a5ecf618c7f91ff5e7ffd92f..2158c576aa47ef618b7602c2f4e351b7beb023b3 100644 index 75965afd7b4bed23a5ecf618c7f91ff5e7ffd92f..3dd88803c5897ac856c107e7f54c3b73cba5adf8 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -291,7 +291,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
- super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
+ super(world.getLevel().kaiijuConfig.regionFormatName, world.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, world.getLevel().kaiijuConfig.regionFormatLinearInternalCompressionLevel, session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Kaiiju
// Paper - rewrite chunk system
this.tickingGenerated = new AtomicInteger();
this.playerMap = new PlayerMap();
@@ -336,7 +336,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), null, null); // Paper - rewrite chunk system
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
this.overworldDataStorage = persistentStateManagerFactory;
- this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world);
+ this.poiManager = new PoiManager(this.level.kaiijuConfig.regionFormatName, this.level.kaiijuConfig.regionFormatLinearCompressionLevel, this.level.kaiijuConfig.regionFormatLinearInternalCompressionLevel, path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); // Kaiiju
this.setViewDistance(viewDistance);
// Paper start
this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
@@ -950,13 +950,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -950,13 +950,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper start - chunk status cache "api" // Paper start - chunk status cache "api"
@@ -593,50 +577,119 @@ index 75965afd7b4bed23a5ecf618c7f91ff5e7ffd92f..2158c576aa47ef618b7602c2f4e351b7
regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkSerializer.getStatus(compound)); regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkSerializer.getStatus(compound));
} }
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index a5655ebb233f1e1e1dd7f79fdd948020478928fc..92430e71f64d88352838ee9cf0f4d22c050e7acc 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -390,9 +390,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
private final EntityRegionFileStorage entityStorage;
private static final class EntityRegionFileStorage extends net.minecraft.world.level.chunk.storage.RegionFileStorage {
-
- public EntityRegionFileStorage(Path directory, boolean dsync) {
- super(directory, dsync);
+ public EntityRegionFileStorage(String format, int linearCompression, int linearInternalCompression, Path directory, boolean dsync) { // Kaiiju
+ super(format, linearCompression, linearInternalCompression, directory, dsync); // Kaiiju
}
protected void write(ChunkPos pos, net.minecraft.nbt.CompoundTag nbt) throws IOException {
@@ -583,7 +582,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
// CraftBukkit end
boolean flag2 = minecraftserver.forceSynchronousWrites();
DataFixer datafixer = minecraftserver.getFixerUpper();
- this.entityStorage = new EntityRegionFileStorage(convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver);
+ this.entityStorage = new EntityRegionFileStorage(this.getLevel().kaiijuConfig.regionFormatName, this.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, this.getLevel().kaiijuConfig.regionFormatLinearInternalCompressionLevel, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); // Kaiiju
// this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper // Paper - rewrite chunk system
StructureTemplateManager structuretemplatemanager = minecraftserver.getStructureManager();
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
index 759b125cc1251b9b4f1f443c9f70c482ef5b32f8..aca60733c87f7f95b5719ded24eb8cf697f9d83e 100644 index 759b125cc1251b9b4f1f443c9f70c482ef5b32f8..761293b17cf12e28487034508906702bae2a3feb 100644
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java --- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -61,10 +61,17 @@ public class WorldUpgrader { @@ -61,7 +61,7 @@ public class WorldUpgrader {
private volatile int skipped; private volatile int skipped;
private final Object2FloatMap<ResourceKey<LevelStem>> progressMap = Object2FloatMaps.synchronize(new Object2FloatOpenCustomHashMap(Util.identityStrategy())); // CraftBukkit private final Object2FloatMap<ResourceKey<LevelStem>> progressMap = Object2FloatMaps.synchronize(new Object2FloatOpenCustomHashMap(Util.identityStrategy())); // CraftBukkit
private volatile Component status = Component.translatable("optimizeWorld.stage.counting"); private volatile Component status = Component.translatable("optimizeWorld.stage.counting");
- public static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); - public static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
+ public static Pattern REGEX; // Kaiiju + public static Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.(linear | mca)$"); // Kaiiju
private final DimensionDataStorage overworldDataStorage; private final DimensionDataStorage overworldDataStorage;
public WorldUpgrader(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, Registry<LevelStem> dimensionOptionsRegistry, boolean eraseCache) { public WorldUpgrader(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, Registry<LevelStem> dimensionOptionsRegistry, boolean eraseCache) {
+ // Kaiiju start @@ -115,8 +115,14 @@ public class WorldUpgrader {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) { while (iterator1.hasNext()) {
+ this.REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.linear$"); ResourceKey<LevelStem> resourcekey1 = (ResourceKey) iterator1.next(); // CraftBukkit
+ } else { Path path = this.levelStorage.getDimensionPath((ResourceKey) null); // CraftBukkit
+ this.REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); -
+ } - builder1.put(resourcekey1, new ChunkStorage(path.resolve("region"), this.dataFixer, true));
+ // Kaiiju end + // Kaiiju start
this.dimensions = dimensionOptionsRegistry; + String worldName = this.levelStorage.getLevelId();
this.levels = (Set) dimensionOptionsRegistry.registryKeySet().stream().collect(Collectors.toUnmodifiableSet()); // CraftBukkit + net.minecraft.server.level.ServerLevel level = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle();
this.eraseCache = eraseCache; + String formatName = level.kaiijuConfig.regionFormatName;
@@ -235,6 +242,11 @@ public class WorldUpgrader { + int linearCompression = level.kaiijuConfig.regionFormatLinearCompressionLevel;
+ int linearInternalCompression = level.kaiijuConfig.regionFormatLinearInternalCompressionLevel;
+ builder1.put(resourcekey1, new ChunkStorage(formatName, linearCompression, linearInternalCompression, path.resolve("region"), this.dataFixer, true));
+ // Kaiiju end
}
ImmutableMap<ResourceKey<LevelStem>, ChunkStorage> immutablemap1 = builder1.build(); // CraftBukkit
@@ -235,7 +241,7 @@ public class WorldUpgrader {
File file = this.levelStorage.getDimensionPath((ResourceKey) null).toFile(); // CraftBukkit File file = this.levelStorage.getDimensionPath((ResourceKey) null).toFile(); // CraftBukkit
File file1 = new File(file, "region"); File file1 = new File(file, "region");
File[] afile = file1.listFiles((file2, s) -> { File[] afile = file1.listFiles((file2, s) -> {
+ // Kaiiju start - return s.endsWith(".mca");
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) { + return s.endsWith(".mca") || s.endsWith(".linear"); // Kaiiju
+ return s.endsWith(".linear");
+ }
+ // Kaiiju end
return s.endsWith(".mca");
}); });
@@ -254,7 +266,7 @@ public class WorldUpgrader { if (afile == null) {
@@ -254,7 +260,13 @@ public class WorldUpgrader {
int l = Integer.parseInt(matcher.group(2)) << 5; int l = Integer.parseInt(matcher.group(2)) << 5;
try { try {
- RegionFile regionfile = new RegionFile(file2.toPath(), file1.toPath(), true); - RegionFile regionfile = new RegionFile(file2.toPath(), file1.toPath(), true);
+ dev.kaiijumc.kaiiju.region.AbstractRegionFile regionfile = dev.kaiijumc.kaiiju.region.AbstractRegionFileFactory.getAbstractRegionFile(file2.toPath(), file1.toPath(), true); // Kaiiju + // Kaiiju start
+ String worldName = this.levelStorage.getLevelId();
+ net.minecraft.server.level.ServerLevel level = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle();
+ int linearCompression = level.kaiijuConfig.regionFormatLinearCompressionLevel;
+ int linearInternalCompression = level.kaiijuConfig.regionFormatLinearInternalCompressionLevel;
+ dev.kaiijumc.kaiiju.region.AbstractRegionFile regionfile = dev.kaiijumc.kaiiju.region.AbstractRegionFileFactory.getAbstractRegionFile(linearCompression, linearInternalCompression, file2.toPath(), file1.toPath(), true);
+ // Kaiiju end
try { try {
for (int i1 = 0; i1 < 32; ++i1) { for (int i1 = 0; i1 < 32; ++i1) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
index 8950b220b9a3512cd4667beb7bdec0e82e07edc6..ca93af37207a78e41b6d20333638bec32c11c416 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
@@ -57,8 +57,8 @@ public class PoiManager extends SectionStorage<PoiSection> {
// Paper end - rewrite chunk system
- public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) {
- super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world);
+ public PoiManager(String formatName, int linearCompression, int linearInternalCompression, Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { // Kaiiju
+ super(formatName, linearCompression, linearInternalCompression, path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); // Kaiiju
this.world = (net.minecraft.server.level.ServerLevel)world; // Paper - rewrite chunk system
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
index 5a425be023d77f0370d102dfb52427147849ac1a..527384a43f5c512273cce0d16a3bc887e24357c2 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
@@ -37,11 +37,12 @@ public class ChunkStorage implements AutoCloseable {
public final RegionFileStorage regionFileCache;
// Paper end - async chunk loading
- public ChunkStorage(Path directory, DataFixer dataFixer, boolean dsync) {
+ public ChunkStorage(String format, int linearCompression, int linearInternalCompression, Path directory, DataFixer dataFixer, boolean dsync) { // Kaiiju
this.fixerUpper = dataFixer;
+
// Paper start - async chunk io
// remove IO worker
- this.regionFileCache = new RegionFileStorage(directory, dsync, true); // Paper - nuke IOWorker // Paper
+ this.regionFileCache = new RegionFileStorage(format, linearCompression, linearInternalCompression, directory, dsync, true); // Paper - nuke IOWorker // Paper // Kaiiju
// Paper end - async chunk io
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index dcfe090c269d4cbcc2eb1b6f85392848bb34656c..d42c320179ae055b8675d1ce6ce1788ecafb8e9d 100644 index dcfe090c269d4cbcc2eb1b6f85392848bb34656c..d42c320179ae055b8675d1ce6ce1788ecafb8e9d 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -699,39 +752,51 @@ index dcfe090c269d4cbcc2eb1b6f85392848bb34656c..d42c320179ae055b8675d1ce6ce1788e
try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) { try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) {
return NbtIo.read((java.io.DataInput) out); return NbtIo.read((java.io.DataInput) out);
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da747cf30c 100644 index bd502ca721de0cab438d995efa00ad0554c0d2fe..ad784bc53d5c9a4abb944ce21e5bb81b939ecbea 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -21,8 +21,9 @@ import net.minecraft.world.level.ChunkPos; @@ -22,17 +22,27 @@ public class RegionFileStorage implements AutoCloseable {
public class RegionFileStorage implements AutoCloseable {
public static final String ANVIL_EXTENSION = ".mca"; public static final String ANVIL_EXTENSION = ".mca";
+ public static final String LINEAR_EXTENSION = ".linear"; // Kaiiju
private static final int MAX_CACHE_SIZE = 256; private static final int MAX_CACHE_SIZE = 256;
- public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap(); - public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap();
+ public final Long2ObjectLinkedOpenHashMap<dev.kaiijumc.kaiiju.region.AbstractRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap(); // Kaiiju + public final Long2ObjectLinkedOpenHashMap<dev.kaiijumc.kaiiju.region.AbstractRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap(); // Kaiiju
private final Path folder; private final Path folder;
private final boolean sync; private final boolean sync;
+ // Kaiiju start - Per world chunk format
+ public final String format;
+ public final int linearCompression;
+ public final int linearInternalCompression;
+ // Kaiiju end
@@ -42,9 +43,17 @@ public class RegionFileStorage implements AutoCloseable { private final boolean isChunkData; // Paper
- protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor
+ protected RegionFileStorage(String format, int linearCompression, int linearInternalCompression, Path directory, boolean dsync) { // Paper - protected constructor
// Paper start - add isChunkData param
- this(directory, dsync, false);
+ this(format, linearCompression, linearInternalCompression, directory, dsync, false);
}
- RegionFileStorage(Path directory, boolean dsync, boolean isChunkData) {
+ RegionFileStorage(String format, int linearCompression, int linearInternalCompression, Path directory, boolean dsync, boolean isChunkData) { // Kaiiju
+ // Kaiiju start
+ this.format = format;
+ this.linearCompression = linearCompression;
+ this.linearInternalCompression = linearInternalCompression;
+ // Kaiiju end
this.isChunkData = isChunkData;
// Paper end - add isChunkData param
this.folder = directory;
@@ -42,7 +52,7 @@ public class RegionFileStorage implements AutoCloseable {
// Paper start // Paper start
public static @Nullable ChunkPos getRegionFileCoordinates(Path file) { public static @Nullable ChunkPos getRegionFileCoordinates(Path file) {
String fileName = file.getFileName().toString(); String fileName = file.getFileName().toString();
+ // Kaiiju start - if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) { + if (!fileName.startsWith("r.") || !fileName.endsWith(".mca") || !fileName.endsWith(".linear")) { // Kaiiju
+ if (!fileName.startsWith("r.") || !fileName.endsWith(".linear")) {
+ return null;
+ }
+ } else {
+ // Kaiiju end
if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
return null; return null;
} }
+ } // Kaiiju
String[] split = fileName.split("\\."); @@ -62,49 +72,66 @@ public class RegionFileStorage implements AutoCloseable {
@@ -62,49 +71,57 @@ public class RegionFileStorage implements AutoCloseable {
} }
} }
@@ -777,18 +842,28 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
Path path = this.folder; Path path = this.folder;
int j = chunkcoordintpair.getRegionX(); int j = chunkcoordintpair.getRegionX();
- Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change - Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
+ // Kaiiju start - if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit
- RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
+ // Kaiiju start - Polyglot
+ //Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change + //Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
+ Path path1; + Path path1;
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatName.equals("LINEAR")) { + if (existingOnly) {
+ path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".linear"); + Path anvil = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
+ Path linear = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".linear");
+ if (java.nio.file.Files.exists(anvil)) path1 = anvil;
+ else if (java.nio.file.Files.exists(linear)) path1 = linear;
+ else return null;
+ } else { + } else {
+ path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); + String extension = switch (this.format) {
+ case "LINEAR" -> "linear";
+ default -> "mca";
+ };
+ path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + "." + extension);
+ } + }
+ //if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit
+ // Kaiiju end + // Kaiiju end
if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit +
- RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header + dev.kaiijumc.kaiiju.region.AbstractRegionFile regionfile1 = dev.kaiijumc.kaiiju.region.AbstractRegionFileFactory.getAbstractRegionFile(this.linearCompression, this.linearInternalCompression, path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header // Kaiiju
+ dev.kaiijumc.kaiiju.region.AbstractRegionFile regionfile1 = dev.kaiijumc.kaiiju.region.AbstractRegionFileFactory.getAbstractRegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header // Kaiiju
this.regionCache.putAndMoveToFirst(i, regionfile1); this.regionCache.putAndMoveToFirst(i, regionfile1);
// Paper start // Paper start
@@ -799,7 +874,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
} }
// Paper end // Paper end
return regionfile1; return regionfile1;
@@ -132,7 +149,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -132,7 +159,7 @@ public class RegionFileStorage implements AutoCloseable {
} }
@@ -808,7 +883,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
synchronized (regionfile) { synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
@@ -179,14 +196,14 @@ public class RegionFileStorage implements AutoCloseable { @@ -179,14 +206,14 @@ public class RegionFileStorage implements AutoCloseable {
@Nullable @Nullable
public CompoundTag read(ChunkPos pos) throws IOException { public CompoundTag read(ChunkPos pos) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
@@ -825,7 +900,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
// We add the regionfile parameter to avoid the potential deadlock (on fileLock) if we went back to obtain a regionfile // We add the regionfile parameter to avoid the potential deadlock (on fileLock) if we went back to obtain a regionfile
// if we decide to re-read // if we decide to re-read
// Paper end // Paper end
@@ -196,7 +213,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -196,7 +223,7 @@ public class RegionFileStorage implements AutoCloseable {
// Paper start // Paper start
if (regionfile.isOversized(pos.x, pos.z)) { if (regionfile.isOversized(pos.x, pos.z)) {
@@ -834,7 +909,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
return readOversizedChunk(regionfile, pos); return readOversizedChunk(regionfile, pos);
} }
// Paper end // Paper end
@@ -210,12 +227,12 @@ public class RegionFileStorage implements AutoCloseable { @@ -210,12 +237,12 @@ public class RegionFileStorage implements AutoCloseable {
if (this.isChunkData) { if (this.isChunkData) {
ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound); ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound);
if (!chunkPos.equals(pos)) { if (!chunkPos.equals(pos)) {
@@ -850,7 +925,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
return null; return null;
} }
} }
@@ -249,13 +266,13 @@ public class RegionFileStorage implements AutoCloseable { @@ -249,13 +276,13 @@ public class RegionFileStorage implements AutoCloseable {
return nbttagcompound; return nbttagcompound;
} finally { // Paper start } finally { // Paper start
@@ -866,7 +941,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
if (regionfile == null) { if (regionfile == null) {
return; return;
} }
@@ -285,7 +302,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -285,7 +312,7 @@ public class RegionFileStorage implements AutoCloseable {
} }
protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
@@ -875,7 +950,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
if (nbt == null && regionfile == null) { if (nbt == null && regionfile == null) {
return; return;
} }
@@ -335,7 +352,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -335,7 +362,7 @@ public class RegionFileStorage implements AutoCloseable {
} }
// Paper end // Paper end
} finally { // Paper start } finally { // Paper start
@@ -884,7 +959,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
} // Paper end } // Paper end
} }
@@ -344,7 +361,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -344,7 +371,7 @@ public class RegionFileStorage implements AutoCloseable {
ObjectIterator objectiterator = this.regionCache.values().iterator(); ObjectIterator objectiterator = this.regionCache.values().iterator();
while (objectiterator.hasNext()) { while (objectiterator.hasNext()) {
@@ -893,7 +968,7 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
try { try {
regionfile.close(); regionfile.close();
@@ -360,7 +377,7 @@ public class RegionFileStorage implements AutoCloseable { @@ -360,7 +387,7 @@ public class RegionFileStorage implements AutoCloseable {
ObjectIterator objectiterator = this.regionCache.values().iterator(); ObjectIterator objectiterator = this.regionCache.values().iterator();
while (objectiterator.hasNext()) { while (objectiterator.hasNext()) {
@@ -902,8 +977,23 @@ index bd502ca721de0cab438d995efa00ad0554c0d2fe..37242c6225795271e0ba6a853252f2da
regionfile.flush(); regionfile.flush();
} }
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
index d783072bc964e45c308197e6f79874eb4a09f871..f335bb86031c4efbc88f44d542eefcc6815cd2b7 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
@@ -47,8 +47,8 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
public final RegistryAccess registryAccess; // Paper - rewrite chunk system
protected final LevelHeightAccessor levelHeightAccessor;
- public SectionStorage(Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) {
- super(path, dsync); // Paper - remove mojang I/O thread
+ public SectionStorage(String format, int linearCompression, int linearInternalCompression, Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) { // Kaiiju
+ super(format, linearCompression, linearInternalCompression, path, dsync); // Paper - remove mojang I/O thread // Kaiiju
this.codec = codecFactory;
this.factory = factory;
this.fixerUpper = dataFixer;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index b17bc6482d2bd97d2e48d3967dea72605cf13164..2a13629ffb60dc60706da446e6dc7f3683d0410b 100644 index 6a327616cd590b70170f8441c003a2109640201d..2ef0a41fd9ee60bc0866cf5c678498c68250689c 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -552,7 +552,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -552,7 +552,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {

View File

@@ -5,16 +5,15 @@ Subject: [PATCH] Kaiiju Lobotomize Configuration
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
index dd4c3ca77acb3aeefc69b8eb948b8b202ff87a19..ac4440f8d2bd30e3e074ef797d5138b64996fcbb 100644 index 1b180af49adee16c2d8305d01cf213322c4d721b..daa81b36696e82ba7bbd6eefd746362d7c2ba2f1 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java --- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java +++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
@@ -122,4 +122,7 @@ public class KaiijuWorldConfig { @@ -150,4 +150,7 @@ public class KaiijuWorldConfig {
final Map<String, Object> value = getMap("world-settings." + worldName + "." + path, null); regionFormatLinearCompressionLevel = 1;
return value.isEmpty() ? fallback : value; }
} }
-}
\ No newline at end of file
+ +
+ private void lobotomizeSettings() { + private void lobotomizeSettings() {
+ } + }
+} }
\ No newline at end of file

View File

@@ -7,11 +7,11 @@ Inspired by "Lobotomized animals" by @KioProject123
Checks might be a nuisance to performance. Checks might be a nuisance to performance.
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
index ac4440f8d2bd30e3e074ef797d5138b64996fcbb..d28f05943ef25aad1d5a0d4d3f72b991a3caaa5f 100644 index daa81b36696e82ba7bbd6eefd746362d7c2ba2f1..f4af17136437cff7052827b027e3d2a75801b6eb 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java --- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java +++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
@@ -123,6 +123,17 @@ public class KaiijuWorldConfig { @@ -151,6 +151,17 @@ public class KaiijuWorldConfig {
return value.isEmpty() ? fallback : value; }
} }
+ public boolean lobotomizeAnimalEnabled = false; + public boolean lobotomizeAnimalEnabled = false;
@@ -28,6 +28,7 @@ index ac4440f8d2bd30e3e074ef797d5138b64996fcbb..d28f05943ef25aad1d5a0d4d3f72b991
+ lobotomizeAnimalFloat = getBoolean("lobotomize.animal.float", lobotomizeAnimalFloat); + lobotomizeAnimalFloat = getBoolean("lobotomize.animal.float", lobotomizeAnimalFloat);
} }
} }
\ No newline at end of file
diff --git a/src/main/java/dev/kaiijumc/kaiiju/entity/Lobotomized.java b/src/main/java/dev/kaiijumc/kaiiju/entity/Lobotomized.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/entity/Lobotomized.java b/src/main/java/dev/kaiijumc/kaiiju/entity/Lobotomized.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..805df3e27cfbbdf3525c96942afca12d50abc350 index 0000000000000000000000000000000000000000..805df3e27cfbbdf3525c96942afca12d50abc350

View File

@@ -5,34 +5,39 @@ Subject: [PATCH] Kaiiju Lobotomize Villager
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
index d28f05943ef25aad1d5a0d4d3f72b991a3caaa5f..91034f553193381c470544ff068d4d7cfb82cc50 100644 index f4af17136437cff7052827b027e3d2a75801b6eb..fc715266abdd604bf6c2403b758dcd22440adcbe 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java --- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java +++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
@@ -128,6 +128,11 @@ public class KaiijuWorldConfig { @@ -156,6 +156,13 @@ public class KaiijuWorldConfig {
public boolean lobotomizeAnimalCheckCanJump = true; public boolean lobotomizeAnimalCheckCanJump = true;
public boolean lobotomizeAnimalLookAtPlayer = false; public boolean lobotomizeAnimalLookAtPlayer = false;
public boolean lobotomizeAnimalFloat = true; public boolean lobotomizeAnimalFloat = true;
+ public boolean lobotomizeVillagerEnabled = false; + public boolean lobotomizeVillagerEnabled = false;
+ public int lobotomizeVillagerCheckInterval = 100; + public int lobotomizeVillagerCheckInterval = 100;
+ public boolean lobotomizeVillagerDoRaids = true;
+ public boolean lobotomizeVillagerCheckCanJump = true; + public boolean lobotomizeVillagerCheckCanJump = true;
+ public boolean lobotomizeVillagerCheckOnBed = true; + public boolean lobotomizeVillagerCheckOnBed = true;
+ public boolean lobotomizeVillagerCheckActionBlock = true; + public boolean lobotomizeVillagerCheckJobSite = true;
+ public boolean lobotomizeVillagerCheckBedNearby = true;
private void lobotomizeSettings() { private void lobotomizeSettings() {
lobotomizeAnimalEnabled = getBoolean("lobotomize.animal.enabled", lobotomizeAnimalEnabled); lobotomizeAnimalEnabled = getBoolean("lobotomize.animal.enabled", lobotomizeAnimalEnabled);
@@ -135,5 +140,10 @@ public class KaiijuWorldConfig { @@ -163,5 +170,12 @@ public class KaiijuWorldConfig {
lobotomizeAnimalCheckCanJump = getBoolean("lobotomize.animal.check-can-jump", lobotomizeAnimalCheckCanJump); lobotomizeAnimalCheckCanJump = getBoolean("lobotomize.animal.check-can-jump", lobotomizeAnimalCheckCanJump);
lobotomizeAnimalLookAtPlayer = getBoolean("lobotomize.animal.look-at-player", lobotomizeAnimalLookAtPlayer); lobotomizeAnimalLookAtPlayer = getBoolean("lobotomize.animal.look-at-player", lobotomizeAnimalLookAtPlayer);
lobotomizeAnimalFloat = getBoolean("lobotomize.animal.float", lobotomizeAnimalFloat); lobotomizeAnimalFloat = getBoolean("lobotomize.animal.float", lobotomizeAnimalFloat);
+ lobotomizeVillagerEnabled = getBoolean("lobotomize.villager.enabled", lobotomizeVillagerEnabled); + lobotomizeVillagerEnabled = getBoolean("lobotomize.villager.enabled", lobotomizeVillagerEnabled);
+ lobotomizeVillagerDoRaids = getBoolean("lobotomize.villager.do-raids", lobotomizeVillagerDoRaids);
+ lobotomizeVillagerCheckInterval = getInt("lobotomize.villager.check-interval", lobotomizeVillagerCheckInterval); + lobotomizeVillagerCheckInterval = getInt("lobotomize.villager.check-interval", lobotomizeVillagerCheckInterval);
+ lobotomizeVillagerCheckCanJump = getBoolean("lobotomize.villager.check-can-jump", lobotomizeVillagerCheckCanJump); + lobotomizeVillagerCheckCanJump = getBoolean("lobotomize.villager.check-can-jump", lobotomizeVillagerCheckCanJump);
+ lobotomizeVillagerCheckOnBed = getBoolean("lobotomize.villager.check-on-bed", lobotomizeVillagerCheckOnBed); + lobotomizeVillagerCheckOnBed = getBoolean("lobotomize.villager.check-on-bed", lobotomizeVillagerCheckOnBed);
+ lobotomizeVillagerCheckActionBlock = getBoolean("lobotomize.villager.check-action-block", lobotomizeVillagerCheckActionBlock); + lobotomizeVillagerCheckJobSite = getBoolean("lobotomize.villager.check-job-site", lobotomizeVillagerCheckJobSite);
+ lobotomizeVillagerCheckBedNearby = getBoolean("lobotomize.villager.check-bed-nearby", lobotomizeVillagerCheckBedNearby);
} }
} }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04ec927b79 100644 index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..f1a66bda9949eff5f8e420d28d23f47aec3d4587 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -200,14 +200,14 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -200,14 +200,14 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@@ -53,7 +58,7 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
if (this.isLobotomized) { if (this.isLobotomized) {
this.notLobotomizedCount = 0; this.notLobotomizedCount = 0;
@@ -219,9 +219,76 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -219,9 +219,80 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
} }
private boolean canTravelFrom(BlockPos pos) { private boolean canTravelFrom(BlockPos pos) {
@@ -84,7 +89,8 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
+ if (bottom == null) return false; + if (bottom == null) return false;
+ net.minecraft.world.level.block.Block bottomBlock = bottom.getBlock(); + net.minecraft.world.level.block.Block bottomBlock = bottom.getBlock();
+ if (isTallBlock(bottomBlock)) return false; + if (isTallBlock(bottomBlock)) return false;
+ if (this.level.kaiijuConfig.lobotomizeVillagerCheckActionBlock && isInteractiveBlock(bottomBlock, this.getVillagerData().getProfession())) return true; + if (this.level.kaiijuConfig.lobotomizeVillagerCheckBedNearby && isBed(bottomBlock)) return true;
+ if (this.level.kaiijuConfig.lobotomizeVillagerCheckJobSite && isInteractiveJobSite(bottomBlock, this.getVillagerData().getProfession())) return true;
+ // If he can't interact, check if he can travel + // If he can't interact, check if he can travel
+ if (!bottom.isPathfindable(level, pos, net.minecraft.world.level.pathfinder.PathComputationType.LAND)) return false; + if (!bottom.isPathfindable(level, pos, net.minecraft.world.level.pathfinder.PathComputationType.LAND)) return false;
+ if (top == null) top = this.level.getBlockState(pos.above()); + if (top == null) top = this.level.getBlockState(pos.above());
@@ -100,12 +106,15 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
+ private boolean isOnBed() { + private boolean isOnBed() {
+ BlockPos pos = new BlockPos(getX(), getY() - 0.5D, getZ()); + BlockPos pos = new BlockPos(getX(), getY() - 0.5D, getZ());
+ net.minecraft.world.level.block.Block below = this.level.getBlockIfLoaded(pos); + net.minecraft.world.level.block.Block below = this.level.getBlockIfLoaded(pos);
+ return below instanceof net.minecraft.world.level.block.BedBlock; + return isBed(below);
+ } + }
+ +
+ private static boolean isInteractiveBlock(net.minecraft.world.level.block.Block block, VillagerProfession profession) { + private static boolean isBed(net.minecraft.world.level.block.Block block) {
+ if (block instanceof net.minecraft.world.level.block.BedBlock) return true; + return block instanceof net.minecraft.world.level.block.BedBlock;
+ if (profession == VillagerProfession.NITWIT) return false; + }
+
+ private boolean isInteractiveJobSite(net.minecraft.world.level.block.Block block, VillagerProfession profession) {
+ if (this.lastTradedPlayer == null) return false;
+ return (block instanceof net.minecraft.world.level.block.BlastFurnaceBlock && profession != VillagerProfession.ARMORER) || + return (block instanceof net.minecraft.world.level.block.BlastFurnaceBlock && profession != VillagerProfession.ARMORER) ||
+ (block instanceof net.minecraft.world.level.block.SmokerBlock && profession != VillagerProfession.BUTCHER) || + (block instanceof net.minecraft.world.level.block.SmokerBlock && profession != VillagerProfession.BUTCHER) ||
+ (block instanceof net.minecraft.world.level.block.CartographyTableBlock && profession != VillagerProfession.CARTOGRAPHER) || + (block instanceof net.minecraft.world.level.block.CartographyTableBlock && profession != VillagerProfession.CARTOGRAPHER) ||
@@ -131,7 +140,7 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
private boolean canTravelTo(BlockPos pos) { private boolean canTravelTo(BlockPos pos) {
net.minecraft.world.level.block.state.BlockState state = this.level.getBlockStateIfLoaded(pos); net.minecraft.world.level.block.state.BlockState state = this.level.getBlockStateIfLoaded(pos);
if (state == null) { if (state == null) {
@@ -337,7 +404,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -337,7 +408,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
protected void mobTick(boolean inactive) { protected void mobTick(boolean inactive) {
//this.level.getProfiler().push("villagerBrain"); // Purpur //this.level.getProfiler().push("villagerBrain"); // Purpur
// Purpur start // Purpur start
@@ -140,7 +149,16 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
// treat as inactive if lobotomized // treat as inactive if lobotomized
inactive = inactive || checkLobotomized(); inactive = inactive || checkLobotomized();
} else { } else {
@@ -647,6 +714,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -380,7 +451,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
this.lastTradedPlayer = null;
}
- if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper
+ if ((!inactive || (this.level.kaiijuConfig.lobotomizeVillagerDoRaids && this.isLobotomized)) && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper // Kaiiju
Raid raid = ((ServerLevel) this.level).getRaidAt(this.blockPosition());
if (raid != null && raid.isActive() && !raid.isOver()) {
@@ -647,6 +718,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
if (this.assignProfessionWhenSpawned) { if (this.assignProfessionWhenSpawned) {
nbt.putBoolean("AssignProfessionWhenSpawned", true); nbt.putBoolean("AssignProfessionWhenSpawned", true);
} }
@@ -148,7 +166,7 @@ index aed1d9ccffe471b6c2a1d52d2d3d097f6431318b..0227e8d4f810c6fb90779cb3d257ca04
} }
@@ -687,6 +755,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -687,6 +759,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
if (nbt.contains("AssignProfessionWhenSpawned")) { if (nbt.contains("AssignProfessionWhenSpawned")) {
this.assignProfessionWhenSpawned = nbt.getBoolean("AssignProfessionWhenSpawned"); this.assignProfessionWhenSpawned = nbt.getBoolean("AssignProfessionWhenSpawned");
} }

View File

@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
Date: Thu, 16 Feb 2023 01:38:59 +0200
Subject: [PATCH] Kaiiju Network Configuration
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 7da7e0aeb5eac9ac73a3570e716f1ceb11fd7027..2791fe6cc78cc13d969a903134c08e992a6ecdca 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -192,4 +192,7 @@ public class KaiijuConfig {
}
return builder.build();
}
+
+ private static void networkSettings() {
+ }
}

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
Date: Thu, 16 Feb 2023 01:49:54 +0200
Subject: [PATCH] Purpur Network Send Null Entity Packets
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 2791fe6cc78cc13d969a903134c08e992a6ecdca..276c0e2936dfd3ca752deb65c80565c477f65e7f 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -193,6 +193,8 @@ public class KaiijuConfig {
return builder.build();
}
+ public static boolean sendNullEntityPackets = true;
private static void networkSettings() {
+ sendNullEntityPackets = getBoolean("network.send-null-entity-packets", sendNullEntityPackets);
}
}
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 0f9a3a6c05fee59c29764f0c0d7a6cb8a2a861b1..9d0a52bf600583ecbf80c2233a01ff43e609266f 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -186,6 +186,11 @@ public class ServerEntity {
this.teleportDelay = 0;
packet1 = new ClientboundTeleportEntityPacket(this.entity);
}
+ // Kaiiju start - Don't send null move entity packets
+ if (!dev.kaiijumc.kaiiju.KaiijuConfig.sendNullEntityPackets && isNullMovePacket(packet1)) {
+ packet1 = null;
+ }
+ // Kaiiju end
}
if ((this.trackDelta || this.entity.hasImpulse || this.entity instanceof LivingEntity && ((LivingEntity) this.entity).isFallFlying()) && this.tickCount > 0) {
@@ -252,6 +257,20 @@ public class ServerEntity {
}
+ // Kaiiju start - Don't send null move entity packets
+ private boolean isNullMovePacket(Packet<?> packet) {
+ if (packet instanceof ClientboundMoveEntityPacket move) {
+ if (packet instanceof ClientboundMoveEntityPacket.Pos)
+ return move.getXa() == 0 && move.getYa() == 0 && move.getZa() == 0;
+ if (packet instanceof ClientboundMoveEntityPacket.PosRot)
+ return move.getXa() == 0 && move.getYa() == 0 && move.getZa() == 0 && move.getyRot() == 0 && move.getxRot() == 0;
+ if (packet instanceof ClientboundMoveEntityPacket.Rot)
+ return move.getyRot() == 0 && move.getxRot() == 0;
+ }
+ return false;
+ }
+ // Kaiiju end
+
public void removePairing(ServerPlayer player) {
this.entity.stopSeenByPlayer(player);
player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()}));

View File

@@ -0,0 +1,20 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
Date: Thu, 16 Feb 2023 21:28:49 +0200
Subject: [PATCH] Kaiiju Lithium Configuration
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 276c0e2936dfd3ca752deb65c80565c477f65e7f..98c11996a4f052e4e8f1b2782e214817a7999677 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -197,4 +197,9 @@ public class KaiijuConfig {
private static void networkSettings() {
sendNullEntityPackets = getBoolean("network.send-null-entity-packets", sendNullEntityPackets);
}
+
+ public static boolean lithiumEnable = true;
+ private static void lithiumSettings() {
+ lithiumEnable = getBoolean("lithium.enable", lithiumEnable);
+ }
}

View File

@@ -0,0 +1,125 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
Date: Thu, 16 Feb 2023 21:34:37 +0200
Subject: [PATCH] Lithium Math FastUtil
Author: JellySquid
Licence: LGPL-3.0
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 98c11996a4f052e4e8f1b2782e214817a7999677..259f7bdca1b9f59dd148492f8f8fe7dc959e55d9 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -199,7 +199,9 @@ public class KaiijuConfig {
}
public static boolean lithiumEnable = true;
+ public static boolean lithiumMathFastUtil = true;
private static void lithiumSettings() {
lithiumEnable = getBoolean("lithium.enable", lithiumEnable);
+ lithiumMathFastUtil = getBoolean("lithium.math.fast-util", lithiumMathFastUtil) && lithiumEnable;
}
}
diff --git a/src/main/java/net/minecraft/core/AxisCycle.java b/src/main/java/net/minecraft/core/AxisCycle.java
index b5d8a60dc78a76c0a55bfc30cc49d26857bd914a..dd8d98acf21bb676e86f9befb45fd09e1b14a01d 100644
--- a/src/main/java/net/minecraft/core/AxisCycle.java
+++ b/src/main/java/net/minecraft/core/AxisCycle.java
@@ -35,6 +35,18 @@ public enum AxisCycle {
@Override
public Direction.Axis cycle(Direction.Axis axis) {
+ // Kaiiju start - Lithium
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil){
+ switch (axis.ordinal()) {
+ case 0: //X
+ return Direction.Axis.Y;
+ case 1: //Y
+ return Direction.Axis.Z;
+ case 2: //Z
+ return Direction.Axis.X;
+ }
+ }
+ // Kaiiju end
return AXIS_VALUES[Math.floorMod(axis.ordinal() + 1, 3)];
}
@@ -56,6 +68,18 @@ public enum AxisCycle {
@Override
public Direction.Axis cycle(Direction.Axis axis) {
+ // Kaiiju start - Lithium
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil){
+ switch (axis.ordinal()) {
+ case 0: //X
+ return Direction.Axis.Z;
+ case 1: //Y
+ return Direction.Axis.X;
+ case 2: //Z
+ return Direction.Axis.Y;
+ }
+ }
+ // Kaiiju end
return AXIS_VALUES[Math.floorMod(axis.ordinal() - 1, 3)];
}
diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java
index a4dc96b1a3bf309584657e3a1e7dfaea967f9425..09c1989dc3b12d9488b8869e71f2a4890656cc36 100644
--- a/src/main/java/net/minecraft/core/Direction.java
+++ b/src/main/java/net/minecraft/core/Direction.java
@@ -191,6 +191,7 @@ public enum Direction implements StringRepresentable {
}
public Direction getOpposite() {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil) return VALUES[this.oppositeIndex]; // Kaiiju
return from3DDataValue(this.oppositeIndex);
}
@@ -453,6 +454,7 @@ public enum Direction implements StringRepresentable {
}
public static Direction getRandom(RandomSource random) {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil) return VALUES[random.nextInt(VALUES.length)]; // Kaiiju
return Util.getRandom(VALUES, random);
}
diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java
index cfb2e46b34b2982d6724f18214557fc80cf4adfa..4fae201f57dc23ed0e25f17739f97133a7f7534c 100644
--- a/src/main/java/net/minecraft/world/phys/AABB.java
+++ b/src/main/java/net/minecraft/world/phys/AABB.java
@@ -81,10 +81,36 @@ public class AABB {
}
public double min(Direction.Axis axis) {
+ // Kaiiju start - Lithium
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil){
+ switch (axis.ordinal()) {
+ case 0: //X
+ return this.minX;
+ case 1: //Y
+ return this.minY;
+ case 2: //Z
+ return this.minZ;
+ }
+ throw new IllegalArgumentException();
+ }
+ // Kaiiju end
return axis.choose(this.minX, this.minY, this.minZ);
}
public double max(Direction.Axis axis) {
+ // Kaiiju start - Lithium
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathFastUtil){
+ switch (axis.ordinal()) {
+ case 0: //X
+ return this.maxX;
+ case 1: //Y
+ return this.maxY;
+ case 2: //Z
+ return this.maxZ;
+ }
+ throw new IllegalArgumentException();
+ }
+ // Kaiiju end
return axis.choose(this.maxX, this.maxY, this.maxZ);
}

View File

@@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
Date: Fri, 17 Feb 2023 00:34:31 +0200
Subject: [PATCH] Lithium Math SineLut
Author: JellySquid
Licence: LGPL-3.0
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
index 259f7bdca1b9f59dd148492f8f8fe7dc959e55d9..a4f9f31941ddd119dca74f3e23bf8507ee4b7369 100644
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
@@ -200,8 +200,10 @@ public class KaiijuConfig {
public static boolean lithiumEnable = true;
public static boolean lithiumMathFastUtil = true;
+ public static boolean lithiumMathSineLut = true;
private static void lithiumSettings() {
lithiumEnable = getBoolean("lithium.enable", lithiumEnable);
lithiumMathFastUtil = getBoolean("lithium.math.fast-util", lithiumMathFastUtil) && lithiumEnable;
+ lithiumMathSineLut = getBoolean("lithium.math.sine-lut", lithiumMathSineLut) && lithiumEnable;
}
}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java b/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccb45e94ea6d1a627df786fb88baec7edd1f2427
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java
@@ -0,0 +1,90 @@
+package me.jellysquid.mods.lithium.common.util.math;
+
+import net.minecraft.util.Mth;
+
+/**
+ * A replacement for the sine angle lookup table used in {@link MathHelper}, both reducing the size of LUT and improving
+ * the access patterns for common paired sin/cos operations.
+ *
+ * sin(-x) = -sin(x)
+ * ... to eliminate negative angles from the LUT.
+ *
+ * sin(x) = sin(pi/2 - x)
+ * ... to eliminate supplementary angles from the LUT.
+ *
+ * Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling
+ * it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been
+ * tightly optimized to avoid branching where possible and to use very quick integer operations.
+ *
+ * Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend
+ * extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends
+ * up being slower than vanilla when the lookup table is able to be kept in cache memory.
+ *
+ * Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those
+ * from {@link MathHelper}. Validation is performed during runtime to ensure that the table is correct.
+ *
+ * @author coderbot16 Author of the original (and very clever) implementation in Rust:
+ * https://gitlab.com/coderbot16/i73/-/tree/master/i73-trig/src
+ * @author jellysquid3 Additional optimizations, port to Java
+ */
+public class CompactSineLUT {
+ private static final int[] SINE_TABLE_INT = new int[16384 + 1];
+ private static final float SINE_TABLE_MIDPOINT;
+
+ static {
+ final float[] SINE_TABLE = Mth.getSinTable();
+ // Copy the sine table, covering to raw int bits
+ for (int i = 0; i < SINE_TABLE_INT.length; i++) {
+ SINE_TABLE_INT[i] = Float.floatToRawIntBits(SINE_TABLE[i]);
+ }
+
+ SINE_TABLE_MIDPOINT = SINE_TABLE[SINE_TABLE.length / 2];
+
+ // Test that the lookup table is correct during runtime
+ for (int i = 0; i < SINE_TABLE.length; i++) {
+ float expected = SINE_TABLE[i];
+ float value = lookup(i);
+
+ if (expected != value) {
+ throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value));
+ }
+ }
+ }
+
+ // [VanillaCopy] MathHelper#sin(float)
+ public static float sin(float f) {
+ return lookup((int) (f * 10430.378f) & 0xFFFF);
+ }
+
+ // [VanillaCopy] MathHelper#cos(float)
+ public static float cos(float f) {
+ return lookup((int) (f * 10430.378f + 16384.0f) & 0xFFFF);
+ }
+
+ private static float lookup(int index) {
+ // A special case... Is there some way to eliminate this?
+ if (index == 32768) {
+ return SINE_TABLE_MIDPOINT;
+ }
+
+ // Trigonometric identity: sin(-x) = -sin(x)
+ // Given a domain of 0 <= x <= 2*pi, just negate the value if x > pi.
+ // This allows the sin table size to be halved.
+ int neg = (index & 0x8000) << 16;
+
+ // All bits set if (pi/2 <= x), none set otherwise
+ // Extracts the 15th bit from 'half'
+ int mask = (index << 17) >> 31;
+
+ // Trigonometric identity: sin(x) = sin(pi/2 - x)
+ int pos = (0x8001 & mask) + (index ^ mask);
+
+ // Wrap the position in the table. Moving this down to immediately before the array access
+ // seems to help the Hotspot compiler optimize the bit math better.
+ pos &= 0x7fff;
+
+ // Fetch the corresponding value from the LUT and invert the sign bit as needed
+ // This directly manipulate the sign bit on the float bits to simplify logic
+ return Float.intBitsToFloat(SINE_TABLE_INT[pos] ^ neg);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/util/Mth.java b/src/main/java/net/minecraft/util/Mth.java
index 618f19d70a61062ed5989ec6cf0c036f2e047466..dd320f3a3f2b51a723a2fcc65d477a22c0901455 100644
--- a/src/main/java/net/minecraft/util/Mth.java
+++ b/src/main/java/net/minecraft/util/Mth.java
@@ -45,11 +45,19 @@ public class Mth {
return (float)((int)(value * f)) / f;
}
+ // Kaiiju start
+ public static float[] getSinTable() {
+ return SIN;
+ }
+ // Kaiiju end
+
public static float sin(float value) {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathSineLut) return me.jellysquid.mods.lithium.common.util.math.CompactSineLUT.sin(value); // Kaiiju
return SIN[(int)(value * 10430.378F) & '\uffff'];
}
public static float cos(float value) {
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathSineLut) return me.jellysquid.mods.lithium.common.util.math.CompactSineLUT.cos(value); // Kaiiju
return SIN[(int)(value * 10430.378F + 16384.0F) & '\uffff'];
}