diff --git a/README.md b/README.md index 7af441410..a94f373ff 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,6 @@ Contributing * Feel free to open an [Issue](https://github.com/Akarin-project/akarin/issues) if you have any problem with Akarin. * [Pull Request](https://github.com/Akarin-project/akarin/pulls) is welcomed, Akarin use [Mixin](https://github.com/SpongePowered/Mixin) to modify the code, you can checkout `sources` folder to see them. Moreover, add your name to the [LICENSE](https://github.com/Akarin-project/Akarin/blob/master/LICENSE.md) if you want to publish your code under the [MIT License](https://github.com/Akarin-project/Akarin/blob/master/licenses/MIT.md). * If you want to join the [Akarin-project](https://github.com/Akarin-project) team, you can send an email to `kira@kira.moe` with your experience and necessary information. Besides, welcome to join our [TIM Group](https://jq.qq.com/?_wv=1027&k=59q2kV4) to chat *(Chinese)*. -* Note that you need add `work/Paper/Paper-Server` to the `Build Path` of your IDE manually to organize the *NMS* import, the raw *NMS* dependency was dragged to the `Paper-Parent` project. +* Note that you need add `work/Paper/Paper-Server` to the `Build Path` of your IDE manually to organize the *NMS* imports, the raw *NMS* dependency was dragged to the `Paper-Parent` project. ![Akarin project](https://i.loli.net/2018/05/13/5af7fbbfbcddf.png) \ No newline at end of file diff --git a/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java index 92ca12b19..a44ecac9e 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java @@ -4,7 +4,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.akarin.api.LogWrapper; import net.minecraft.server.BiomeBase; import net.minecraft.server.Block; import net.minecraft.server.BlockFire; @@ -31,111 +29,114 @@ public class ParallelRegistry { private static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Parallel Registry Thread - %1$d").build(); /** - * Registry order: SoundEffect -> Block -> BlockFire -> Item -> PotionBrewer -> BiomeBase + * Registry order: SoundEffect -> Block */ - private static final ExecutorService STAGE_A = Executors.newSingleThreadExecutor(STAGE_FACTORY); // TODO go deeper! + private static final ExecutorService STAGE_BLOCK = Executors.newSingleThreadExecutor(STAGE_FACTORY); /** - * Registry order: MobEffectList -> PotionRegistry + * Registry order: Item -> PotionBrewer & orderless: BlockFire, BiomeBase (After STAGE_BLOCK) */ - private static final ExecutorService STAGE_B = Executors.newSingleThreadExecutor(STAGE_FACTORY); + private static final ExecutorService STAGE_BLOCK_BASE = Executors.newWorkStealingPool(3); + /** - * Registry order: Enchantment -> EntityTypes + * Registry order: MobEffectList -> PotionRegistry & orderless: Enchantment, EntityTypes */ - private static final ExecutorService STAGE_C = Executors.newSingleThreadExecutor(STAGE_FACTORY); + private static final ExecutorService STAGE_STANDALONE = Executors.newWorkStealingPool(3); - private static final int TERMINATION_IN_SEC = 30; + private static final int TERMINATION_IN_SEC = 30; // TODO configurable + // We've kept the original order in codes thought we use parallel @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/SoundEffect.b()V" )) private static void soundEffect() { - STAGE_A.execute(() -> SoundEffect.b()); + STAGE_BLOCK.execute(() -> { + SoundEffect.b(); + Block.w(); + + STAGE_BLOCK_BASE.execute(() -> BlockFire.e()); // This single task only cost 4ms, however, firing a task only takes 1ms + STAGE_BLOCK_BASE.execute(() -> { + Item.t(); + PotionBrewer.a(); + }); + STAGE_BLOCK_BASE.execute(() -> BiomeBase.q()); + }); } @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/Block.w()V" )) - private static void block() { - STAGE_A.execute(() -> Block.w()); - } + private static void block() {} // STAGE_BLOCK @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/BlockFire.e()V" )) - private static void blockFire() { - STAGE_A.execute(() -> BlockFire.e()); - } + private static void blockFire() {} // STAGE_BLOCK_BASE @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/MobEffectList.k()V" )) - private static void mobEffectList() { - STAGE_B.execute(() -> MobEffectList.k()); - } + private static void mobEffectList() {} // STAGE_STANDALONE @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/Enchantment.g()V" )) private static void enchantment() { - STAGE_C.execute(() -> Enchantment.g()); + STAGE_STANDALONE.execute(() -> Enchantment.g()); + STAGE_STANDALONE.execute(() -> EntityTypes.c()); + STAGE_STANDALONE.execute(() -> { + MobEffectList.k(); + PotionRegistry.b(); + }); } @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/Item.t()V" )) - private static void item() { - STAGE_A.execute(() -> Item.t()); - } + private static void item() {} // STAGE_BLOCK_BASE - @Redirect(method = "c", at = @At( + @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/PotionRegistry.b()V" )) - private static void potionRegistry() { - STAGE_B.execute(() -> PotionRegistry.b()); - } + private static void potionRegistry() {} // STAGE_STANDALONE - @Redirect(method = "c", at = @At( + @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/PotionBrewer.a()V" )) - private static void potionBrewer() { - STAGE_A.execute(() -> PotionBrewer.a()); - } + private static void potionBrewer() {} // STAGE_BLOCK_BASE - @Redirect(method = "c", at = @At( + @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/EntityTypes.c()V" )) - private static void entityTypes() { - STAGE_C.execute(() -> EntityTypes.c()); - } + private static void entityTypes() {} // STAGE_STANDALONE - @Redirect(method = "c", at = @At( + @Redirect(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/BiomeBase.q()V" )) - private static void biomeBase() { - STAGE_A.execute(() -> BiomeBase.q()); - } + private static void biomeBase() {} // STAGE_BLOCK_BASE - @Inject(method = "c", at = @At( + @Inject(method = "c()V", at = @At( value = "INVOKE", target = "net/minecraft/server/DispenserRegistry.b()V", shift = At.Shift.BEFORE )) private static void await(CallbackInfo info) throws InterruptedException { - STAGE_A.shutdown(); - STAGE_B.shutdown(); - STAGE_C.shutdown(); - STAGE_A.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); - STAGE_B.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); - STAGE_C.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + STAGE_STANDALONE.shutdown(); + STAGE_BLOCK.shutdown(); + + STAGE_STANDALONE.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + STAGE_BLOCK.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + // This must after STAGE_BLOCK terminated + STAGE_BLOCK_BASE.shutdown(); + STAGE_BLOCK_BASE.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); } }