Skip to content

Commit

Permalink
chiyogami-init-commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bea4dev committed Jun 13, 2023
1 parent 6eca47e commit a1c43d5
Show file tree
Hide file tree
Showing 18 changed files with 2,555 additions and 51 deletions.
83 changes: 40 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,40 @@
# ForkTest - A Paper fork, using paperweight

This is an example project, showcasing how to setup a fork of Paper (or any other fork using paperweight), using paperweight.

The files of most interest are
- build.gradle.kts
- settings.gradle.kts
- gradle.properties

When updating upstream, be sure to keep the dependencies noted in `build.gradle.kts` in sync with upstream.
It's also a good idea to use the same version of the Gradle wrapper as upstream.

## Tasks

```
Paperweight tasks
-----------------
applyApiPatches
applyPatches
applyServerPatches
cleanCache - Delete the project setup cache and task outputs.
createMojmapBundlerJar - Build a runnable bundler jar
createMojmapPaperclipJar - Build a runnable paperclip jar
createReobfBundlerJar - Build a runnable bundler jar
createReobfPaperclipJar - Build a runnable paperclip jar
generateDevelopmentBundle
rebuildApiPatches
rebuildPatches
rebuildServerPatches
reobfJar - Re-obfuscate the built jar to obf mappings
runDev - Spin up a non-relocated Mojang-mapped test server
runReobf - Spin up a test server from the reobfJar output jar
runShadow - Spin up a test server from the shadowJar archiveFile
```

## Branches

Each branch of this project represents an example:

- [`main` is the standard example](https://github.com/PaperMC/paperweight-examples/tree/main)
- [`submodules` shows how paperweight can be applied on a fork using the more traditional git submodule system](https://github.com/PaperMC/paperweight-examples/tree/submodules)
- [`mojangapi` shows how a fork could patch arbitrary non-git directories (such as `Paper-MojangAPI`)](https://github.com/PaperMC/paperweight-examples/tree/mojangapi)
- [`submodules-mojang` shows the same as `mojangapi`, but on the git submodules setup from `submodules`](https://github.com/PaperMC/paperweight-examples/tree/submodules-mojangapi)
![chiyogami](https://user-images.githubusercontent.com/34712108/135766838-98102b74-0990-4408-af3d-d576edb0b8fb.png)

Chiyogamiは [Paper](https://github.com/PaperMC/Paper) をフォークしたものであり、Spigotプラグインを動作させつつマルチスレッド実行を可能とするMinecraftサーバーソフトです。

[![Support Server](https://img.shields.io/discord/893173646728757268.svg?label=Discord&logo=Discord&colorB=7289da&style=for-the-badge)](https://discord.com/invite/KKQNAPsFR6)

> [Download](https://github.com/bea4dev/Chiyogami/releases)
Other versions
------
* [1.18.2](https://github.com/bea4dev/Chiyogami/tree/ver/1.18.2)
* [1.19.2](https://github.com/bea4dev/Chiyogami/tree/ver/1.19.2)

Notes
------
- [x] このサーバーは開発段階であるため十分なテストがされていません
- [x] このサーバーを実行する前には必ずワールドデータ等のバックアップをしてください
- [x] issue等のフィードバックを歓迎します

API
------
APIは未公開です

How to build
------

ビルドを実行するには、git, jdk17が必要です。

1. リポジトリを [ダウンロード](https://codeload.github.com/bea4dev/Chiyogami/zip/refs/heads/ver/1.20.1) or clone して解凍します。
2. 解凍したフォルダ内でWindowsの場合はgit-bash、linux or Macの場合はターミナルを開き```./gradlew applyPatches```を実行したあと```./gradlew createReobfBundlerJar```を実行します
3. ```build/libs```内にjarファイルが生成されていれば成功です

For developer
------

このサーバーはワールドにそれぞれ専用のスレッドを割り当て、半ば楽観的に同期を取りつつ動作します。

コマンドやスケジューラー系統の処理はマルチスレッド化した中には含まれていないので互換性を維持し易くなっています。

イベントの発火処理にはデフォルトで排他制御が設けられますが、ワールド間での順序関係は保証されないため注意が必要です。
194 changes: 194 additions & 0 deletions patches/api/0001-chiyogami-init-commit-0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: bea4dev <bea0224@outlook.jp>
Date: Mon, 12 Jun 2023 17:49:25 +0900
Subject: [PATCH] chiyogami-init-commit-0


diff --git a/src/main/java/world/chiyogami/thread/ConcurrentTaskHandler.java b/src/main/java/world/chiyogami/thread/ConcurrentTaskHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb918bd7e4f689f85abd4b8d30f49f71a95ed0ad
--- /dev/null
+++ b/src/main/java/world/chiyogami/thread/ConcurrentTaskHandler.java
@@ -0,0 +1,52 @@
+package world.chiyogami.thread;
+
+import org.bukkit.World;
+import java.util.function.Supplier;
+
+/**
+ * Task utility class for safe operation on worlds from other threads.
+ */
+public abstract class ConcurrentTaskHandler {
+
+ protected static ConcurrentTaskHandler INSTANCE = null;
+
+ /**
+ * Performs tasks to the target world in a thread-safe and non-delayed manner.
+ * <p>
+ * When accessing from a thread other than the main thread. Typically, a latency of 50 ms or less is incurred.
+ * <p>
+ * <b>This method only guarantees thread-safety for operations on worlds,
+ * not for global variables or methods (e.g. Bukkit.createInventory();).</b>
+ *
+ * @param targetWorld The world in which the task is to be performed.
+ * @param task Supplier task.
+ * @return Result of supplier.
+ */
+ public static <T> T runConcurrentTaskForWorld(World targetWorld, Supplier<T> task) {
+ return INSTANCE.runConcurrentTaskForWorldImpl(targetWorld, task);
+ }
+
+ /**
+ * Performs tasks to the target world in a thread-safe and non-delayed manner.
+ * <p>
+ * When accessing from a thread other than the main thread. Typically, a latency of 50 ms or less is incurred.
+ * <p>
+ * <b>This method only guarantees thread-safety for operations on worlds,
+ * not for global variables or methods (e.g. Bukkit.createInventory();).</b>
+ *
+ * @param targetWorld The world in which the task is to be performed.
+ * @param runnable Runnable task.
+ */
+ public static void runConcurrentTaskForWorld(World targetWorld, Runnable runnable) {
+ INSTANCE.runConcurrentTaskForWorldImpl(targetWorld, () -> {
+ runnable.run();
+ return null;
+ });
+ }
+
+
+ protected ConcurrentTaskHandler(){INSTANCE = this;}
+
+ protected abstract <T> T runConcurrentTaskForWorldImpl(World targetWorld, Supplier<T> supplier);
+
+}
diff --git a/src/main/java/world/chiyogami/thread/WorldThreadLockHandler.java b/src/main/java/world/chiyogami/thread/WorldThreadLockHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3c5d30fe0fe3457cb8c533906373a66e00a7508
--- /dev/null
+++ b/src/main/java/world/chiyogami/thread/WorldThreadLockHandler.java
@@ -0,0 +1,14 @@
+package world.chiyogami.thread;
+
+abstract class WorldThreadLockHandler {
+
+ public static WorldThreadLockHandler INSTANCE;
+
+
+ protected WorldThreadLockHandler() {INSTANCE = this;}
+
+ public abstract void lock(WorldThreadSafeLock worldThreadSafeLock);
+
+ public abstract void unlock(WorldThreadSafeLock worldThreadSafeLock);
+
+}
diff --git a/src/main/java/world/chiyogami/thread/WorldThreadRunnable.java b/src/main/java/world/chiyogami/thread/WorldThreadRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..1694e1e7cb34b47a7165910672d04054a310b9ab
--- /dev/null
+++ b/src/main/java/world/chiyogami/thread/WorldThreadRunnable.java
@@ -0,0 +1,53 @@
+package world.chiyogami.thread;
+
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class WorldThreadRunnable implements Runnable {
+
+ private World world = null;
+
+ private long period = 0;
+
+ private long delay = 0;
+
+ private boolean canceled = false;
+
+ private boolean scheduled = false;
+
+ public World getWorld() {return world;}
+
+ public long getPeriod() {return period;}
+
+ public long getDelay() {return delay;}
+
+ public synchronized boolean isCanceled() {return canceled;}
+
+ public synchronized void cancel() {this.canceled = true;}
+
+ public synchronized void runTask(@NotNull World world) {
+ checkScheduled();
+ this.world = world;
+ scheduled = true;
+ world.scheduleTask(this);
+ }
+
+ public synchronized void runTaskLater(@NotNull World world, long delay) {
+ checkScheduled();
+ this.world = world;
+ this.delay = delay;
+ scheduled = true;
+ world.scheduleTask(this, delay);
+ }
+
+ public synchronized void runTaskTimer(@NotNull World world, long delay, long period) {
+ checkScheduled();
+ this.world = world;
+ this.delay = delay;
+ this.period = period;
+ scheduled = true;
+ world.scheduleTask(this, delay, period);
+ }
+
+ private void checkScheduled() {if (scheduled) throw new IllegalStateException("This task is already scheduled.");}
+}
diff --git a/src/main/java/world/chiyogami/thread/WorldThreadSafeLock.java b/src/main/java/world/chiyogami/thread/WorldThreadSafeLock.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6874f7bc6ac933453230307176eaafb6ff67fd0
--- /dev/null
+++ b/src/main/java/world/chiyogami/thread/WorldThreadSafeLock.java
@@ -0,0 +1,45 @@
+package world.chiyogami.thread;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * ReentrantLock for acquiring locks while avoiding deadlocks in the world thread.
+ */
+public class WorldThreadSafeLock extends ReentrantLock {
+
+ public WorldThreadSafeLock(boolean fair) {
+ super(fair);
+ }
+
+ @Override
+ public void lock() {
+ WorldThreadLockHandler.INSTANCE.lock(this);
+ super.lock();
+ }
+
+ @Override
+ public void unlock() {
+ super.unlock();
+ WorldThreadLockHandler.INSTANCE.unlock(this);
+ }
+
+ @Override
+ public boolean tryLock() {
+ boolean already = super.tryLock();
+ if (already) {
+ WorldThreadLockHandler.INSTANCE.lock(this);
+ }
+ return already;
+ }
+
+ @Override
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ boolean already = super.tryLock(timeout, unit);
+ if (already) {
+ WorldThreadLockHandler.INSTANCE.lock(this);
+ }
+ return already;
+ }
+
+}
Loading

0 comments on commit a1c43d5

Please sign in to comment.