diff --git a/.github/workflows/1_18.yml b/.github/workflows/1_18.yml new file mode 100644 index 0000000000..8d7340c4b1 --- /dev/null +++ b/.github/workflows/1_18.yml @@ -0,0 +1,99 @@ +name: 1.18 build check + +on: + push: + branches: + - 1_18 + paths: + - src/** + - build.sbt + - .scalafix.conf + - .scalafmt.conf + - project/* + - .github/workflows/**.yml + - .github/actions/**/**.yml + +jobs: + build_check: + env: + BUILD_ENVIRONMENT_IS_CI_OR_LOCAL: "CI" + runs-on: ubuntu-20.04 + container: ghcr.io/giganticminecraft/seichiassist-builder-v2:424c09f + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Prepare build dependencies cache + uses: actions/cache@v3 + env: + cache-name: cache-build-dependencies + cache-version: v-5 + with: + # sbt等は$HOMEではなくユーザーディレクトリを見ているようで、 + # GH Actionsでの ~ は /github/home/ に展開されるにもかかわらず + # 実際のキャッシュは /root/ 以下に配備される。 + # + # /root/.ivy/cache, /root/.sbt - sbt関連のキャッシュ + # /root/.m2 - ビルドログを観察した感じprotoc等はここを利用する + # /root/.cache - cousierがscalasbt等をキャッシュするのに使っている + path: | + /root/.ivy2/cache + /root/.sbt + /root/.m2 + /root/.cache + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}-${{ hashFiles('**/build.sbt') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}- + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}- + + - name: Prepare build cache + if: github.ref != 'refs/heads/master' + uses: actions/cache@v3 + env: + cache-name: cache-build + cache-version: v-5 + with: + path: | + target + project/target + project/project/target + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}- + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}- + + # CIでのcheckoutはファイルのタイムスタンプをチェックアウト時刻に設定するため、 + # そのままビルドするとlocalDependenciesにあるjarに変更が行われたと見なされ + # 不要なインクリメンタルコンパイルが走る + # タイムスタンプをコミット時刻に設定することでこれが回避できる + - name: Restore localDependencies' timestamps + # 参考: https://qiita.com/tomlla/items/219cea9dd071c8a9e147 + run: | + git config --global --add safe.directory /__w/SeichiAssist/SeichiAssist + for jar in localDependencies/*.jar; do + timestamp=`git log -1 --pretty=format:'%cd' --date=format:'%Y%m%d%H%M.%S' $jar` + touch -t "$timestamp" $jar + done + + # scalapbは.protoの再コンパイルの必要性を判定する際にタイムスタンプを見ているから、コミット時刻に合わせる + - name: Restore protocol timestamps + ## 参考: https://qiita.com/tomlla/items/219cea9dd071c8a9e147 + run: | + for proto in protocol/*.proto; do + timestamp=`git log -1 --pretty=format:'%cd' --date=format:'%Y%m%d%H%M.%S' $proto` + touch -t "$timestamp" $proto + done + + - name: Check format with Scalafmt + run: ./sbt scalafmtCheckAll + + - name: Check lint with Scalafix on push + run: ./sbt "scalafix --check" + + - name: Test and build artifact + run: ./sbt assembly + + - name: Clean build artifact for caching target folder + run: rm -r target/build diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index dbd30c1b0a..6b2409222c 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -5,7 +5,6 @@ on: branches: - develop - master - pull_request: branches: - develop @@ -15,7 +14,7 @@ jobs: env: BUILD_ENVIRONMENT_IS_CI_OR_LOCAL: "CI" runs-on: ubuntu-22.04 - container: ghcr.io/giganticminecraft/seichiassist-builder:1a64049 + container: ghcr.io/giganticminecraft/seichiassist-builder-v2:5357f57 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -68,6 +67,8 @@ jobs: - name: Restore localDependencies' timestamps # 参考: https://qiita.com/tomlla/items/219cea9dd071c8a9e147 run: | + git config --global --add safe.directory /__w/SeichiAssist/SeichiAssist + for jar in localDependencies/*.jar; do timestamp=`git log -1 --pretty=format:'%cd' --date=format:'%Y%m%d%H%M.%S' $jar` touch -t "$timestamp" $jar @@ -125,7 +126,7 @@ jobs: output-sha: name: 最終コミットのSHA値を取得する - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: sha: ${{ steps.output-sha.outputs.sha }} steps: @@ -140,7 +141,7 @@ jobs: create_prerelease: name: GitHub ReleasesにPreReleaseを作成する - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 if: github.ref == 'refs/heads/develop' needs: - build_test_and_upload diff --git a/.github/workflows/create_1_18_release.yml b/.github/workflows/create_1_18_release.yml new file mode 100644 index 0000000000..0525e7565b --- /dev/null +++ b/.github/workflows/create_1_18_release.yml @@ -0,0 +1,106 @@ +name: Create 1.18 release + +on: + pull_request: + paths: + - src/** + - build.sbt + - .scalafix.conf + - .scalafmt.conf + - project/* + - .github/workflows/**.yml + - .github/actions/**/**.yml + +jobs: + create_release: + runs-on: ubuntu-20.04 + container: ghcr.io/giganticminecraft/seichiassist-builder-v2:424c09f + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Prepare build dependencies cache + uses: actions/cache@v3 + env: + cache-name: cache-build-dependencies + cache-version: v-5 + with: + # sbt等は$HOMEではなくユーザーディレクトリを見ているようで、 + # GH Actionsでの ~ は /github/home/ に展開されるにもかかわらず + # 実際のキャッシュは /root/ 以下に配備される。 + # + # /root/.ivy/cache, /root/.sbt - sbt関連のキャッシュ + # /root/.m2 - ビルドログを観察した感じprotoc等はここを利用する + # /root/.cache - cousierがscalasbt等をキャッシュするのに使っている + path: | + /root/.ivy2/cache + /root/.sbt + /root/.m2 + /root/.cache + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}-${{ hashFiles('**/build.sbt') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}- + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}- + + - name: Prepare build cache + if: github.ref != 'refs/heads/master' + uses: actions/cache@v3 + env: + cache-name: cache-build + cache-version: v-5 + with: + path: | + target + project/target + project/project/target + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}-${{ github.ref }}- + ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.cache-version }}- + + # CIでのcheckoutはファイルのタイムスタンプをチェックアウト時刻に設定するため、 + # そのままビルドするとlocalDependenciesにあるjarに変更が行われたと見なされ + # 不要なインクリメンタルコンパイルが走る + # タイムスタンプをコミット時刻に設定することでこれが回避できる + - name: Restore localDependencies' timestamps + # 参考: https://qiita.com/tomlla/items/219cea9dd071c8a9e147 + run: | + git config --global --add safe.directory /__w/SeichiAssist/SeichiAssist + for jar in localDependencies/*.jar; do + timestamp=`git log -1 --pretty=format:'%cd' --date=format:'%Y%m%d%H%M.%S' $jar` + touch -t "$timestamp" $jar + done + + # scalapbは.protoの再コンパイルの必要性を判定する際にタイムスタンプを見ているから、コミット時刻に合わせる + - name: Restore protocol timestamps + ## 参考: https://qiita.com/tomlla/items/219cea9dd071c8a9e147 + run: | + for proto in protocol/*.proto; do + timestamp=`git log -1 --pretty=format:'%cd' --date=format:'%Y%m%d%H%M.%S' $proto` + touch -t "$timestamp" $proto + done + + - name: Build artifact + run: ./sbt assembly + + - name: Create and push a tag + id: tag-name + run: | + TAG_NAME=pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} + git tag $TAG_NAME + git push origin $TAG_NAME + echo "value=$TAG_NAME" >> $GITHUB_OUTPUT + + - name: Create release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: target/build/SeichiAssist.jar + tag_name: ${{ steps.tag-name.outputs.value }} + draft: false + + - name: Clean build artifact for caching target folder + run: rm -r target/build diff --git a/.gitignore b/.gitignore index bade594553..36e104a5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,8 @@ # Local files deployLocal.sh -localDependencies/spigot-1.12.2.jar +localDependencies/spigot-1.18.2.jar +plugins/* # Docker docker/spigot/serverfiles/eula.txt @@ -25,3 +26,6 @@ docker/spigot/serverfiles/eula.txt .metals project/.bloop/ project/metals.sbt + +# scalac に -Yprofile-trace profile.trace を渡しているので、Chrome Trace file が生成される +/profile.trace diff --git a/.java-version b/.java-version new file mode 100644 index 0000000000..03b6389f32 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3dd11365d6..c8df6e1d39 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,18 +2,18 @@ ## 開発を始めるために必要なもの - [IntelliJ IDEA](https://www.jetbrains.com/idea/) などの統合開発環境 -- [JDK 8](https://adoptopenjdk.net/?variant=openjdk8&jvmVariant=hotspot) +- [AdoptOpenJDK 17](https://adoptium.net/temurin/releases/?version=17) - [sbt 1.9](https://www.scala-sbt.org/1.x/docs/Setup.html) - [Scala 2.13](https://www.scala-lang.org/download/) -- Spigot 1.12.2 +- Spigot 1.18.2 - Docker - GitHubのアカウント - Git ### 準備 #### Java Development Kit -最初に、Java Development Kit (JDK) 8をインストールする必要があります。 -[AdoptOpenJDK 1.8](https://adoptopenjdk.net/?variant=openjdk8&jvmVariant=hotspot) のインストールを推奨します。 +最初に、Java Development Kit (JDK) 17をインストールする必要があります。 +[AdoptOpenJDK 17](https://adoptium.net/temurin/releases/?version=17) のインストールを推奨します。 #### 統合開発環境 次に、[IntelliJ IDEA](https://www.jetbrains.com/idea/)などの統合開発環境を導入します。 @@ -152,6 +152,10 @@ IntelliJ IDEAの設定でフォーマットに `scalafmt` を使う #### 手元でデバッグ SeichiAssistは手元でデバッグできる環境を整えています。環境を立ち上げるためには、Dockerが必要です。 +/pluginsディレクトリに対してjarファイル配置すると、そのjarファイルとSeichiAssistを同時に起動した場合の動作を確認することができます。 +整地鯖で利用しているプラグインはGiganticMinecraftのメンバーのみ[MinIOからダウンロード](https://minio-console.onp-k8s.admin.seichi.click/browser/seichi-plugins/ZGViLTEtMTYtNS8=)することができます。 +接続情報などの詳しい情報は、Discordで聞いてください。 + ##### Dockerを立ち上げる Linux環境では、`./prepare-docker.sh`、Windowsでは`prepare-docker.bat`を実行することで @@ -167,7 +171,7 @@ Linux環境では、`./prepare-docker.sh`、Windowsでは`prepare-docker.bat`を サーバーやDB等を停止する場合、 `docker compose down` を実行してください。 -なお、SeichiAssistがJDK 8以外でコンパイルされた場合は、実行時にエラーとなります。必ずJDKのバージョンを揃えるようにしてください。 +なお、SeichiAssistがJava 17未満でコンパイルされた場合は、実行時にエラーとなります。必ずJDKのバージョンを揃えるようにしてください。 ##### デバッグ用環境への接続 diff --git a/README.md b/README.md index 3110aba168..bb68004d2b 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ [![GitHub Actions](https://github.com/GiganticMinecraft/SeichiAssist/actions/workflows/build_and_deploy.yml/badge.svg)](https://github.com/GiganticMinecraft/SeichiAssist/actions/workflows/build_and_deploy.yml) ## 前提プラグイン -- [CoreProtect-2.14.4](https://www.spigotmc.org/resources/coreprotect.8631/download?version=231781) -- [item-nbt-api-plugin-1.8.2-SNAPSHOT](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/download?version=241690) -- [Multiverse-Core-2.5.0](https://dev.bukkit.org/projects/multiverse-core/files/2428161/download) -- [Multiverse-Portals-2.5.0](https://dev.bukkit.org/projects/multiverse-portals/files/2428333/download) +- [CoreProtect-2.15.0](https://www.spigotmc.org/resources/coreprotect.8631/download?version=231781) +- [item-nbt-api-plugin-2.11.2](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/download?version=241690) +- [Multiverse-Core-4.3.1](https://dev.bukkit.org/projects/multiverse-core/files/2428161/download) +- [Multiverse-Portals-4.2.1](https://dev.bukkit.org/projects/multiverse-portals/files/2428333/download) - [ParticleAPI_v2.1.1](https://dl.inventivetalent.org/download/?file=plugin/ParticleAPI_v2.1.1) -- [WorldBorder1.8.7](https://dev.bukkit.org/projects/worldborder/files/2415838/download) -- [worldedit-bukkit-6.1.9](https://dev.bukkit.org/projects/worldedit/files/2597538/download) -- [worldguard-bukkit-6.2.2](https://dev.bukkit.org/projects/worldguard/files/2610618/download) +- [WorldBorder1.9.10 (beta)](https://www.spigotmc.org/resources/worldborder.60905/download?version=275003) +- [worldedit-bukkit-7.0.0](https://dev.bukkit.org/projects/worldedit/files/2597538/download) +- [worldguard-bukkit-7.0.0](https://dev.bukkit.org/projects/worldguard/files/2610618/download) ## 前提プラグイン(整地鯖内製) - RegenWorld [リポジトリ](https://github.com/GiganticMinecraft/RegenWorld) | [jar](https://redmine.seichi.click/attachments/download/890/RegenWorld-1.0.jar) diff --git a/build.sbt b/build.sbt index a570decae3..600b1fb470 100644 --- a/build.sbt +++ b/build.sbt @@ -58,18 +58,24 @@ resolvers ++= Seq( val providedDependencies = Seq( "org.jetbrains" % "annotations" % "24.1.0", - "org.spigotmc" % "spigot-api" % "1.12.2-R0.1-SNAPSHOT", + "org.apache.commons" % "commons-lang3" % "3.12.0", + "commons-codec" % "commons-codec" % "1.16.0", + "org.spigotmc" % "spigot-api" % "1.18.2-R0.1-SNAPSHOT", // https://maven.enginehub.org/repo/com/sk89q/worldedit/worldedit-bukkit/ - "com.sk89q.worldguard" % "worldguard-legacy" % "6.2", - "net.coreprotect" % "coreprotect" % "2.14.2", - "com.mojang" % "authlib" % "1.6.25", + "com.sk89q.worldguard" % "worldguard-bukkit" % "7.0.7", + "net.coreprotect" % "coreprotect" % "21.3", + "com.mojang" % "authlib" % "6.0.52", // no runtime "org.typelevel" %% "simulacrum" % "1.0.1" ).map(_ % "provided") val scalafixCoreDep = - "ch.epfl.scala" %% "scalafix-core" % _root_.scalafix.sbt.BuildInfo.scalafixVersion % ScalafixConfig + "ch.epfl.scala" %% "scalafix-core" % _root_ + .scalafix + .sbt + .BuildInfo + .scalafixVersion % ScalafixConfig val testDependencies = Seq( "org.scalamock" %% "scalamock" % "5.2.0", @@ -84,7 +90,8 @@ val dependenciesToEmbed = Seq( // DB "org.mariadb.jdbc" % "mariadb-java-client" % "3.3.1", - "org.flywaydb" % "flyway-core" % "5.2.4", + "org.flywaydb" % "flyway-core" % "10.2.0", + "org.flywaydb" % "flyway-mysql" % "10.2.0", "org.scalikejdbc" %% "scalikejdbc" % "3.5.0", // redis @@ -101,8 +108,8 @@ val dependenciesToEmbed = Seq( "io.chrisdavenport" %% "cats-effect-time" % "0.1.2", // logging - "org.slf4j" % "slf4j-api" % "1.7.36", - "org.slf4j" % "slf4j-jdk14" % "1.7.36", + "org.slf4j" % "slf4j-api" % "2.0.10", + "org.slf4j" % "slf4j-jdk14" % "2.0.10", "com.typesafe.scala-logging" % "scala-logging-slf4j_2.10" % "2.1.2", // type-safety utils @@ -196,6 +203,8 @@ lazy val root = (project in file(".")).settings( excludeDependencies := Seq(ExclusionRule(organization = "org.bukkit", name = "bukkit")), unmanagedBase := baseDirectory.value / "localDependencies", scalacOptions ++= Seq( + "-Yprofile-trace", + "profile.trace", "-encoding", "utf8", "-unchecked", @@ -208,7 +217,11 @@ lazy val root = (project in file(".")).settings( ), javacOptions ++= Seq("-encoding", "utf8"), assembly / assemblyShadeRules ++= Seq( - ShadeRule.rename("org.mariadb.jdbc.**" -> "com.github.unchama.seichiassist.relocateddependencies.org.mariadb.jdbc.@1").inAll + ShadeRule + .rename( + "org.mariadb.jdbc.**" -> "com.github.unchama.seichiassist.relocateddependencies.org.mariadb.jdbc.@1" + ) + .inAll ), // sbt-assembly 1.0.0からはTestを明示的にタスクツリーに入れる必要がある // cf. https://github.com/sbt/sbt-assembly/pull/432/commits/361224a6202856bc2e572df811d0e6a1f1efda98 diff --git a/compose.yml b/compose.yml index 386425942b..b9306adc4a 100644 --- a/compose.yml +++ b/compose.yml @@ -21,9 +21,9 @@ services: - "25566:25565" - "7091:7091" environment: - - VERSION=1.12.2 + - VERSION=1.18.2 - EULA=TRUE - - TYPE=SPIGOT + - TYPE=PAPER - ONLINE_MODE=FALSE - ENABLE_JMX=true - JMX_PORT=7091 @@ -51,9 +51,9 @@ services: - "25567:25565" - "7092:7091" environment: - - VERSION=1.12.2 + - VERSION=1.18.2 - EULA=TRUE - - TYPE=SPIGOT + - TYPE=PAPER - ONLINE_MODE=FALSE - ENABLE_JMX=true - JMX_PORT=7091 @@ -70,7 +70,7 @@ services: - redis stdin_open: true bungeecord: - image: itzg/bungeecord:java8 + image: itzg/bungeecord:java17 ports: - "25565:25577" volumes: diff --git a/docker/spigot/Dockerfile b/docker/spigot/Dockerfile index 2281dfcbf8..fb243c1db6 100644 --- a/docker/spigot/Dockerfile +++ b/docker/spigot/Dockerfile @@ -1,28 +1,26 @@ # syntax=docker/dockerfile:1.6 -FROM ghcr.io/giganticminecraft/chunk-search-rs:sha-598517c as chunk-search-provider -FROM ghcr.io/giganticminecraft/seichiassist-runner:ba2aa54 +FROM ghcr.io/giganticminecraft/chunk-search-rs:sha-f1943b1 as chunk-search-provider +FROM ghcr.io/giganticminecraft/seichiassist-runner-v2:486225f +FROM mikefarah/yq:4.40.5 as yq -FROM itzg/minecraft-server:java8-multiarch +FROM itzg/minecraft-server:java17-jdk -# JDKとnkfをインストール -RUN apt-get update && apt-get install -y \ - nkf \ - openjdk-8-jdk \ -&& apt-get clean \ -&& rm -rf /var/lib/apt/lists/* +# nkfをインストール +RUN apt-get update && apt-get install -y nkf \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* #yqをインストール -RUN curl -LJO https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 && \ -mv yq_linux_amd64 /usr/local/bin/yq && \ -chmod a+x /usr/local/bin/yq +COPY --from=yq /usr/bin/yq /usr/bin/yq # chunk-search-rsをインストール COPY --link --from=chunk-search-provider /build/chunk-search-rs /usr/bin/chunk-search-rs # プラグインとスクリプトをローカルからコピーする -COPY --link ./localDependencies/ /data/plugins/ COPY --link ./target/build/ /SeichiAssist/ COPY --link ./docker/spigot/ /data/ +ADD ./localDependencies/ /data/plugins/ +ADD ./plugins /plugins RUN chmod a+x /data/update-seichiassist.sh RUN nkf -Lu --overwrite /data/update-seichiassist.sh diff --git a/docker/spigot/spigot.yml b/docker/spigot/spigot.yml new file mode 100644 index 0000000000..ff92ba13da --- /dev/null +++ b/docker/spigot/spigot.yml @@ -0,0 +1,171 @@ +# This is the main configuration file for Spigot. +# As you can see, there's tons to configure. Some options may impact gameplay, so use +# with caution, and make sure you know what each option does before configuring. +# For a reference for any variable inside this file, check out the Spigot wiki at +# http://www.spigotmc.org/wiki/spigot-configuration/ +# +# If you need help with the configuration or have any questions related to Spigot, +# join us at the Discord or drop by our forums and leave a post. +# +# Discord: https://www.spigotmc.org/go/discord +# Forums: http://www.spigotmc.org/ + +messages: + whitelist: You are not whitelisted on this server! + unknown-command: Unknown command. Type "/help" for help. + server-full: The server is full! + outdated-client: Outdated client! Please use {0} + outdated-server: Outdated server! I'm still on {0} + restart: Server is restarting +advancements: + disable-saving: false + disabled: + - minecraft:story/disabled +settings: + sample-count: 12 + bungeecord: true + player-shuffle: 0 + user-cache-size: 1000 + save-user-cache-on-stop-only: false + moved-wrongly-threshold: 0.0625 + moved-too-quickly-multiplier: 10.0 + timeout-time: 60 + restart-on-crash: true + restart-script: ./start.sh + netty-threads: 4 + attribute: + maxHealth: + max: 2048.0 + movementSpeed: + max: 2048.0 + attackDamage: + max: 2048.0 + log-villager-deaths: true + log-named-deaths: true + debug: false +players: + disable-saving: false +commands: + spam-exclusions: + - /skill + silent-commandblock-console: false + replace-commands: + - setblock + - summon + - testforblock + - tellraw + log: true + tab-complete: 0 + send-namespaced: true +config-version: 12 +stats: + disable-saving: false + forced-stats: {} +world-settings: + default: + below-zero-generation-in-existing-chunks: true + verbose: false + merge-radius: + exp: 3.0 + item: 2.5 + growth: + cactus-modifier: 100 + cane-modifier: 100 + melon-modifier: 100 + mushroom-modifier: 100 + pumpkin-modifier: 100 + sapling-modifier: 100 + beetroot-modifier: 100 + carrot-modifier: 100 + potato-modifier: 100 + wheat-modifier: 100 + netherwart-modifier: 100 + vine-modifier: 100 + cocoa-modifier: 100 + bamboo-modifier: 100 + sweetberry-modifier: 100 + kelp-modifier: 100 + twistingvines-modifier: 100 + weepingvines-modifier: 100 + cavevines-modifier: 100 + glowberry-modifier: 100 + entity-activation-range: + animals: 32 + monsters: 32 + raiders: 48 + misc: 16 + water: 16 + villagers: 32 + flying-monsters: 32 + wake-up-inactive: + animals-max-per-tick: 4 + animals-every: 1200 + animals-for: 100 + monsters-max-per-tick: 8 + monsters-every: 400 + monsters-for: 100 + villagers-max-per-tick: 4 + villagers-every: 600 + villagers-for: 100 + flying-monsters-max-per-tick: 8 + flying-monsters-every: 200 + flying-monsters-for: 100 + villagers-work-immunity-after: 100 + villagers-work-immunity-for: 20 + villagers-active-for-panic: true + tick-inactive-villagers: true + ignore-spectators: false + entity-tracking-range: + players: 48 + animals: 48 + monsters: 48 + misc: 32 + other: 64 + ticks-per: + hopper-transfer: 8 + hopper-check: 1 + hopper-amount: 1 + dragon-death-sound-radius: 0 + seed-village: 10387312 + seed-desert: 14357617 + seed-igloo: 14357618 + seed-jungle: 14357619 + seed-swamp: 14357620 + seed-monument: 10387313 + seed-shipwreck: 165745295 + seed-ocean: 14357621 + seed-outpost: 165745296 + seed-endcity: 10387313 + seed-slime: 987234911 + seed-nether: 30084232 + seed-mansion: 10387319 + seed-fossil: 14357921 + seed-portal: 34222645 + seed-stronghold: default + hunger: + jump-walk-exhaustion: 0.05 + jump-sprint-exhaustion: 0.2 + combat-exhaustion: 0.1 + regen-exhaustion: 6.0 + swim-multiplier: 0.01 + sprint-multiplier: 0.1 + other-multiplier: 0.0 + max-tnt-per-tick: 100 + max-tick-time: + tile: 50 + entity: 50 + arrow-despawn-rate: 1200 + trident-despawn-rate: 1200 + hanging-tick-frequency: 100 + view-distance: default + simulation-distance: default + thunder-chance: 100000 + item-despawn-rate: 6000 + enable-zombie-pigmen-portal-spawns: true + nerf-spawner-mobs: false + wither-spawn-sound-radius: 0 + zombie-aggressive-towards-villager: true + mob-spawn-range: 8 + end-portal-sound-radius: 0 + worldeditregentempworld: + verbose: false diff --git a/localDependencies/Multiverse-Core-2.5.0.jar b/localDependencies/Multiverse-Core-2.5.0.jar deleted file mode 100644 index bb694d66ae..0000000000 Binary files a/localDependencies/Multiverse-Core-2.5.0.jar and /dev/null differ diff --git a/localDependencies/Multiverse-Core-4.3.1.jar b/localDependencies/Multiverse-Core-4.3.1.jar new file mode 100644 index 0000000000..09b089552f Binary files /dev/null and b/localDependencies/Multiverse-Core-4.3.1.jar differ diff --git a/localDependencies/Multiverse-Portals-2.5.0.jar b/localDependencies/Multiverse-Portals-2.5.0.jar deleted file mode 100644 index 1527c60b6a..0000000000 Binary files a/localDependencies/Multiverse-Portals-2.5.0.jar and /dev/null differ diff --git a/localDependencies/Multiverse-Portals-4.2.1.jar b/localDependencies/Multiverse-Portals-4.2.1.jar new file mode 100644 index 0000000000..f4ed83cc7c Binary files /dev/null and b/localDependencies/Multiverse-Portals-4.2.1.jar differ diff --git a/localDependencies/WorldBorder.jar b/localDependencies/WorldBorder.jar index a6388760d2..151682c937 100644 Binary files a/localDependencies/WorldBorder.jar and b/localDependencies/WorldBorder.jar differ diff --git a/localDependencies/item-nbt-api-plugin-1.8.2-SNAPSHOT.jar b/localDependencies/item-nbt-api-plugin-1.8.2-SNAPSHOT.jar deleted file mode 100644 index 6c399eab4a..0000000000 Binary files a/localDependencies/item-nbt-api-plugin-1.8.2-SNAPSHOT.jar and /dev/null differ diff --git a/localDependencies/item-nbt-api-plugin-2.11.2.jar b/localDependencies/item-nbt-api-plugin-2.11.2.jar new file mode 100644 index 0000000000..f1f6904215 Binary files /dev/null and b/localDependencies/item-nbt-api-plugin-2.11.2.jar differ diff --git a/localDependencies/worldedit-bukkit-6.1.9.jar b/localDependencies/worldedit-bukkit-6.1.9.jar deleted file mode 100644 index fd5d0036f5..0000000000 Binary files a/localDependencies/worldedit-bukkit-6.1.9.jar and /dev/null differ diff --git a/localDependencies/worldedit-bukkit-7.2.14.jar b/localDependencies/worldedit-bukkit-7.2.14.jar new file mode 100644 index 0000000000..76af69ee03 Binary files /dev/null and b/localDependencies/worldedit-bukkit-7.2.14.jar differ diff --git a/localDependencies/worldguard-bukkit-6.2.2.jar b/localDependencies/worldguard-bukkit-6.2.2.jar deleted file mode 100644 index 2f615d493c..0000000000 Binary files a/localDependencies/worldguard-bukkit-6.2.2.jar and /dev/null differ diff --git a/localDependencies/worldguard-bukkit-7.0.7-dist.jar b/localDependencies/worldguard-bukkit-7.0.7-dist.jar new file mode 100644 index 0000000000..9c4ea0bb77 Binary files /dev/null and b/localDependencies/worldguard-bukkit-7.0.7-dist.jar differ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 3def2e3633..99dfab09e6 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,7 +2,9 @@ name: @name@ main: com.github.unchama.seichiassist.SeichiAssist version: @version@ -softdepend: [WorldGuard, CoreProtect] +api-version: 1.18 + +softdepend: [WorldGuard, CoreProtect, NBTAPI, Multiverse-Core, RegenWorld] loadbefore: # ワールドマイグレーション時にこれらプラグインのタスクがworldへの参照を持ちデータのGCが行われなくなる diff --git a/src/main/scala/com/github/unchama/buildassist/BuildAssist.scala b/src/main/scala/com/github/unchama/buildassist/BuildAssist.scala index 32072d60da..318116771b 100644 --- a/src/main/scala/com/github/unchama/buildassist/BuildAssist.scala +++ b/src/main/scala/com/github/unchama/buildassist/BuildAssist.scala @@ -97,8 +97,11 @@ object BuildAssist { , Material.COBBLESTONE // 丸石 , - Material.WOOD // 木 - , + Material.ACACIA_WOOD, + Material.BIRCH_WOOD, + Material.DARK_OAK_WOOD, + Material.JUNGLE_WOOD, + Material.OAK_WOOD, Material.SAND // 砂 , Material.GRAVEL // 砂利 @@ -109,18 +112,34 @@ object BuildAssist { , Material.COAL_ORE // 石炭鉱石 , - Material.LOG // 原木 - , + Material.ACACIA_LOG, + Material.BIRCH_LOG, + Material.DARK_OAK_LOG, + Material.JUNGLE_LOG, + Material.OAK_LOG, Material.GLASS // ガラス , Material.LAPIS_ORE // ラピス鉱石 , Material.LAPIS_BLOCK // ラピスB , - Material.SANDSTONE // 砂岩 - , - Material.WOOL // 羊毛 - , + Material.SANDSTONE, // 砂岩 + Material.BLACK_WOOL, + Material.BLUE_WOOL, + Material.BROWN_WOOL, + Material.CYAN_WOOL, + Material.GRAY_WOOL, + Material.GREEN_WOOL, + Material.LIGHT_BLUE_WOOL, + Material.LIGHT_GRAY_WOOL, + Material.LIME_WOOL, + Material.MAGENTA_WOOL, + Material.ORANGE_WOOL, + Material.PINK_WOOL, + Material.PURPLE_WOOL, + Material.RED_WOOL, + Material.WHITE_WOOL, + Material.YELLOW_WOOL, Material.GOLD_BLOCK // 金B , Material.IRON_BLOCK // 鉄B @@ -149,38 +168,76 @@ object BuildAssist { , Material.SOUL_SAND // ソウルサンド , - Material.GLOWSTONE // グロウストーン - , - Material.STAINED_GLASS // 色付きガラス - , - Material.SMOOTH_BRICK // 石レンガ - , - Material.MYCEL // 菌糸 + Material.GLOWSTONE, + Material.BLACK_STAINED_GLASS, + Material.BLUE_STAINED_GLASS, + Material.BROWN_STAINED_GLASS, + Material.CYAN_STAINED_GLASS, + Material.GRAY_STAINED_GLASS, + Material.GREEN_STAINED_GLASS, + Material.LIGHT_BLUE_STAINED_GLASS, + Material.LIGHT_GRAY_STAINED_GLASS, + Material.LIME_STAINED_GLASS, + Material.MAGENTA_STAINED_GLASS, + Material.ORANGE_STAINED_GLASS, + Material.PINK_STAINED_GLASS, + Material.PURPLE_STAINED_GLASS, + Material.RED_STAINED_GLASS, + Material.WHITE_STAINED_GLASS, + Material.YELLOW_STAINED_GLASS, + Material.STONE_BRICKS // 石レンガ + , + Material.MYCELIUM // 菌糸 , Material.NETHER_BRICK // ネザーレンガ , - Material.ENDER_STONE // エンドストーン + Material.END_STONE // エンドストーン , Material.EMERALD_ORE // エメ鉱石 , Material.EMERALD_BLOCK // エメB , - Material.COBBLE_WALL // 丸石の壁 + Material.COBBLESTONE_WALL // 丸石の壁 , - Material.QUARTZ_ORE // 水晶鉱石 + Material.NETHER_QUARTZ_ORE // 水晶鉱石 , Material.QUARTZ_BLOCK // 水晶B , - Material.STAINED_CLAY // 色付き固焼き粘土 - , - Material.LOG_2 // 原木2 - , + Material.BLACK_TERRACOTTA, + Material.BLUE_TERRACOTTA, + Material.BROWN_TERRACOTTA, + Material.CYAN_TERRACOTTA, + Material.GRAY_TERRACOTTA, + Material.GREEN_TERRACOTTA, + Material.LIGHT_BLUE_TERRACOTTA, + Material.LIGHT_GRAY_TERRACOTTA, + Material.LIME_TERRACOTTA, + Material.MAGENTA_TERRACOTTA, + Material.ORANGE_TERRACOTTA, + Material.PINK_TERRACOTTA, + Material.PURPLE_TERRACOTTA, + Material.RED_TERRACOTTA, + Material.WHITE_TERRACOTTA, + Material.YELLOW_TERRACOTTA, Material.PRISMARINE // プリズマリン , - Material.SEA_LANTERN // シーランタン - , - Material.HARD_CLAY // 固焼き粘土 - , + Material.SEA_LANTERN, // シーランタン + Material.BLACK_GLAZED_TERRACOTTA, + Material.BLUE_GLAZED_TERRACOTTA, + Material.BROWN_GLAZED_TERRACOTTA, + Material.CYAN_GLAZED_TERRACOTTA, + Material.GRAY_GLAZED_TERRACOTTA, + Material.GREEN_GLAZED_TERRACOTTA, + Material.LIGHT_BLUE_GLAZED_TERRACOTTA, + Material.LIGHT_GRAY_GLAZED_TERRACOTTA, + Material.LIME_GLAZED_TERRACOTTA, + Material.MAGENTA_GLAZED_TERRACOTTA, + Material.ORANGE_GLAZED_TERRACOTTA, + Material.PINK_GLAZED_TERRACOTTA, + Material.PURPLE_GLAZED_TERRACOTTA, + Material.RED_GLAZED_TERRACOTTA, + Material.WHITE_GLAZED_TERRACOTTA, + Material.YELLOW_GLAZED_TERRACOTTA, Material.COAL_BLOCK // 石炭B , Material.PACKED_ICE // 氷塊 @@ -191,22 +248,49 @@ object BuildAssist { , Material.PURPUR_PILLAR // 柱状プルパーブ , - Material.END_BRICKS // エンドレンガB + Material.END_STONE_BRICKS // エンドレンガB , - Material.RED_NETHER_BRICK // 赤ネザーレンガB + Material.RED_NETHER_BRICKS // 赤ネザーレンガB , Material.BONE_BLOCK // 骨B , - Material.NETHER_WART_BLOCK // ネザーウォートB - , - Material.CONCRETE // コンクリート - , - Material.CONCRETE_POWDER // コンクリートパウダー - , + Material.NETHER_WART_BLOCK, // ネザーウォートB + Material.BLACK_CONCRETE, + Material.BLUE_CONCRETE, + Material.BROWN_CONCRETE, + Material.CYAN_CONCRETE, + Material.GRAY_CONCRETE, + Material.GREEN_CONCRETE, + Material.LIGHT_BLUE_CONCRETE, + Material.LIGHT_GRAY_CONCRETE, + Material.LIME_CONCRETE, + Material.MAGENTA_CONCRETE, + Material.ORANGE_CONCRETE, + Material.PINK_CONCRETE, + Material.PURPLE_CONCRETE, + Material.RED_CONCRETE, + Material.WHITE_CONCRETE, + Material.YELLOW_CONCRETE, + Material.BLACK_CONCRETE_POWDER, + Material.BLUE_CONCRETE_POWDER, + Material.BROWN_CONCRETE_POWDER, + Material.CYAN_CONCRETE_POWDER, + Material.GRAY_CONCRETE_POWDER, + Material.GREEN_CONCRETE_POWDER, + Material.LIGHT_BLUE_CONCRETE_POWDER, + Material.LIGHT_GRAY_CONCRETE_POWDER, + Material.LIME_CONCRETE_POWDER, + Material.MAGENTA_CONCRETE_POWDER, + Material.ORANGE_CONCRETE_POWDER, + Material.PINK_CONCRETE_POWDER, + Material.PURPLE_CONCRETE_POWDER, + Material.RED_CONCRETE_POWDER, + Material.WHITE_CONCRETE_POWDER, + Material.YELLOW_CONCRETE_POWDER, Material.ACACIA_STAIRS, Material.ACACIA_FENCE, Material.ACACIA_FENCE_GATE, - Material.BIRCH_WOOD_STAIRS, + Material.BIRCH_STAIRS, Material.BIRCH_FENCE, Material.BIRCH_FENCE_GATE, Material.BONE_BLOCK, @@ -215,28 +299,33 @@ object BuildAssist { Material.BRICK_STAIRS, Material.CACTUS, Material.CHEST, - Material.CLAY_BRICK, Material.DARK_OAK_STAIRS, Material.DARK_OAK_FENCE, Material.DARK_OAK_FENCE_GATE, - Material.END_BRICKS, + Material.END_STONE_BRICKS, Material.FURNACE, Material.GLOWSTONE, - Material.HARD_CLAY, Material.JACK_O_LANTERN, Material.JUKEBOX, Material.JUNGLE_FENCE, Material.JUNGLE_FENCE_GATE, - Material.JUNGLE_WOOD_STAIRS, + Material.STRIPPED_JUNGLE_WOOD, Material.LADDER, - Material.LEAVES, - Material.LEAVES_2, - Material.LOG, - Material.LOG_2, + Material.OAK_LEAVES, + Material.BIRCH_LEAVES, + Material.JUNGLE_LEAVES, + Material.ACACIA_LEAVES, + Material.DARK_OAK_LEAVES, + Material.SPRUCE_LEAVES, + Material.ACACIA_LOG, + Material.BIRCH_LOG, + Material.DARK_OAK_LOG, + Material.JUNGLE_LOG, + Material.OAK_LOG, Material.NETHER_BRICK, Material.NETHER_BRICK_STAIRS, Material.NETHER_WART_BLOCK, - Material.RED_NETHER_BRICK, + Material.RED_NETHER_BRICKS, Material.OBSIDIAN, Material.PACKED_ICE, Material.PRISMARINE, @@ -252,31 +341,72 @@ object BuildAssist { Material.SANDSTONE_STAIRS, Material.SEA_LANTERN, Material.SLIME_BLOCK, - Material.SMOOTH_BRICK, - Material.SMOOTH_STAIRS, + Material.SMOOTH_STONE, + Material.CHISELED_STONE_BRICKS, + Material.CRACKED_STONE_BRICKS, + Material.INFESTED_STONE_BRICKS, + Material.MOSSY_STONE_BRICKS, + Material.STONE_BRICK_STAIRS, Material.SNOW_BLOCK, Material.SPRUCE_FENCE, Material.SPRUCE_FENCE_GATE, - Material.SPRUCE_WOOD_STAIRS, - Material.FENCE, - Material.FENCE_GATE, - Material.STAINED_CLAY, - Material.STAINED_GLASS, - Material.STAINED_GLASS_PANE, - Material.STEP, + Material.STRIPPED_ACACIA_WOOD, + Material.STRIPPED_BIRCH_WOOD, + Material.STRIPPED_DARK_OAK_WOOD, + Material.STRIPPED_JUNGLE_WOOD, + Material.STRIPPED_OAK_WOOD, + Material.OAK_FENCE, + Material.ACACIA_FENCE, + Material.BIRCH_FENCE, + Material.DARK_OAK_FENCE, + Material.JUNGLE_FENCE, + Material.OAK_FENCE_GATE, + Material.ACACIA_FENCE_GATE, + Material.BIRCH_FENCE_GATE, + Material.DARK_OAK_FENCE_GATE, + Material.JUNGLE_FENCE_GATE, + Material.OAK_FENCE_GATE, + Material.BLACK_STAINED_GLASS_PANE, + Material.BLUE_STAINED_GLASS_PANE, + Material.BROWN_STAINED_GLASS_PANE, + Material.CYAN_STAINED_GLASS_PANE, + Material.GRAY_STAINED_GLASS_PANE, + Material.GREEN_STAINED_GLASS_PANE, + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + Material.LIGHT_GRAY_STAINED_GLASS_PANE, + Material.LIME_STAINED_GLASS_PANE, + Material.MAGENTA_STAINED_GLASS_PANE, + Material.ORANGE_STAINED_GLASS_PANE, + Material.PINK_STAINED_GLASS_PANE, + Material.PURPLE_STAINED_GLASS_PANE, + Material.RED_STAINED_GLASS_PANE, + Material.WHITE_STAINED_GLASS_PANE, + Material.YELLOW_STAINED_GLASS_PANE, + Material.ACACIA_SLAB, + Material.BIRCH_SLAB, + Material.DARK_OAK_SLAB, + Material.JUNGLE_SLAB, + Material.OAK_SLAB, Material.STONE, - Material.STONE_SLAB2, - Material.THIN_GLASS, + Material.STONE_SLAB, Material.TORCH, - Material.WOOD, - Material.WOOD_STAIRS, - Material.WOOD_STEP, - Material.WOOL, - Material.CARPET, - Material.WORKBENCH, - // #1008 - Material.LEAVES, - Material.LEAVES_2 + Material.BLACK_CARPET, + Material.BLUE_CARPET, + Material.BROWN_CARPET, + Material.CYAN_CARPET, + Material.GRAY_CARPET, + Material.GREEN_CARPET, + Material.LIGHT_BLUE_CARPET, + Material.LIGHT_GRAY_CARPET, + Material.LIME_CARPET, + Material.MAGENTA_CARPET, + Material.ORANGE_CARPET, + Material.PINK_CARPET, + Material.PURPLE_CARPET, + Material.RED_CARPET, + Material.WHITE_CARPET, + Material.YELLOW_CARPET, + Material.CRAFTING_TABLE ) // 直列設置ブロックの対象リスト @@ -291,8 +421,11 @@ object BuildAssist { , Material.COBBLESTONE // 丸石 , - Material.WOOD // 木 - , + Material.ACACIA_WOOD, + Material.BIRCH_WOOD, + Material.DARK_OAK_WOOD, + Material.JUNGLE_WOOD, + Material.OAK_WOOD, Material.SAND // 砂 , Material.GRAVEL // 砂利 @@ -303,8 +436,11 @@ object BuildAssist { , Material.COAL_ORE // 石炭鉱石 , - Material.LOG // 原木 - , + Material.ACACIA_LOG, + Material.BIRCH_LOG, + Material.DARK_OAK_LOG, + Material.JUNGLE_LOG, + Material.OAK_LOG, Material.GLASS // ガラス , Material.LAPIS_ORE // ラピス鉱石 @@ -313,8 +449,22 @@ object BuildAssist { , Material.SANDSTONE // 砂岩 , - Material.WOOL // 羊毛 - , + Material.BLACK_WOOL, + Material.BLUE_WOOL, + Material.BROWN_WOOL, + Material.CYAN_WOOL, + Material.GRAY_WOOL, + Material.GREEN_WOOL, + Material.LIGHT_BLUE_WOOL, + Material.LIGHT_GRAY_WOOL, + Material.LIME_WOOL, + Material.MAGENTA_WOOL, + Material.ORANGE_WOOL, + Material.PINK_WOOL, + Material.PURPLE_WOOL, + Material.RED_WOOL, + Material.WHITE_WOOL, + Material.YELLOW_WOOL, Material.GOLD_BLOCK // 金B , Material.IRON_BLOCK // 鉄B @@ -345,36 +495,76 @@ object BuildAssist { , Material.GLOWSTONE // グロウストーン , - Material.STAINED_GLASS // 色付きガラス - , - Material.SMOOTH_BRICK // 石レンガ - , - Material.MYCEL // 菌糸 + Material.BLACK_STAINED_GLASS, + Material.BLUE_STAINED_GLASS, + Material.BROWN_STAINED_GLASS, + Material.CYAN_STAINED_GLASS, + Material.GRAY_STAINED_GLASS, + Material.GREEN_STAINED_GLASS, + Material.LIGHT_BLUE_STAINED_GLASS, + Material.LIGHT_GRAY_STAINED_GLASS, + Material.LIME_STAINED_GLASS, + Material.MAGENTA_STAINED_GLASS, + Material.ORANGE_STAINED_GLASS, + Material.PINK_STAINED_GLASS, + Material.PURPLE_STAINED_GLASS, + Material.RED_STAINED_GLASS, + Material.WHITE_STAINED_GLASS, + Material.YELLOW_STAINED_GLASS, + Material.STONE_BRICKS // 石レンガ + , + Material.MYCELIUM // 菌糸 , Material.NETHER_BRICK // ネザーレンガ , - Material.ENDER_STONE // エンドストーン + Material.END_STONE // エンドストーン , Material.EMERALD_ORE // エメ鉱石 , Material.EMERALD_BLOCK // エメB , - Material.COBBLE_WALL // 丸石の壁 + Material.COBBLESTONE_WALL // 丸石の壁 , - Material.QUARTZ_ORE // 水晶鉱石 + Material.NETHER_QUARTZ_ORE // 水晶鉱石 , Material.QUARTZ_BLOCK // 水晶B , - Material.STAINED_CLAY // 色付き固焼き粘土 - , - Material.LOG_2 // 原木2 - , + Material.BLACK_TERRACOTTA, + Material.BLUE_TERRACOTTA, + Material.BROWN_TERRACOTTA, + Material.CYAN_TERRACOTTA, + Material.GRAY_TERRACOTTA, + Material.GREEN_TERRACOTTA, + Material.LIGHT_BLUE_TERRACOTTA, + Material.LIGHT_GRAY_TERRACOTTA, + Material.LIME_TERRACOTTA, + Material.MAGENTA_TERRACOTTA, + Material.ORANGE_TERRACOTTA, + Material.PINK_TERRACOTTA, + Material.PURPLE_TERRACOTTA, + Material.RED_TERRACOTTA, + Material.WHITE_TERRACOTTA, + Material.YELLOW_TERRACOTTA, Material.PRISMARINE // プリズマリン , Material.SEA_LANTERN // シーランタン , - Material.HARD_CLAY // 固焼き粘土 - , + Material.BLACK_GLAZED_TERRACOTTA, + Material.BLUE_GLAZED_TERRACOTTA, + Material.BROWN_GLAZED_TERRACOTTA, + Material.CYAN_GLAZED_TERRACOTTA, + Material.GRAY_GLAZED_TERRACOTTA, + Material.GREEN_GLAZED_TERRACOTTA, + Material.LIGHT_BLUE_GLAZED_TERRACOTTA, + Material.LIGHT_GRAY_GLAZED_TERRACOTTA, + Material.LIME_GLAZED_TERRACOTTA, + Material.MAGENTA_GLAZED_TERRACOTTA, + Material.ORANGE_GLAZED_TERRACOTTA, + Material.PINK_GLAZED_TERRACOTTA, + Material.PURPLE_GLAZED_TERRACOTTA, + Material.RED_GLAZED_TERRACOTTA, + Material.WHITE_GLAZED_TERRACOTTA, + Material.YELLOW_GLAZED_TERRACOTTA, Material.COAL_BLOCK // 石炭B , Material.PACKED_ICE // 氷塊 @@ -385,22 +575,53 @@ object BuildAssist { , Material.PURPUR_PILLAR // 柱状プルパーブ , - Material.END_BRICKS // エンドレンガB + Material.END_STONE_BRICKS // エンドレンガB , - Material.RED_NETHER_BRICK // 赤ネザーレンガB + Material.RED_NETHER_BRICKS // 赤ネザーレンガB , Material.BONE_BLOCK // 骨B , - Material.FENCE // オークフェンス - , - Material.IRON_FENCE // 鉄フェンス - , - Material.THIN_GLASS // 板ガラス - , - Material.NETHER_FENCE // ネザーフェンス - , - Material.STAINED_GLASS_PANE // 色付き板ガラス - , + Material.OAK_FENCE, + Material.ACACIA_FENCE, + Material.BIRCH_FENCE, + Material.DARK_OAK_FENCE, + Material.JUNGLE_FENCE, + Material.IRON_BARS // 鉄フェンス + , + Material.BLACK_STAINED_GLASS, + Material.BLUE_STAINED_GLASS, + Material.BROWN_STAINED_GLASS, + Material.CYAN_STAINED_GLASS, + Material.GRAY_STAINED_GLASS, + Material.GREEN_STAINED_GLASS, + Material.LIGHT_BLUE_STAINED_GLASS, + Material.LIGHT_GRAY_STAINED_GLASS, + Material.LIME_STAINED_GLASS, + Material.MAGENTA_STAINED_GLASS, + Material.ORANGE_STAINED_GLASS, + Material.PINK_STAINED_GLASS, + Material.PURPLE_STAINED_GLASS, + Material.RED_STAINED_GLASS, + Material.WHITE_STAINED_GLASS, + Material.YELLOW_STAINED_GLASS, + Material.NETHER_BRICK_FENCE // ネザーフェンス + , + Material.BLACK_STAINED_GLASS_PANE, + Material.BLUE_STAINED_GLASS_PANE, + Material.BROWN_STAINED_GLASS_PANE, + Material.CYAN_STAINED_GLASS_PANE, + Material.GRAY_STAINED_GLASS_PANE, + Material.GREEN_STAINED_GLASS_PANE, + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + Material.LIGHT_GRAY_STAINED_GLASS_PANE, + Material.LIME_STAINED_GLASS_PANE, + Material.MAGENTA_STAINED_GLASS_PANE, + Material.ORANGE_STAINED_GLASS_PANE, + Material.PINK_STAINED_GLASS_PANE, + Material.PURPLE_STAINED_GLASS_PANE, + Material.RED_STAINED_GLASS_PANE, + Material.WHITE_STAINED_GLASS_PANE, + Material.YELLOW_STAINED_GLASS_PANE, Material.SLIME_BLOCK // スライムB , Material.SPRUCE_FENCE // 松フェンス @@ -413,40 +634,79 @@ object BuildAssist { , Material.ACACIA_FENCE // アカシアフェンス , - Material.NETHER_WART_BLOCK // ネザーウォートB - , - Material.CONCRETE // コンクリート - , - Material.CONCRETE_POWDER // コンクリートパウダー - , - Material.LEAVES, - Material.LEAVES_2 + Material.NETHER_WART_BLOCK, // ネザーウォートB + Material.BLACK_CONCRETE, + Material.BLUE_CONCRETE, + Material.BROWN_CONCRETE, + Material.CYAN_CONCRETE, + Material.GRAY_CONCRETE, + Material.GREEN_CONCRETE, + Material.LIGHT_BLUE_CONCRETE, + Material.LIGHT_GRAY_CONCRETE, + Material.LIME_CONCRETE, + Material.MAGENTA_CONCRETE, + Material.ORANGE_CONCRETE, + Material.PINK_CONCRETE, + Material.PURPLE_CONCRETE, + Material.RED_CONCRETE, + Material.WHITE_CONCRETE, + Material.YELLOW_CONCRETE, + Material.BLACK_CONCRETE_POWDER, + Material.BLUE_CONCRETE_POWDER, + Material.BROWN_CONCRETE_POWDER, + Material.CYAN_CONCRETE_POWDER, + Material.GRAY_CONCRETE_POWDER, + Material.GREEN_CONCRETE_POWDER, + Material.LIGHT_BLUE_CONCRETE_POWDER, + Material.LIGHT_GRAY_CONCRETE_POWDER, + Material.LIME_CONCRETE_POWDER, + Material.MAGENTA_CONCRETE_POWDER, + Material.ORANGE_CONCRETE_POWDER, + Material.PINK_CONCRETE_POWDER, + Material.PURPLE_CONCRETE_POWDER, + Material.RED_CONCRETE_POWDER, + Material.WHITE_CONCRETE_POWDER, + Material.YELLOW_CONCRETE_POWDER, + Material.OAK_LEAVES, + Material.BIRCH_LEAVES, + Material.JUNGLE_LEAVES, + Material.ACACIA_LEAVES, + Material.DARK_OAK_LEAVES, + Material.SPRUCE_LEAVES ) // ハーフブロックとして扱うMaterial val material_slab2: java.util.Set[Material] = util .EnumSet .of( - Material.STONE_SLAB2 // 赤砂岩 - , - Material.PURPUR_SLAB // プルパー - , - Material.WOOD_STEP // 木 - , - Material.STEP // 石 + Material.RED_SANDSTONE_SLAB, + Material.PURPUR_SLAB, + Material.ACACIA_SLAB, + Material.BIRCH_SLAB, + Material.DARK_OAK_SLAB, + Material.JUNGLE_SLAB, + Material.OAK_SLAB, + Material.STONE_SLAB, + Material.STONE_BRICK_SLAB ) val material_destruction: java.util.Set[Material] = util .EnumSet .of( - Material.LONG_GRASS // 草 - , + Material.GRASS, + Material.TALL_GRASS, Material.DEAD_BUSH // 枯れ木 , - Material.YELLOW_FLOWER // タンポポ - , - Material.RED_ROSE // 花9種 - , + Material.DANDELION, + Material.POPPY, + Material.BLUE_ORCHID, + Material.ALLIUM, + Material.AZURE_BLUET, + Material.RED_TULIP, + Material.ORANGE_TULIP, + Material.WHITE_TULIP, + Material.PINK_TULIP, + Material.OXEYE_DAISY, Material.BROWN_MUSHROOM // きのこ , Material.RED_MUSHROOM // 赤きのこ @@ -455,16 +715,15 @@ object BuildAssist { , Material.SNOW // 雪 , - Material.DOUBLE_PLANT // 高い花、草 - , + Material.SUNFLOWER, + Material.LILAC, + Material.LARGE_FERN, + Material.ROSE_BUSH, + Material.PEONY, Material.WATER // 水 , - Material.STATIONARY_WATER // 水 - , Material.LAVA // 溶岩 , - Material.STATIONARY_LAVA // 溶岩 - , Material.VINE // ツタ ) diff --git a/src/main/scala/com/github/unchama/buildassist/MenuInventoryData.scala b/src/main/scala/com/github/unchama/buildassist/MenuInventoryData.scala index 95666d3373..4a822694d9 100644 --- a/src/main/scala/com/github/unchama/buildassist/MenuInventoryData.scala +++ b/src/main/scala/com/github/unchama/buildassist/MenuInventoryData.scala @@ -2,11 +2,12 @@ package com.github.unchama.buildassist import cats.effect.SyncIO import com.github.unchama.buildassist.util.AsyncInventorySetter +import com.github.unchama.itemstackbuilder.{IconItemStackBuilder, SkullItemStackBuilder} +import com.github.unchama.seichiassist.SkullOwners import com.github.unchama.seichiassist.subsystems.itemmigration.infrastructure.minecraft.JdbcBackedUuidRepository -import com.github.unchama.seichiassist.util.ItemMetaFactory import org.bukkit.ChatColor._ import org.bukkit.entity.Player -import org.bukkit.inventory.meta.{ItemMeta, SkullMeta} +import org.bukkit.inventory.meta.ItemMeta import org.bukkit.inventory.{Inventory, ItemStack} import org.bukkit.{Bukkit, Material} @@ -26,41 +27,34 @@ object MenuInventoryData { val playerdata = BuildAssist.instance.temporaryData(uuid) val inventory = Bukkit.getServer.createInventory(null, 4 * 9, s"$DARK_PURPLE$BOLD「直列設置」設定") - var itemstack = new ItemStack(Material.SKULL_ITEM, 1) - var itemmeta: ItemMeta = Bukkit.getItemFactory.getItemMeta(Material.WOOD) - val skullmeta: SkullMeta = ItemMetaFactory.SKULL.getValue + var itemstack = new ItemStack(Material.PLAYER_HEAD, 11) + var itemmeta: ItemMeta = itemstack.getItemMeta var lore = List(s"$RESET$DARK_RED${UNDERLINE}クリックで移動") // ホームを開く - itemstack.setDurability(3.toShort) - skullmeta.setDisplayName(s"$YELLOW$UNDERLINE${BOLD}ホームへ") - skullmeta.setLore(lore.asJava) - - /** - * 参加したことのないプレーヤーはgetOfflinePlayerでデータが取れないのでこうするしか無い - */ - skullmeta.setOwner("MHF_ArrowLeft") - itemstack.setItemMeta(skullmeta) + itemstack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowLeft) + .title(s"$YELLOW$UNDERLINE${BOLD}ホームへ") + .lore(lore) + .build() AsyncInventorySetter.setItemAsync(inventory, 27, itemstack) - // 直列設置設定 - itemstack = new ItemStack(Material.WOOD, 1) - itemmeta.setDisplayName( - s"$YELLOW$UNDERLINE${BOLD}直列設置 :${BuildAssist.line_up_str(playerdata.line_up_flg)}" - ) - lore = List( - s"$RESET${GRAY}オフハンドに木の棒、メインハンドに設置したいブロックを持って", - s"$RESET${GRAY}左クリックすると向いてる方向に並べて設置します。", - s"$RESET${GRAY}建築Lv${BuildAssist.config.getblocklineuplevel}以上で利用可能", - s"$RESET${GRAY}クリックで切り替え" - ) - itemmeta.setLore(lore.asJava) - itemstack.setItemMeta(itemmeta) + itemstack = new IconItemStackBuilder(Material.OAK_PLANKS) + .title( + s"$YELLOW$UNDERLINE${BOLD}直列設置 :${BuildAssist.line_up_str(playerdata.line_up_flg)}" + ) + .lore( + s"$RESET${GRAY}オフハンドに木の棒、メインハンドに設置したいブロックを持って", + s"$RESET${GRAY}左クリックすると向いてる方向に並べて設置します。", + s"$RESET${GRAY}建築Lv${BuildAssist.config.getblocklineuplevel}以上で利用可能", + s"$RESET${GRAY}クリックで切り替え" + ) + .build() + inventory.setItem(0, itemstack) // 直列設置ハーフブロック設定 - itemstack = new ItemStack(Material.STEP, 1) - itemmeta = Bukkit.getItemFactory.getItemMeta(Material.STEP) + itemstack = new ItemStack(Material.STONE_SLAB, 1) + itemmeta = itemstack.getItemMeta itemmeta.setDisplayName( s"$YELLOW$UNDERLINE${BOLD}ハーフブロック設定 :${BuildAssist.line_up_step_str(playerdata.line_up_step_flg)}" ) diff --git a/src/main/scala/com/github/unchama/buildassist/PlayerInventoryListener.scala b/src/main/scala/com/github/unchama/buildassist/PlayerInventoryListener.scala index 539535777f..484cda811e 100644 --- a/src/main/scala/com/github/unchama/buildassist/PlayerInventoryListener.scala +++ b/src/main/scala/com/github/unchama/buildassist/PlayerInventoryListener.scala @@ -58,7 +58,7 @@ class PlayerInventoryListener( // プレイヤーデータが無い場合は処理終了 // インベントリ名が以下の時処理 - if (topinventory.getTitle == s"${DARK_PURPLE.toString}$BOLD「直列設置」設定") { + if (view.getTitle == s"${DARK_PURPLE.toString}$BOLD「直列設置」設定") { event.setCancelled(true) // プレイヤーインベントリのクリックの場合終了 @@ -68,7 +68,7 @@ class PlayerInventoryListener( /* * クリックしたボタンに応じた各処理内容の記述ここから */ - if (itemstackcurrent.getType == Material.SKULL_ITEM) { + if (itemstackcurrent.getType == Material.PLAYER_HEAD) { // ホームメニューへ帰還 effectEnvironment.unsafeRunAsyncTargetedEffect(player)( @@ -78,7 +78,7 @@ class PlayerInventoryListener( ), "BuildMainMenuを開く" ) - } else if (itemstackcurrent.getType == Material.WOOD) { + } else if (itemstackcurrent.getType == Material.OAK_PLANKS) { // 直列設置設定 if (playerLevel < BuildAssist.config.getblocklineuplevel) { player.sendMessage(RED.toString + "建築Lvが足りません") @@ -91,7 +91,7 @@ class PlayerInventoryListener( player.playSound(player.getLocation, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f) player.openInventory(MenuInventoryData.getBlockLineUpData(player)) } - } else if (itemstackcurrent.getType == Material.STEP) { + } else if (itemstackcurrent.getType == Material.STONE_SLAB) { // 直列設置ハーフブロック設定 if (playerdata.line_up_step_flg >= 2) { playerdata.line_up_step_flg = 0 diff --git a/src/main/scala/com/github/unchama/buildassist/listener/BlockLineUpTriggerListener.scala b/src/main/scala/com/github/unchama/buildassist/listener/BlockLineUpTriggerListener.scala index 5aa13a032a..f1ec54ae36 100644 --- a/src/main/scala/com/github/unchama/buildassist/listener/BlockLineUpTriggerListener.scala +++ b/src/main/scala/com/github/unchama/buildassist/listener/BlockLineUpTriggerListener.scala @@ -7,7 +7,8 @@ import com.github.unchama.seichiassist.subsystems.buildcount.application.actions import com.github.unchama.seichiassist.subsystems.buildcount.domain.explevel.BuildExpAmount import com.github.unchama.seichiassist.subsystems.mana.ManaApi import com.github.unchama.seichiassist.subsystems.minestack.MineStackAPI -import com.github.unchama.util.external.ExternalPlugins +import com.github.unchama.util.external.WorldGuardWrapper +import org.bukkit.block.data.`type`.Slab import org.bukkit.entity.Player import org.bukkit.event.block.Action import org.bukkit.event.player.PlayerInteractEvent @@ -15,6 +16,7 @@ import org.bukkit.event.{EventHandler, Listener} import org.bukkit.inventory.ItemStack import org.bukkit.{Material, Sound} +import scala.util.chaining.scalaUtilChainingOps import scala.util.control.Breaks class BlockLineUpTriggerListener[ @@ -61,7 +63,6 @@ class BlockLineUpTriggerListener[ val pl = player.getLocation val mainHandItemType = mainHandItem.getType - val mainHandItemData = mainHandItem.getData.getData // 仰角は下向きがプラスで上向きがマイナス val pitch = pl.getPitch @@ -103,8 +104,10 @@ class BlockLineUpTriggerListener[ if (buildAssistData.line_up_minestack_flg == 1) { mineStackAPI .mineStackObjectList - .findBySignedItemStack(mainHandItem, player) + .findBySignedItemStacks(Vector(mainHandItem), player) .unsafeRunSync() + .head + ._2 } else None val maxBlockUsage = { @@ -132,30 +135,20 @@ class BlockLineUpTriggerListener[ Seq(Some(available), manaCap, Some(64L)).flatten.min }.toInt - def slabToDoubleSlab(material: Material) = material match { - case Material.STONE_SLAB2 => Material.DOUBLE_STONE_SLAB2 - case Material.PURPUR_SLAB => Material.PURPUR_DOUBLE_SLAB - case Material.WOOD_STEP => Material.WOOD_DOUBLE_STEP - case Material.STEP => Material.DOUBLE_STEP - case _ => mainHandItemType - } + def slabToDoubleSlab(material: Material): Material = + if (material.createBlockData().isInstanceOf[Slab]) { + material.asInstanceOf[Slab].tap(slab => slab.setType(Slab.Type.DOUBLE)).getMaterial + } else material val playerHoldsSlabBlock = BuildAssist.material_slab2.contains(mainHandItemType) - val doesHoldLeaves = - (mainHandItemType eq Material.LEAVES) || (mainHandItemType eq Material.LEAVES_2) + (mainHandItemType eq Material.OAK_LEAVES) || (mainHandItemType eq Material.DARK_OAK_LEAVES) || ( + mainHandItemType eq Material.BIRCH_LEAVES + ) || (mainHandItemType eq Material.ACACIA_LEAVES) || ( + mainHandItemType eq Material.JUNGLE_LEAVES + ) || (mainHandItemType eq Material.SPRUCE_LEAVES) val slabLineUpStepMode = buildAssistData.line_up_step_flg val shouldPlaceDoubleSlabs = playerHoldsSlabBlock && slabLineUpStepMode == 2 - val upsideBit = 8 - val noDecayBit = 4 - val placingBlockData: Byte = - if (playerHoldsSlabBlock && slabLineUpStepMode == 0) - (mainHandItemData | upsideBit).toByte - else if (doesHoldLeaves) - (mainHandItemData | noDecayBit).toByte - else - mainHandItemData - val (placingBlockType, itemConsumptionPerPlacement, placementIteration) = if (shouldPlaceDoubleSlabs) (slabToDoubleSlab(mainHandItemType), 2, maxBlockUsage / 2) @@ -174,7 +167,7 @@ class BlockLineUpTriggerListener[ val block = playerWorld.getBlockAt(px, py, pz) // 他人の保護がかかっている場合は設置終わり - if (!ExternalPlugins.getWorldGuard.canBuild(player, block.getLocation)) b.break + if (!WorldGuardWrapper.canBuild(player, block.getLocation)) b.break() if (block.getType != Material.AIR) { // 空気以外にぶつかり、ブロック破壊をしないならば終わる @@ -183,7 +176,7 @@ class BlockLineUpTriggerListener[ .material_destruction .contains(block.getType) || buildAssistData.line_up_des_flg == 0 ) { - b.break + b.break() } block.getDrops.asScala.foreach { @@ -192,7 +185,6 @@ class BlockLineUpTriggerListener[ } block.setType(placingBlockType) - block.setData(placingBlockData) placedBlockCount += itemConsumptionPerPlacement } diff --git a/src/main/scala/com/github/unchama/buildassist/listener/TilingSkillTriggerListener.scala b/src/main/scala/com/github/unchama/buildassist/listener/TilingSkillTriggerListener.scala index 6b530f7166..2a41a3b462 100644 --- a/src/main/scala/com/github/unchama/buildassist/listener/TilingSkillTriggerListener.scala +++ b/src/main/scala/com/github/unchama/buildassist/listener/TilingSkillTriggerListener.scala @@ -2,11 +2,13 @@ package com.github.unchama.buildassist.listener import cats.effect.ConcurrentEffect.ops.toAllConcurrentEffectOps import cats.effect.{ConcurrentEffect, SyncEffect, SyncIO} -import com.github.unchama.buildassist.{BuildAssist, Util} +import com.github.unchama.buildassist.BuildAssist import com.github.unchama.seichiassist.subsystems.buildcount.application.actions.IncrementBuildExpWhenBuiltWithSkill import com.github.unchama.seichiassist.subsystems.buildcount.domain.explevel.BuildExpAmount import com.github.unchama.seichiassist.subsystems.minestack.MineStackAPI +import com.github.unchama.util.external.WorldGuardWrapper import org.bukkit.ChatColor.RED +import org.bukkit.block.data.`type`.Leaves import org.bukkit.entity.Player import org.bukkit.event.block.Action import org.bukkit.event.player.PlayerInteractEvent @@ -48,10 +50,7 @@ class TilingSkillTriggerListener[G[_]: ConcurrentEffect, F[ ) return val clickedBlock = event.getClickedBlock - val offHandItemSelector = offHandItem.getData.getData - if ( - !(offHandItem.getType == clickedBlock.getType && offHandItemSelector == clickedBlock.getData) - ) { + if (!(offHandItem.getType == clickedBlock.getType)) { player.sendMessage(s"$RED「オフハンドと同じブロック」をクリックしてください。(基準になります)") return } @@ -71,37 +70,40 @@ class TilingSkillTriggerListener[G[_]: ConcurrentEffect, F[ val minestackObjectToUse = mineStackAPI .mineStackObjectList - .findBySignedItemStack(offHandItem, player) + .findBySignedItemStacks(Vector(offHandItem), player) .toIO .unsafeRunSync() + .head + ._2 .filter(_ => buildAssistPlayerData.zs_minestack_flag) val replaceableMaterials = Set( Material.AIR, Material.SNOW, - Material.LONG_GRASS, + Material.TALL_GRASS, Material.DEAD_BUSH, - Material.YELLOW_FLOWER, - Material.RED_ROSE, + Material.DANDELION, + Material.POPPY, + Material.BLUE_ORCHID, + Material.ALLIUM, + Material.AZURE_BLUET, + Material.RED_TULIP, + Material.ORANGE_TULIP, + Material.WHITE_TULIP, + Material.PINK_TULIP, + Material.OXEYE_DAISY, + Material.SUNFLOWER, + Material.LILAC, + Material.LARGE_FERN, + Material.ROSE_BUSH, + Material.PEONY, Material.RED_MUSHROOM, Material.BROWN_MUSHROOM ) - val fillTargetMaterials = Set( - Material.AIR, - Material.LAVA, - Material.STATIONARY_LAVA, - Material.WATER, - Material.STATIONARY_WATER - ) + val fillTargetMaterials = Set(Material.AIR, Material.LAVA, Material.WATER) val b1 = new Breaks - val rawDataModifier: Byte => Byte = offHandItem.getType match { - case Material.LEAVES | Material.LEAVES_2 => - val noDecayBit: Byte = 8 - x => (x | noDecayBit).asInstanceOf[Byte] - case _ => identity - } b1.breakable { val targetXValues = centerX - areaInt to centerX + areaInt @@ -121,7 +123,7 @@ class TilingSkillTriggerListener[G[_]: ConcurrentEffect, F[ val blockToBeReplaced = fillLocation.getBlock if (fillTargetMaterials.contains(blockToBeReplaced.getType)) { - if (Util.getWorldGuard.canBuild(player, fillLocation)) { + if (WorldGuardWrapper.canBuild(player, fillLocation)) { blockToBeReplaced.setType(Material.DIRT) } else { // 他人の保護がかかっている場合は通知を行う @@ -137,7 +139,15 @@ class TilingSkillTriggerListener[G[_]: ConcurrentEffect, F[ } targetSurfaceBlock.setType(offHandItem.getType) - targetSurfaceBlock.setData(rawDataModifier(offHandItemSelector)) + + val block = targetSurfaceLocation.getBlock + + block.getBlockData match { + case leavesData: Leaves => + leavesData.setPersistent(true) + block.setBlockData(leavesData) + case _ => + } placementCount += 1 } @@ -179,7 +189,7 @@ class TilingSkillTriggerListener[G[_]: ConcurrentEffect, F[ if (replaceableMaterials.contains(targetSurfaceBlock.getType)) { // 他人の保護がかかっている場合は処理を終了 - if (!Util.getWorldGuard.canBuild(player, targetSurfaceLocation)) { + if (!WorldGuardWrapper.canBuild(player, targetSurfaceLocation)) { player.sendMessage(s"${RED}付近に誰かの保護がかかっているようです") b1.break() } diff --git a/src/main/scala/com/github/unchama/buildassist/menu/BlockPlacementSkillMenu.scala b/src/main/scala/com/github/unchama/buildassist/menu/BlockPlacementSkillMenu.scala index 858e921d01..7a0ffb7921 100644 --- a/src/main/scala/com/github/unchama/buildassist/menu/BlockPlacementSkillMenu.scala +++ b/src/main/scala/com/github/unchama/buildassist/menu/BlockPlacementSkillMenu.scala @@ -7,6 +7,7 @@ import com.github.unchama.menuinventory.router.CanOpen import com.github.unchama.menuinventory.slot.button.action.LeftClickButtonEffect import com.github.unchama.menuinventory.slot.button.{Button, RecomputedButton} import com.github.unchama.menuinventory.{Menu, MenuFrame, MenuSlotLayout} +import com.github.unchama.seichiassist.SkullOwners import com.github.unchama.seichiassist.effects.player.CommonSoundEffects import com.github.unchama.seichiassist.menus.BuildMainMenu import com.github.unchama.targetedeffect.commandsender.MessageEffect @@ -115,7 +116,7 @@ object BlockPlacementSkillMenu extends Menu { val playerData = BuildAssist.instance.temporaryData(getUniqueId) val currentRange = playerData.computeCurrentSkillRange() - val iconItemStack = new SkullItemStackBuilder("MHF_ArrowUp") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowUp) .title(s"$RED$UNDERLINE${BOLD}範囲設定を最大値に変更") .lore( s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange", @@ -142,7 +143,7 @@ object BlockPlacementSkillMenu extends Menu { val currentRange = playerData.computeCurrentSkillRange() val changedRange = 11 - val iconItemStack = new SkullItemStackBuilder("MHF_ArrowUp") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowUp) .title(s"$RED$UNDERLINE${BOLD}範囲設定を$changedRange×${changedRange}に変更") .lore( s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange", @@ -169,7 +170,7 @@ object BlockPlacementSkillMenu extends Menu { val currentRange = playerData.computeCurrentSkillRange() val changedRange = currentRange + 2 - val iconItemStack = new SkullItemStackBuilder("MHF_ArrowUp") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowUp) .title(s"$YELLOW$UNDERLINE${BOLD}範囲設定を一段階大きくする") .lore { List(s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange").concat( @@ -208,7 +209,7 @@ object BlockPlacementSkillMenu extends Menu { val currentRange = playerData.computeCurrentSkillRange() val changedRange = 5 - val iconItemStack = new SkullItemStackBuilder("MHF_TNT") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_TNT) .title(s"$RED$UNDERLINE${BOLD}範囲設定を初期値に変更") .lore( s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange", @@ -235,7 +236,7 @@ object BlockPlacementSkillMenu extends Menu { val currentRange = playerData.computeCurrentSkillRange() val changedRange = currentRange - 2 - val iconItemStack = new SkullItemStackBuilder("MHF_ArrowDown") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowDown) .title(s"$YELLOW$UNDERLINE${BOLD}範囲設定を一段階小さくする") .lore( List(s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange") @@ -272,7 +273,7 @@ object BlockPlacementSkillMenu extends Menu { val playerData = BuildAssist.instance.temporaryData(getUniqueId) val currentRange = playerData.computeCurrentSkillRange() - val iconItemStack = new SkullItemStackBuilder("MHF_ArrowDown") + val iconItemStack = new SkullItemStackBuilder(SkullOwners.MHF_ArrowDown) .title(s"$RED$UNDERLINE${BOLD}範囲設定を最小値に変更") .lore( s"$RESET${AQUA}現在の範囲設定: $currentRange×$currentRange", diff --git a/src/main/scala/com/github/unchama/contextualexecutor/builder/Parsers.scala b/src/main/scala/com/github/unchama/contextualexecutor/builder/Parsers.scala index 12b9c10096..f8fd70fdcb 100644 --- a/src/main/scala/com/github/unchama/contextualexecutor/builder/Parsers.scala +++ b/src/main/scala/com/github/unchama/contextualexecutor/builder/Parsers.scala @@ -93,6 +93,6 @@ object Parsers { } catch { case _: DateTimeParseException => Left(failureMessage) - case e => throw e + case e: Throwable => throw e } } diff --git a/src/main/scala/com/github/unchama/datarepository/bukkit/player/BukkitRepositoryControls.scala b/src/main/scala/com/github/unchama/datarepository/bukkit/player/BukkitRepositoryControls.scala index 27063da5f5..182e352452 100644 --- a/src/main/scala/com/github/unchama/datarepository/bukkit/player/BukkitRepositoryControls.scala +++ b/src/main/scala/com/github/unchama/datarepository/bukkit/player/BukkitRepositoryControls.scala @@ -164,7 +164,7 @@ object BukkitRepositoryControls { private def backupProcess[F[_]: Sync, Key, R]( finalization: RepositoryFinalization[F, Key, R] )(dataMap: TrieMap[Key, R]): F[Unit] = { - Sync[F].suspend { + Sync[F].defer { dataMap.toList.traverse(finalization.persistPair.tupled).as(()) } } diff --git a/src/main/scala/com/github/unchama/fs2/workaround/fs3/Fs3Topic.scala b/src/main/scala/com/github/unchama/fs2/workaround/fs3/Fs3Topic.scala index 58bced3bb3..806fdb33ed 100644 --- a/src/main/scala/com/github/unchama/fs2/workaround/fs3/Fs3Topic.scala +++ b/src/main/scala/com/github/unchama/fs2/workaround/fs3/Fs3Topic.scala @@ -210,10 +210,8 @@ object Fs3Topic { def close: F[Unit] = { Bracket[F, Throwable].uncancelable { signalClosure.complete(()).flatMap { _ => - state - .get - .flatMap { case (subs, _) => foreach(subs)(_.close.void) } - .as(Fs3Topic.rightUnit) + state.get.flatMap { case (subs, _) => foreach(subs)(_.close.void) } +// .as(Fs3Topic.rightUnit) } } } diff --git a/src/main/scala/com/github/unchama/generic/Diff.scala b/src/main/scala/com/github/unchama/generic/Diff.scala index 3d517bb6d5..2cd94183b5 100644 --- a/src/main/scala/com/github/unchama/generic/Diff.scala +++ b/src/main/scala/com/github/unchama/generic/Diff.scala @@ -7,7 +7,7 @@ import cats.Eq * * [[A]] に関連付いた [[Eq]] インスタンスによって [[left]] と [[right]] が等価でないと判定されることが保証される。 */ -case class Diff[A: Eq] private (left: A, right: A) +case class Diff[A] private (left: A, right: A) object Diff { diff --git a/src/main/scala/com/github/unchama/generic/ListExtra.scala b/src/main/scala/com/github/unchama/generic/ListExtra.scala index 57eedb323e..06622109e1 100644 --- a/src/main/scala/com/github/unchama/generic/ListExtra.scala +++ b/src/main/scala/com/github/unchama/generic/ListExtra.scala @@ -2,24 +2,6 @@ package com.github.unchama.generic object ListExtra { - /** - * Listの内容を[[B]]または[[C]]に分類し、 - * tupleとして返します。 - */ - def partitionWith[A, B, C]( - list: List[A] - )(partitioningFunction: A => Either[B, C]): (List[B], List[C]) = { - list match { - case ::(head, next) => - val partitionedNext = partitionWith(next)(partitioningFunction) - partitioningFunction(head) match { - case Left(value) => (value :: partitionedNext._1, partitionedNext._2) - case Right(value) => (partitionedNext._1, value :: partitionedNext._2) - } - case Nil => (Nil, Nil) - } - } - /** * Listの中身で条件に一致するものがあったときに`element`を先頭に追加し直します * listの中に与えられたpredicateに合致する要素があった場合、その要素をelementで写して変換します。そのような要素がなかった場合、そのままlistを返却します。 diff --git a/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricSignallingRef.scala b/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricSignallingRef.scala index a48ed7755b..a287935e9a 100644 --- a/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricSignallingRef.scala +++ b/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricSignallingRef.scala @@ -90,7 +90,7 @@ object AsymmetricSignallingRef { override val valuesAwait: Resource[F, Stream[F, A]] = changeTopic.subscribeAwait(topicQueueSize).flatMap { subscription => Resource - .liftF { + .eval { state.get.map { currentValue => subscription .through(ReorderingPipe.withInitialToken[F, A](currentValue.nextStamp)) diff --git a/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricTryableDeferred.scala b/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricTryableDeferred.scala index 17373b4c1b..d6debefe1a 100644 --- a/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricTryableDeferred.scala +++ b/src/main/scala/com/github/unchama/generic/effect/concurrent/AsymmetricTryableDeferred.scala @@ -119,7 +119,7 @@ object AsymmetricTryableDeferred { implicit F: Concurrent[F] ) extends AsymmetricTryableDeferred[F, A] { def get: F[A] = - F.suspend { + F.defer { ref.get match { case State.Set(a) => F.pure(a) @@ -168,7 +168,7 @@ object AsymmetricTryableDeferred { } def complete(a: A): F[Unit] = - F.suspend(unsafeComplete(a)) + F.defer(unsafeComplete(a)) @tailrec private def unsafeComplete(a: A): F[Unit] = diff --git a/src/main/scala/com/github/unchama/itemmigration/bukkit/targets/WorldLevelData.scala b/src/main/scala/com/github/unchama/itemmigration/bukkit/targets/WorldLevelData.scala index 54664f1147..07b646fe5b 100644 --- a/src/main/scala/com/github/unchama/itemmigration/bukkit/targets/WorldLevelData.scala +++ b/src/main/scala/com/github/unchama/itemmigration/bukkit/targets/WorldLevelData.scala @@ -109,7 +109,7 @@ object WorldLevelData { } private def queueChunkSaverFlush[F[_]](implicit F: Concurrent[F], logger: Logger) = { - import com.github.unchama.util.nms.v1_12_2.world.WorldChunkSaving + import com.github.unchama.util.nms.v1_18_2.world.WorldChunkSaving F.delay { logger.info("チャンクの保存キューの処理を要求します…") @@ -123,7 +123,7 @@ object WorldLevelData { } private def flushEntityRemovalQueue[F[_]: Sync](worldRef: Ref[F, World]): F[Unit] = { - import com.github.unchama.util.nms.v1_12_2.world.WorldChunkSaving + import com.github.unchama.util.nms.v1_18_2.world.WorldChunkSaving worldRef.get >>= WorldChunkSaving.flushEntityRemovalQueue[F] } diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/AbstractItemStackBuilder.scala b/src/main/scala/com/github/unchama/itemstackbuilder/AbstractItemStackBuilder.scala index 2048320be8..dd2db3b87a 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/AbstractItemStackBuilder.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/AbstractItemStackBuilder.scala @@ -13,12 +13,10 @@ import org.bukkit.inventory.{ItemFlag, ItemStack} * @author * karayuu */ -abstract class AbstractItemStackBuilder[-M <: ItemMeta] protected ( - material: Material, - durability: Short -) extends ItemStackBuilder { +abstract class AbstractItemStackBuilder[-M <: ItemMeta] protected (material: Material) + extends ItemStackBuilder { - private val component: IconComponent = new IconComponent(material, durability) + private val component: IconComponent = new IconComponent(material) final override def build(): ItemStack = { val itemStack = component.itemStack() diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/IconItemStackBuilder.scala b/src/main/scala/com/github/unchama/itemstackbuilder/IconItemStackBuilder.scala index 1e1a3fa24b..ff33a32f77 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/IconItemStackBuilder.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/IconItemStackBuilder.scala @@ -12,8 +12,8 @@ import org.bukkit.inventory.meta.ItemMeta * @param durability * ダメージ値 Created by karayuu on 2019/03/30 */ -class IconItemStackBuilder(material: Material, durability: Short = 0.toShort) - extends AbstractItemStackBuilder[ItemMeta](material, durability) { +class IconItemStackBuilder(material: Material) + extends AbstractItemStackBuilder[ItemMeta](material) { private var shouldShowAttribute: Boolean = false /** diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/SkullItemStackBuilder.scala b/src/main/scala/com/github/unchama/itemstackbuilder/SkullItemStackBuilder.scala index 32a5326e42..99a59f5fac 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/SkullItemStackBuilder.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/SkullItemStackBuilder.scala @@ -2,8 +2,9 @@ package com.github.unchama.itemstackbuilder import com.mojang.authlib.GameProfile import com.mojang.authlib.properties.Property +import org.apache.commons.codec.binary.Base64 import org.bukkit.inventory.meta.SkullMeta -import org.bukkit.{Bukkit, Material, SkullType} +import org.bukkit.{Bukkit, Material} import java.util.UUID @@ -11,10 +12,7 @@ import java.util.UUID * Created by karayuu on 2019/04/09 */ class SkullItemStackBuilder(private val owner: SkullOwnerReference) - extends AbstractItemStackBuilder[SkullMeta]( - Material.SKULL_ITEM, - SkullType.PLAYER.ordinal.toShort - ) { + extends AbstractItemStackBuilder[SkullMeta](Material.PLAYER_HEAD) { /** * プレーヤーがサーバーに参加したことのない場合に 頭のスキンを読み込むことができないため、そのようなケースが想定されるされる箇所では @@ -25,26 +23,33 @@ class SkullItemStackBuilder(private val owner: SkullOwnerReference) * @see * SkullMeta.setOwner * @param ownerUUID - * [Material.SKULL_ITEM] に表示するプレーヤーのUUID + * [Material.PLAYER_HEAD] に表示するプレーヤーのUUID */ def this(ownerUUID: UUID) = this(SkullOwnerUuid(ownerUUID)) - /** - * @param ownerName - * [Material.SKULL_ITEM] に表示するプレーヤーの名前 - */ - def this(ownerName: String) = this(SkullOwnerName(ownerName)) - - override def transformItemMetaOnBuild(meta: SkullMeta): Unit = { + override protected def transformItemMetaOnBuild(meta: SkullMeta): Unit = { owner match { + case SkullOwnerUuidWithName(uuid, name) => + meta.setOwningPlayer(Bukkit.getOfflinePlayer(uuid)) + val gameProfile = new GameProfile(uuid, name) + + val profileField = meta.getClass.getDeclaredField("profile") + profileField.setAccessible(true) + profileField.set(meta, gameProfile) case SkullOwnerUuid(uuid) => meta.setOwningPlayer(Bukkit.getOfflinePlayer(uuid)) - case SkullOwnerName(name) => - /** - * 参加したことのないプレーヤーはgetOfflinePlayerでデータが取れないのでこうするしか無い - */ - // noinspection ScalaDeprecation - meta.setOwner(name) + val gameProfile = new GameProfile(uuid, null) + + val textureUrl = + s"http://textures.minecraft.net/texture/${uuid.toString.replaceAll("-", "")}" + + val encodedData = Base64.encodeBase64( + String.format("{textures:{SKIN:{url:\"%s\"}}}", textureUrl).getBytes + ) + + gameProfile + .getProperties + .put("textures", new Property("textures", new String(encodedData))) /** * @see diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/SkullOwnerReference.scala b/src/main/scala/com/github/unchama/itemstackbuilder/SkullOwnerReference.scala index 9f86fd223a..5ebad9d5f8 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/SkullOwnerReference.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/SkullOwnerReference.scala @@ -4,9 +4,9 @@ import java.util.UUID sealed trait SkullOwnerReference -case class SkullOwnerUuid(uuid: UUID) extends SkullOwnerReference +case class SkullOwnerUuidWithName(uuid: UUID, name: String) extends SkullOwnerReference -case class SkullOwnerName(name: String) extends SkullOwnerReference +case class SkullOwnerUuid(uuid: UUID) extends SkullOwnerReference /** * UUID指定だけでは、カスタムテクスチャをヘッドに設定することができない場合に備えて、`TextureValue`を指定するもの diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/TippedArrowIconItemStackBuilder.scala b/src/main/scala/com/github/unchama/itemstackbuilder/TippedArrowIconItemStackBuilder.scala index 2cfde169b9..02113dd995 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/TippedArrowIconItemStackBuilder.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/TippedArrowIconItemStackBuilder.scala @@ -6,7 +6,7 @@ import org.bukkit.inventory.meta.PotionMeta import org.bukkit.potion.{PotionData, PotionType} class TippedArrowIconItemStackBuilder(val potionData: PotionData) - extends AbstractItemStackBuilder[PotionMeta](Material.TIPPED_ARROW, 0) { + extends AbstractItemStackBuilder[PotionMeta](Material.TIPPED_ARROW) { def this(potionType: PotionType) = this(new PotionData(potionType)) diff --git a/src/main/scala/com/github/unchama/itemstackbuilder/component/IconComponent.scala b/src/main/scala/com/github/unchama/itemstackbuilder/component/IconComponent.scala index f36c28c4b1..9164c87019 100644 --- a/src/main/scala/com/github/unchama/itemstackbuilder/component/IconComponent.scala +++ b/src/main/scala/com/github/unchama/itemstackbuilder/component/IconComponent.scala @@ -13,7 +13,7 @@ import scala.jdk.javaapi.CollectionConverters.asJava * * Created by karayuu on 2019/04/09 */ -class IconComponent(val material: Material, private val durability: Short = 0.toShort) { +class IconComponent(val material: Material) { var title: String = Bukkit.getItemFactory.getItemMeta(material).ifNotNull(_.getDisplayName) var lore: List[String] = Nil @@ -24,7 +24,7 @@ class IconComponent(val material: Material, private val durability: Short = 0.to var itemFlagSet: Set[ItemFlag] = Set() - def itemStack(): ItemStack = new ItemStack(material, amount, durability) + def itemStack(): ItemStack = new ItemStack(material, amount) def itemMeta(): ItemMeta = { val meta = Bukkit.getItemFactory.getItemMeta(material) diff --git a/src/main/scala/com/github/unchama/minecraft/bukkit/actions/BroadcastBukkitMessage.scala b/src/main/scala/com/github/unchama/minecraft/bukkit/actions/BroadcastBukkitMessage.scala index a94d055081..42b34164da 100644 --- a/src/main/scala/com/github/unchama/minecraft/bukkit/actions/BroadcastBukkitMessage.scala +++ b/src/main/scala/com/github/unchama/minecraft/bukkit/actions/BroadcastBukkitMessage.scala @@ -1,10 +1,10 @@ package com.github.unchama.minecraft.bukkit.actions -import cats.effect.{Sync, SyncIO} +import cats.effect.SyncIO import com.github.unchama.minecraft.actions.{BroadcastMinecraftMessage, OnMinecraftServerThread} import org.bukkit.Bukkit -class BroadcastBukkitMessage[F[_]: Sync: OnMinecraftServerThread] +class BroadcastBukkitMessage[F[_]: OnMinecraftServerThread] extends BroadcastMinecraftMessage[F] { import scala.jdk.CollectionConverters._ @@ -19,7 +19,7 @@ class BroadcastBukkitMessage[F[_]: Sync: OnMinecraftServerThread] object BroadcastBukkitMessage { - def apply[F[_]: Sync: OnMinecraftServerThread]: BroadcastMinecraftMessage[F] = + def apply[F[_]: OnMinecraftServerThread]: BroadcastMinecraftMessage[F] = new BroadcastBukkitMessage[F] } diff --git a/src/main/scala/com/github/unchama/minecraft/bukkit/actions/GetConnectedBukkitPlayers.scala b/src/main/scala/com/github/unchama/minecraft/bukkit/actions/GetConnectedBukkitPlayers.scala index 0684e38bbf..df103ae51c 100644 --- a/src/main/scala/com/github/unchama/minecraft/bukkit/actions/GetConnectedBukkitPlayers.scala +++ b/src/main/scala/com/github/unchama/minecraft/bukkit/actions/GetConnectedBukkitPlayers.scala @@ -1,11 +1,11 @@ package com.github.unchama.minecraft.bukkit.actions -import cats.effect.{Sync, SyncIO} +import cats.effect.SyncIO import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import org.bukkit.Bukkit import org.bukkit.entity.Player -class GetConnectedBukkitPlayers[F[_]: Sync: OnMinecraftServerThread] +class GetConnectedBukkitPlayers[F[_]: OnMinecraftServerThread] extends GetConnectedPlayers[F, Player] { import scala.jdk.CollectionConverters._ diff --git a/src/main/scala/com/github/unchama/minecraft/bukkit/objects/BukkitMaterial.scala b/src/main/scala/com/github/unchama/minecraft/bukkit/objects/BukkitMaterial.scala index 67e7db1990..90c6db0fd5 100644 --- a/src/main/scala/com/github/unchama/minecraft/bukkit/objects/BukkitMaterial.scala +++ b/src/main/scala/com/github/unchama/minecraft/bukkit/objects/BukkitMaterial.scala @@ -5,6 +5,6 @@ import org.bukkit.Material import org.bukkit.inventory.ItemStack class BukkitMaterial extends MinecraftMaterial[Material, ItemStack] { - override def toItemStack(material: Material, durability: Short): ItemStack = - new ItemStack(material, 1, durability) + override def toItemStack(material: Material): ItemStack = + new ItemStack(material, 1) } diff --git a/src/main/scala/com/github/unchama/minecraft/objects/MinecraftMaterial.scala b/src/main/scala/com/github/unchama/minecraft/objects/MinecraftMaterial.scala index 8446c9c693..e2b567916b 100644 --- a/src/main/scala/com/github/unchama/minecraft/objects/MinecraftMaterial.scala +++ b/src/main/scala/com/github/unchama/minecraft/objects/MinecraftMaterial.scala @@ -5,6 +5,6 @@ package com.github.unchama.minecraft.objects */ trait MinecraftMaterial[Material, ItemStack] { - def toItemStack(material: Material, durability: Short): ItemStack + def toItemStack(material: Material): ItemStack } diff --git a/src/main/scala/com/github/unchama/seichiassist/MaterialSets.scala b/src/main/scala/com/github/unchama/seichiassist/MaterialSets.scala index 5f8a9a6498..426abbe212 100644 --- a/src/main/scala/com/github/unchama/seichiassist/MaterialSets.scala +++ b/src/main/scala/com/github/unchama/seichiassist/MaterialSets.scala @@ -7,151 +7,150 @@ import org.bukkit.block.Block import org.bukkit.inventory.ItemStack object MaterialSets { - val fortuneMaterials: Set[Material] = Set( - Material.COAL_ORE, - Material.DIAMOND_ORE, - Material.LAPIS_ORE, - Material.EMERALD_ORE, - Material.REDSTONE_ORE, - Material.GLOWING_REDSTONE_ORE, - Material.QUARTZ_ORE, - Material.MELON_BLOCK, - Material.SEA_LANTERN - ) + + private val notApplicableSeichiSkillMaterials = + Set( + Material.WATER, + Material.LAVA, + Material.AIR, + Material.BEDROCK, + Material.TORCH, + Material.SOUL_TORCH, + Material.REDSTONE_TORCH, + Material.REPEATER, + Material.COMPARATOR, + Material.END_ROD, + Material.FIRE, + Material.WHITE_CARPET, + Material.ORANGE_CARPET, + Material.MAGENTA_CARPET, + Material.LIGHT_BLUE_CARPET, + Material.YELLOW_CARPET, + Material.LIME_CARPET, + Material.PINK_CARPET, + Material.GRAY_CARPET, + Material.LIGHT_GRAY_CARPET, + Material.CYAN_CARPET, + Material.PURPLE_CARPET, + Material.BLUE_CARPET, + Material.BROWN_CARPET, + Material.GREEN_CARPET, + Material.RED_CARPET, + Material.BLACK_CARPET, + Material.WHITE_BANNER, + Material.ORANGE_BANNER, + Material.MAGENTA_BANNER, + Material.LIGHT_BLUE_BANNER, + Material.YELLOW_BANNER, + Material.LIME_BANNER, + Material.PINK_BANNER, + Material.GRAY_BANNER, + Material.LIGHT_GRAY_BANNER, + Material.CYAN_BANNER, + Material.PURPLE_BANNER, + Material.BLUE_BANNER, + Material.BROWN_BANNER, + Material.GREEN_BANNER, + Material.RED_BANNER, + Material.BLACK_BANNER, + Material.RAIL, + Material.POWERED_RAIL, + Material.ACTIVATOR_RAIL, + Material.DETECTOR_RAIL, + Material.REDSTONE, + Material.REDSTONE_WIRE, + Material.TRIPWIRE_HOOK, + Material.OAK_WALL_SIGN, + Material.SPRUCE_WALL_SIGN, + Material.BIRCH_WALL_SIGN, + Material.ACACIA_WALL_SIGN, + Material.JUNGLE_WALL_SIGN, + Material.DARK_OAK_WALL_SIGN, + Material.WARPED_WALL_SIGN, + Material.OAK_SIGN, + Material.SPRUCE_SIGN, + Material.BIRCH_SIGN, + Material.ACACIA_SIGN, + Material.JUNGLE_SIGN, + Material.DARK_OAK_SIGN, + Material.WARPED_SIGN, + Material.LEVER, + Material.STONE_BUTTON, + Material.POLISHED_BLACKSTONE_BUTTON, + Material.OAK_BUTTON, + Material.SPRUCE_BUTTON, + Material.BIRCH_BUTTON, + Material.JUNGLE_BUTTON, + Material.ACACIA_BUTTON, + Material.DARK_OAK_BUTTON, + Material.CRIMSON_BUTTON, + Material.WARPED_BUTTON, + Material.STONE_PRESSURE_PLATE, + Material.POLISHED_BLACKSTONE_PRESSURE_PLATE, + Material.LIGHT_WEIGHTED_PRESSURE_PLATE, + Material.HEAVY_WEIGHTED_PRESSURE_PLATE, + Material.OAK_PRESSURE_PLATE, + Material.SPRUCE_PRESSURE_PLATE, + Material.BIRCH_PRESSURE_PLATE, + Material.JUNGLE_PRESSURE_PLATE, + Material.ACACIA_PRESSURE_PLATE, + Material.DARK_OAK_PRESSURE_PLATE, + Material.CRIMSON_PRESSURE_PLATE, + Material.WARPED_PRESSURE_PLATE, + Material.DROPPER, + Material.PISTON, + Material.OAK_SAPLING, + Material.SPRUCE_SAPLING, + Material.BIRCH_SAPLING, + Material.JUNGLE_SAPLING, + Material.ACACIA_SAPLING, + Material.DARK_OAK_SAPLING, + Material.DEAD_BUSH, + Material.SEA_PICKLE, + Material.CORNFLOWER, + Material.LILY_OF_THE_VALLEY, + Material.WITHER_ROSE, + Material.SPORE_BLOSSOM, + Material.IRON_BLOCK, + Material.COPPER_BLOCK, + Material.DIAMOND_BLOCK, + Material.NETHERITE_BLOCK, + Material.FLOWER_POT, + Material.ANVIL, + Material.BEACON, + Material.ENCHANTING_TABLE, + Material.LADDER, + Material.SNOW, + Material.WITHER_SKELETON_SKULL, + Material.DRAGON_HEAD, + Material.PLAYER_HEAD, + Material.SHULKER_BOX, + Material.JUKEBOX, + Material.HOPPER, + Material.DAYLIGHT_DETECTOR, + Material.OBSERVER, + Material.CAKE, + Material.NOTE_BLOCK, + Material.REDSTONE_LAMP, + Material.EMERALD_BLOCK, + Material.COAL_BLOCK, + Material.LAPIS_BLOCK + ) // このMaterialは整地スキルに対応する - val materials: Set[Material] = Set( - Material.STONE, - Material.NETHERRACK, - Material.NETHER_BRICK, - Material.DIRT, - Material.GRAVEL, - Material.LOG, - Material.LOG_2, - Material.GRASS, - Material.IRON_ORE, - Material.GOLD_ORE, - Material.SAND, - Material.SANDSTONE, - Material.RED_SANDSTONE, - Material.END_BRICKS, - Material.ENDER_STONE, - Material.ICE, - Material.PACKED_ICE, - Material.OBSIDIAN, - Material.MAGMA, - Material.SOUL_SAND, - Material.LEAVES, - Material.LEAVES_2, - Material.CLAY, - Material.STAINED_CLAY, - Material.COBBLESTONE, - Material.MOSSY_COBBLESTONE, - Material.HARD_CLAY, - Material.MONSTER_EGGS, - Material.WEB, - Material.WOOD, - Material.FENCE, - Material.DARK_OAK_FENCE, - Material.RAILS, - Material.MYCEL, - Material.SNOW_BLOCK, - Material.HUGE_MUSHROOM_1, - Material.HUGE_MUSHROOM_2, - Material.BONE_BLOCK, - Material.PURPUR_BLOCK, - Material.PURPUR_PILLAR, - Material.SEA_LANTERN, - Material.PRISMARINE, - Material.SMOOTH_BRICK, - Material.GLOWSTONE, - Material.STAINED_GLASS, - Material.STAINED_GLASS_PANE, - Material.THIN_GLASS, - Material.GLASS, - Material.WOOD_STAIRS, - Material.BIRCH_WOOD_STAIRS, - Material.SPRUCE_WOOD_STAIRS, - Material.ACACIA_STAIRS, - Material.DARK_OAK_STAIRS, - Material.BIRCH_FENCE, - Material.SPRUCE_FENCE, - Material.ACACIA_FENCE, - Material.FENCE_GATE, - Material.BIRCH_FENCE_GATE, - Material.SPRUCE_FENCE_GATE, - Material.ACACIA_FENCE_GATE, - Material.DARK_OAK_FENCE_GATE, - Material.COBBLESTONE_STAIRS, - Material.SANDSTONE_STAIRS, - Material.BRICK_STAIRS, - Material.QUARTZ_STAIRS, - Material.BOOKSHELF, - Material.IRON_FENCE, - Material.ICE, - Material.WOOL, - Material.GOLD_BLOCK, - Material.END_ROD, - Material.PUMPKIN, - Material.MELON_BLOCK, - Material.STONE_SLAB2, - Material.SPONGE, - Material.SOIL, - Material.GRASS_PATH, - Material.MOB_SPAWNER, - Material.WORKBENCH, - Material.FURNACE, - Material.QUARTZ_BLOCK, - Material.CHEST, - Material.TRAPPED_CHEST, - Material.NETHER_FENCE, - Material.NETHER_BRICK_STAIRS, - Material.CAULDRON, - Material.END_ROD, - Material.PURPUR_STAIRS, - Material.END_BRICKS, - Material.PURPUR_SLAB, - Material.ENDER_CHEST, - Material.PURPUR_SLAB, - Material.STEP, - Material.DOUBLE_STEP, - Material.ENDER_PORTAL_FRAME, - Material.ENDER_PORTAL, - Material.VINE, - // #913 - Material.BED_BLOCK, - Material.TRAP_DOOR, - Material.IRON_TRAPDOOR, - Material.CARPET, - Material.IRON_DOOR_BLOCK, - // 木のドアはそれぞれMaterialが別れている - Material.WOODEN_DOOR, - Material.ACACIA_DOOR, - Material.BIRCH_DOOR, - Material.DARK_OAK_DOOR, - Material.JUNGLE_DOOR, - Material.SPRUCE_DOOR, - Material.SMOOTH_STAIRS, - Material.BREWING_STAND, - Material.WOOD_STEP, - Material.TNT, - // #1027,#1159 - Material.WOOD_STEP, - Material.WOOD_DOUBLE_STEP, - Material.DISPENSER, - Material.PISTON_STICKY_BASE, - Material.WEB - ) ++ fortuneMaterials + // TODO(1.18): 1.18のコードに書き換えるときに、materialsの列挙をホワイトリスト方式からブラックリスト方式に書き換えたので、 + // 元のコードとMaterial.values()のdiffを取って、なぜホワイトリスト方式が採用されたかを考えてみる + val materials: Set[Material] = Material.values().toSet.diff(notApplicableSeichiSkillMaterials) // これらのマテリアルを持つブロックは破壊を整地量に計上しない val exclude: Set[Material] = Set( - Material.GRASS_PATH, - Material.SOIL, - Material.MOB_SPAWNER, + Material.DIRT_PATH, + Material.FARMLAND, + Material.SPAWNER, Material.CAULDRON, Material.ENDER_CHEST, - Material.ENDER_PORTAL_FRAME, - Material.ENDER_PORTAL + Material.END_PORTAL_FRAME, + Material.END_PORTAL ) val materialsToCountBlockBreak: Set[Material] = materials -- exclude @@ -163,21 +162,25 @@ object MaterialSets { * * 例えば石をシャベルで掘った時にも、ツールのエンチャントを保ったままダイヤツルハシで掘ったものとして計算し、 結果得られるスタック数が最大のものが結果として採用される。 */ - val breakTestToolMaterials: Seq[Material] = - Seq(Material.DIAMOND_PICKAXE, Material.DIAMOND_AXE, Material.DIAMOND_SPADE) + private val breakTestToolMaterials: Set[Material] = + Set(Material.DIAMOND_PICKAXE, Material.DIAMOND_AXE, Material.DIAMOND_SHOVEL) val breakToolMaterials: Set[Material] = Set( - Material.WOOD_PICKAXE, - Material.WOOD_SPADE, + Material.WOODEN_AXE, + Material.WOODEN_PICKAXE, + Material.WOODEN_SHOVEL, Material.STONE_PICKAXE, Material.STONE_AXE, - Material.STONE_SPADE, + Material.STONE_SHOVEL, Material.IRON_PICKAXE, Material.IRON_AXE, - Material.IRON_SPADE, - Material.GOLD_PICKAXE, - Material.GOLD_AXE, - Material.GOLD_SPADE + Material.IRON_SHOVEL, + Material.GOLDEN_PICKAXE, + Material.GOLDEN_AXE, + Material.GOLDEN_SHOVEL, + Material.NETHERITE_PICKAXE, + Material.NETHERITE_AXE, + Material.NETHERITE_SHOVEL ) ++ breakTestToolMaterials val cancelledMaterials: Set[Material] = Set( @@ -189,10 +192,15 @@ object MaterialSets { Material.BEACON, Material.BIRCH_DOOR, Material.BIRCH_FENCE_GATE, - Material.BIRCH_WOOD_STAIRS, - Material.BOAT, + Material.BIRCH_STAIRS, + Material.BIRCH_BOAT, + Material.OAK_BOAT, + Material.ACACIA_BOAT, + Material.JUNGLE_BOAT, + Material.DARK_OAK_BOAT, + Material.SPRUCE_BOAT, Material.FURNACE, - Material.WORKBENCH, + Material.CRAFTING_TABLE, Material.HOPPER, Material.MINECART ) @@ -200,7 +208,19 @@ object MaterialSets { val transparentMaterials: Set[Material] = Set(Material.BEDROCK, Material.AIR) val gravityMaterials: Set[Material] = - Set(Material.LOG, Material.LOG_2, Material.LEAVES, Material.LEAVES_2) + Set( + Material.ACACIA_LOG, + Material.BIRCH_LOG, + Material.DARK_OAK_LOG, + Material.JUNGLE_LOG, + Material.OAK_LOG, + Material.OAK_LEAVES, + Material.BIRCH_LEAVES, + Material.JUNGLE_LEAVES, + Material.ACACIA_LEAVES, + Material.DARK_OAK_LEAVES, + Material.SPRUCE_LEAVES + ) val fluidMaterials: Set[Material] = Set(Material.WATER, Material.LAVA) diff --git a/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala b/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala index b77a5063e8..1fdabf523d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala +++ b/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala @@ -59,6 +59,7 @@ import com.github.unchama.seichiassist.menus.{BuildMainMenu, TopLevelRouter} import com.github.unchama.seichiassist.meta.subsystem.Subsystem import com.github.unchama.seichiassist.subsystems._ import com.github.unchama.seichiassist.subsystems.anywhereender.AnywhereEnderChestAPI +import com.github.unchama.seichiassist.subsystems.autosave.application.SystemConfiguration import com.github.unchama.seichiassist.subsystems.breakcount.{BreakCountAPI, BreakCountReadAPI} import com.github.unchama.seichiassist.subsystems.breakcountbar.BreakCountBarAPI import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.BreakSkillTargetConfigAPI @@ -106,7 +107,7 @@ import org.bukkit.plugin.java.JavaPlugin import org.bukkit.{Bukkit, Location} import org.flywaydb.core.Flyway import org.slf4j.Logger -import org.slf4j.impl.JDK14LoggerFactory +import org.slf4j.jul.JDK14LoggerFactory import java.util.UUID import java.util.logging.LogManager @@ -221,7 +222,6 @@ class SeichiAssist extends JavaPlugin() { private lazy val itemMigrationSystem: subsystems.itemmigration.System[IO] = { import PluginExecutionContexts.asyncShift - implicit val effectEnvironment: EffectEnvironment = DefaultEffectEnvironment subsystems.itemmigration.System.wired[IO, SyncIO].unsafeRunSync() } @@ -259,6 +259,9 @@ class SeichiAssist extends JavaPlugin() { implicit val globalNotification: DiscordNotificationAPI[IO] = discordNotificationSystem.globalNotification + implicit val getConnectedPlayers: GetConnectedPlayers[IO, Player] = + new GetConnectedBukkitPlayers[IO] + subsystems.buildcount.System.wired[IO, SyncIO].unsafeRunSync() } @@ -344,8 +347,6 @@ class SeichiAssist extends JavaPlugin() { import PluginExecutionContexts.{asyncShift, onMainThread, timer} implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect(asyncShift) - implicit val getConnectedPlayers: GetConnectedPlayers[IO, Player] = - new GetConnectedBukkitPlayers[IO] subsystems.gachapoint.System.wired[IO, SyncIO](breakCountSystem.api).unsafeRunSync() } @@ -385,7 +386,6 @@ class SeichiAssist extends JavaPlugin() { private lazy val presentSystem: Subsystem[IO] = { import PluginExecutionContexts.{asyncShift, onMainThread} - implicit val effectEnvironment: EffectEnvironment = DefaultEffectEnvironment implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect(asyncShift) implicit val uuidToLastSeenName: UuidToLastSeenName[IO] = new GlobalPlayerAccessor[IO] subsystems.present.System.wired @@ -405,7 +405,7 @@ class SeichiAssist extends JavaPlugin() { mineStackSystem.api private lazy val sharedInventorySystem: subsystems.sharedinventory.System[IO] = { - import PluginExecutionContexts.timer + import PluginExecutionContexts.{timer, onMainThread} subsystems.sharedinventory.System.wired[IO, IO].unsafeRunSync() } @@ -417,6 +417,8 @@ class SeichiAssist extends JavaPlugin() { private lazy val gachaSystem: subsystems.gacha.System[IO, Player] = { implicit val gachaTicketAPI: GachaTicketAPI[IO] = gachaTicketSystem.api + implicit val getConnectedPlayers: GetConnectedPlayers[IO, Player] = + new GetConnectedBukkitPlayers[IO] subsystems.gacha.System.wired[IO] } @@ -495,6 +497,15 @@ class SeichiAssist extends JavaPlugin() { private lazy val gridRegionSystem: subsystems.gridregion.System[IO, Player, Location] = subsystems.gridregion.System.wired[IO, SyncIO].unsafeRunSync() + private lazy val joinAndQuitMessenger: Subsystem[IO] = + subsystems.joinandquitmessenger.System.wired[IO] + + private lazy val elevatorSystem: Subsystem[IO] = { + implicit val effectEnvironment: EffectEnvironment = DefaultEffectEnvironment + + subsystems.elevator.System.wired[IO] + } + private lazy val wiredSubsystems: List[Subsystem[IO]] = List( mebiusSystem, expBottleStackSystem, @@ -532,7 +543,9 @@ class SeichiAssist extends JavaPlugin() { consumeGachaTicketSystem, openirontrapdoor.System.wired, gridRegionSystem, - breakSkillTargetConfigSystem + breakSkillTargetConfigSystem, + joinAndQuitMessenger, + elevatorSystem ) private lazy val buildAssist: BuildAssist = { @@ -602,8 +615,8 @@ class SeichiAssist extends JavaPlugin() { // BungeeCordとのI/O Bukkit .getMessenger - .registerIncomingPluginChannel(this, "SeichiAssistBungee", new BungeeReceiver(this)) - Bukkit.getMessenger.registerOutgoingPluginChannel(this, "SeichiAssistBungee") + .registerIncomingPluginChannel(this, "BungeeCord", new BungeeReceiver(this)) + Bukkit.getMessenger.registerOutgoingPluginChannel(this, "BungeeCord") // コンフィグ系の設定は全てConfig.javaに移動 SeichiAssist.seichiAssistConfig = Config.loadFrom(this) @@ -760,7 +773,7 @@ class SeichiAssist extends JavaPlugin() { new ChatInterceptor(List(globalChatInterceptionScope)), new MenuHandler(), SpawnRegionProjectileInterceptor, - Y5DoubleSlabCanceller + YMinus59DoubleSlabCanceller ).concat(bungeeSemaphoreResponderSystem.listenersToBeRegistered) .concat { Seq( @@ -835,8 +848,12 @@ class SeichiAssist extends JavaPlugin() { implicit val ioConcurrent: ConcurrentEffect[IO] = IO.ioConcurrentEffect(asyncShift) implicit val sendMessages: SendMinecraftMessage[IO, Player] = new SendBukkitMessage[IO] - val dragonNightTimeProcess: IO[Nothing] = + val dragonNightTimeProcess: IO[Nothing] = { + implicit val getConnectedPlayers: GetConnectedPlayers[IO, Player] = + new GetConnectedBukkitPlayers[IO] + subsystems.dragonnighttime.System.backgroundProcess[IO, SyncIO, Player] + } val halfHourRankingRoutineOption: Option[IO[Nothing]] = // 公共鯖(7)と建築鯖(8)なら整地量のランキングを表示する必要はない @@ -851,9 +868,12 @@ class SeichiAssist extends JavaPlugin() { subsystems.seichilevelupmessage.System.backgroundProcess[IO, SyncIO, Player] val autoSaveProcess: IO[Nothing] = { - val configuration = seichiAssistConfig.getAutoSaveSystemConfiguration + implicit val configuration: SystemConfiguration = + seichiAssistConfig.getAutoSaveSystemConfiguration + implicit val getConnectedPlayers: GetConnectedPlayers[IO, Player] = + new GetConnectedBukkitPlayers[IO] - subsystems.autosave.System.backgroundProcess[IO, IO](configuration) + subsystems.autosave.System.backgroundProcess[IO] } val programs: List[IO[Nothing]] = diff --git a/src/main/scala/com/github/unchama/seichiassist/SkullOwners.scala b/src/main/scala/com/github/unchama/seichiassist/SkullOwners.scala index d4ca6a2313..8e41efdec6 100644 --- a/src/main/scala/com/github/unchama/seichiassist/SkullOwners.scala +++ b/src/main/scala/com/github/unchama/seichiassist/SkullOwners.scala @@ -1,25 +1,47 @@ package com.github.unchama.seichiassist -import com.github.unchama.itemstackbuilder.{SkullOwnerName, SkullOwnerReference} +import com.github.unchama.itemstackbuilder.{SkullOwnerReference, SkullOwnerUuidWithName} + +import java.util.UUID /** * プレーヤーヘッドにownerとして設定されるプレーヤー達に関する定数を保持するオブジェクト */ object SkullOwners { - val whitecat_haru: SkullOwnerReference = "whitecat_haru".asSkullOwnerReference() - val unchama: SkullOwnerReference = "unchama".asSkullOwnerReference() - - val MHF_ArrowUp: SkullOwnerReference = "MHF_ArrowUp".asSkullOwnerReference() - val MHF_ArrowDown: SkullOwnerReference = "MHF_ArrowDown".asSkullOwnerReference() - val MHF_ArrowLeft: SkullOwnerReference = "MHF_ArrowLeft".asSkullOwnerReference() - val MHF_ArrowRight: SkullOwnerReference = "MHF_ArrowRight".asSkullOwnerReference() + val whitecat_haru: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("394f76df-883d-4855-9e6a-d1a800c1ab1c"), + "whitecat_haru" + ) + val unchama: SkullOwnerReference = + SkullOwnerUuidWithName(UUID.fromString("b66cc3f6-a045-42ad-b4b8-320f20caf140"), "unchama") - val MHF_Exclamation: SkullOwnerReference = "MHF_Exclamation".asSkullOwnerReference() + val MHF_ArrowUp: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("fef039ef-e6cd-4987-9c84-26a3e6134277"), + "MHF_ArrowUp" + ) + val MHF_ArrowDown: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("68f59b9b-5b0b-4b05-a9f2-e1d1405aa348"), + "MHF_ArrowDown" + ) + val MHF_ArrowLeft: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("a68f0b64-8d14-4000-a95f-4b9ba14f8df9"), + "MHF_ArrowLeft" + ) + val MHF_ArrowRight: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("50c8510b-5ea0-4d60-be9a-7d542d6cd156"), + "MHF_ArrowRight" + ) - val MHF_Villager: SkullOwnerReference = "MHF_Villager".asSkullOwnerReference() + val MHF_Exclamation: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("d3c47f6f-ae3a-45c1-ad7c-e2c762b03ae6"), + "MHF_Exclamation" + ) - implicit class StringOps(val string: String) { - def asSkullOwnerReference(): SkullOwnerReference = SkullOwnerName(string) - } + val MHF_Villager: SkullOwnerReference = SkullOwnerUuidWithName( + UUID.fromString("bd482739-767c-45dc-a1f8-c33c40530952"), + "MHF_Villager" + ) + val MHF_TNT: SkullOwnerReference = + SkullOwnerUuidWithName(UUID.fromString("d43af93c-c330-4a3d-bab8-ee74234a011a"), "MHF_TNT") } diff --git a/src/main/scala/com/github/unchama/seichiassist/achievement/AchievementConditions.scala b/src/main/scala/com/github/unchama/seichiassist/achievement/AchievementConditions.scala index bdac55431f..0731288c0e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/achievement/AchievementConditions.scala +++ b/src/main/scala/com/github/unchama/seichiassist/achievement/AchievementConditions.scala @@ -214,7 +214,7 @@ object AchievementConditions { import scala.util.chaining._ stack != null && - stack.getType == Material.SKULL_ITEM && + stack.getType == Material.PLAYER_HEAD && stack .getItemMeta .asInstanceOf[SkullMeta] diff --git a/src/main/scala/com/github/unchama/seichiassist/commands/HatCommand.scala b/src/main/scala/com/github/unchama/seichiassist/commands/HatCommand.scala index 5d09be1140..1985c70e42 100644 --- a/src/main/scala/com/github/unchama/seichiassist/commands/HatCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/commands/HatCommand.scala @@ -4,6 +4,8 @@ import cats.effect.IO import com.github.unchama.seichiassist.commands.contextual.builder.BuilderTemplates import com.github.unchama.targetedeffect.commandsender.MessageEffect import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffect} +import com.github.unchama.targetedeffect.TargetedEffect.emptyEffect +import org.bukkit.Material import org.bukkit.command.TabExecutor import org.bukkit.entity.Player @@ -16,14 +18,18 @@ object HatCommand { val currentHeadItem = player.getInventory.getHelmet IO { - SequentialEffect( - TargetedEffect.delay[IO, Player] { p => - // swapすることでアイテムの過不足を防ぐ - p.getInventory.setHelmet(mainHandItem) - p.getInventory.setItemInOffHand(currentHeadItem) - }, - MessageEffect("メインハンドに持っていたアイテムを頭にかぶりました。") - ) + if (mainHandItem.getType != Material.AIR) { + SequentialEffect( + TargetedEffect.delay[IO, Player] { p => + // swapすることでアイテムの過不足を防ぐ + p.getInventory.setHelmet(mainHandItem) + p.getInventory.setItemInMainHand(currentHeadItem) + }, + MessageEffect("メインハンドに持っていたアイテムを頭にかぶりました。") + ) + } else { + emptyEffect + } } } .asNonBlockingTabExecutor() diff --git a/src/main/scala/com/github/unchama/seichiassist/commands/RegionOwnerTransferCommand.scala b/src/main/scala/com/github/unchama/seichiassist/commands/RegionOwnerTransferCommand.scala index 08135a03bd..c732886a91 100644 --- a/src/main/scala/com/github/unchama/seichiassist/commands/RegionOwnerTransferCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/commands/RegionOwnerTransferCommand.scala @@ -1,69 +1,72 @@ package com.github.unchama.seichiassist.commands +import cats.data.Kleisli import cats.effect.IO import com.github.unchama.contextualexecutor.builder.Parsers import com.github.unchama.seichiassist.commands.contextual.builder.BuilderTemplates.playerCommandBuilder -import com.github.unchama.targetedeffect.TargetedEffect -import com.github.unchama.targetedeffect.commandsender.MessageEffect +import com.github.unchama.targetedeffect.TargetedEffectF +import com.github.unchama.targetedeffect.commandsender.MessageEffectF import com.github.unchama.util.external.WorldGuardWrapper import com.sk89q.worldguard.bukkit.WorldGuardPlugin import com.sk89q.worldguard.protection.regions.ProtectedRegion import org.bukkit.Bukkit import org.bukkit.command.TabExecutor import org.bukkit.entity.Player -import shapeless.{HNil, ::} +import shapeless.{::, HNil} object RegionOwnerTransferCommand { import com.github.unchama.contextualexecutor.builder.ParserResponse._ val executor: TabExecutor = playerCommandBuilder .thenParse(Parsers.identity) - .thenParse(recipientName => { + .thenParse { recipientName => Bukkit.getPlayer(recipientName) match { case recipient: Player => succeedWith(recipient) case _ => failWith(s"${recipientName}というプレイヤーはサーバーに参加したことがありません。") } - }) - .buildWithExecutionF { context => - val (regionName :: newOwner :: HNil) = context.args.parsed + } + .buildWithExecutionCSEffect { context => + val regionName :: newOwner :: HNil = context.args.parsed val sender = context.sender - IO { - WorldGuardPlugin.inst().getRegionManager(sender.getWorld).getRegion(regionName) - }.flatMap { region => - if (region == null) { - MessageEffect(s"${regionName}という名前の保護は存在しません。").run(sender) - } else { - attemptRegionTransfer(sender, newOwner, region) - } + val region = + WorldGuardWrapper.findByRegionName(regionName) + + region match { + case Some(region) => + attemptRegionTransfer(sender, newOwner, region.getRegion(regionName)) + case None => MessageEffectF[IO](s"${regionName}という名前の保護は存在しません。") } } .asNonBlockingTabExecutor() + import cats.implicits._ + private def attemptRegionTransfer( donner: Player, recipient: Player, region: ProtectedRegion - ): IO[TargetedEffect[Player]] = IO { - val owners = region.getOwners - val regionWorld = donner.getWorld - - val recipientLimit = WorldGuardWrapper.getMaxRegionCount(recipient, regionWorld) - val recipientHas = WorldGuardWrapper.getNumberOfRegions(recipient, regionWorld) - + ): TargetedEffectF[IO, Player] = (for { + owners <- Kleisli.liftF(IO(region.getOwners)) + regionWorld <- Kleisli.liftF(IO(donner.getWorld)) + recipientLimit <- Kleisli.liftF(IO(WorldGuardWrapper.getMaxRegion(recipient, regionWorld))) + recipientHas <- Kleisli.liftF( + IO(WorldGuardWrapper.getNumberOfRegions(recipient, regionWorld)) + ) + } yield { if (recipientLimit <= recipientHas) { - MessageEffect(s"相手が保護を上限 ($recipientLimit)まで所持しているため権限を譲渡できません。") + MessageEffectF[IO](s"相手が保護を上限 ($recipientLimit)まで所持しているため権限を譲渡できません。") } else if (owners.contains(WorldGuardPlugin.inst().wrapPlayer(recipient))) { - MessageEffect("相手がすでにオーナーであるため権限を譲渡できません。") + MessageEffectF[IO]("相手がすでにオーナーであるため権限を譲渡できません。") } else if (!owners.contains(donner.getUniqueId)) { - MessageEffect("オーナーではないため権限を譲渡できません。") + MessageEffectF[IO]("オーナーではないため権限を譲渡できません。") } else if (owners.size() != 1) { - MessageEffect("オーナーが複数人いるため権限を譲渡できません。") + MessageEffectF[IO]("オーナーが複数人いるため権限を譲渡できません。") } else { owners.clear() owners.addPlayer(recipient.getUniqueId) - MessageEffect(s"${recipient.getName}に${region.getId}のオーナー権限を譲渡しました。") + MessageEffectF[IO](s"${recipient.getName}に${region.getId}のオーナー権限を譲渡しました。") } - } + }).flatten } diff --git a/src/main/scala/com/github/unchama/seichiassist/commands/RmpCommand.scala b/src/main/scala/com/github/unchama/seichiassist/commands/RmpCommand.scala index cbc782e1a1..5e781c3df8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/commands/RmpCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/commands/RmpCommand.scala @@ -12,7 +12,7 @@ import com.github.unchama.seichiassist.{ManagedWorld, SeichiAssist} import com.github.unchama.targetedeffect import com.github.unchama.targetedeffect.TargetedEffect import com.github.unchama.targetedeffect.commandsender.MessageEffect -import com.github.unchama.util.external.ExternalPlugins +import com.github.unchama.util.external.WorldGuardWrapper import com.sk89q.worldguard.protection.regions.ProtectedRegion import org.bukkit.ChatColor._ import org.bukkit.command.{CommandSender, ConsoleCommandSender, TabExecutor} @@ -78,13 +78,7 @@ object RmpCommand { case None | Some(false) => MessageEffect(s"第1整地以外の保護をかけて整地する整地ワールドでのみ使用出来ます") case Some(true) => getOldRegionsIn(world, days).map { removalTargets => - removalTargets.foreach { target => - ExternalPlugins - .getWorldGuard - .getRegionContainer - .get(world) - .removeRegion(target.getId) - } + removalTargets.foreach(WorldGuardWrapper.removeByProtectedRegionRegion(world, _)) // メッセージ生成 if (removalTargets.isEmpty) { @@ -112,15 +106,15 @@ object RmpCommand { return Left(MessageEffect(s"${RED}データベースアクセスに失敗しました。")) } - val regions = ExternalPlugins.getWorldGuard.getRegionContainer.get(world).getRegions.asScala + val regions = WorldGuardWrapper.getRegions(world) - val oldRegions = regions - .values - .filter { region => - region.getId != "__global__" && region.getId != "spawn" && - region.getOwners.getUniqueIds.asScala.forall(leavers.contains(_)) - } - .toList + val oldRegions = regions.filter { region => + region.getId != "spawn" && region + .getOwners + .getUniqueIds + .asScala + .forall(leavers.contains(_)) + } Right(oldRegions) } diff --git a/src/main/scala/com/github/unchama/seichiassist/commands/StickCommand.scala b/src/main/scala/com/github/unchama/seichiassist/commands/StickCommand.scala index 8fec08a81e..54e3c9ae73 100644 --- a/src/main/scala/com/github/unchama/seichiassist/commands/StickCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/commands/StickCommand.scala @@ -14,7 +14,7 @@ object StickCommand { val executor: TabExecutor = playerCommandBuilder .buildWithExecutionF { context => // 初見プレイヤー用とは別に簡潔な説明 - val stickLore = List("棒を持って右クリックもしくは左クリックでメニューを開きます。", "各メニューの詳細は公式サイトで確認できます。") + val stickLore = List("棒を持って右クリックもしくは", "左クリックでメニューを開きます。", "各メニューの詳細は公式サイトで確認できます。") val stickItemStack = new ItemStack(Material.STICK, 1).tap { itemStack => import itemStack._ val meta = getItemMeta diff --git a/src/main/scala/com/github/unchama/seichiassist/data/MenuInventoryData.java b/src/main/scala/com/github/unchama/seichiassist/data/MenuInventoryData.java index f5a75a1d6c..fc0159d7d6 100644 --- a/src/main/scala/com/github/unchama/seichiassist/data/MenuInventoryData.java +++ b/src/main/scala/com/github/unchama/seichiassist/data/MenuInventoryData.java @@ -450,8 +450,14 @@ public static Inventory getGiganticBerserkBeforeEvolutionMenu(final Player p) { final Inventory inventory = getEmptyInventory(6, ChatColor.DARK_PURPLE + "" + ChatColor.BOLD + "スキルを進化させますか?"); { // 色 - final byte[] table = {12, 15, 4, 0, 3}; - final ItemStack itemstack = new ItemStack(Material.STAINED_GLASS_PANE, 1, table[playerdata.giganticBerserk().stage()]); + final Material[] table = { + Material.ORANGE_STAINED_GLASS_PANE, + Material.BLACK_STAINED_GLASS_PANE, + Material.YELLOW_STAINED_GLASS_PANE, + Material.WHITE_STAINED_GLASS_PANE, + Material.LIGHT_BLUE_STAINED_GLASS_PANE + }; + final ItemStack itemstack = new ItemStack(table[playerdata.giganticBerserk().stage()], 1); final ItemMeta itemmeta = itemstack.getItemMeta(); itemmeta.setDisplayName(" "); itemstack.setItemMeta(itemmeta); @@ -495,10 +501,16 @@ public static Inventory getGiganticBerserkAfterEvolutionMenu(final Player p) { if (isError(p, playerdata, "GiganticBerserk進化後画面")) return null; final Inventory inventory = getEmptyInventory(6, ChatColor.LIGHT_PURPLE + "" + ChatColor.BOLD + "スキルを進化させました"); { - final byte[] table = {12, 15, 4, 0, 3, 12}; - final byte b = table[playerdata.giganticBerserk().stage()]; + final Material[] table = { + Material.BROWN_STAINED_GLASS_PANE, + Material.BLACK_STAINED_GLASS_PANE, + Material.YELLOW_STAINED_GLASS_PANE, + Material.WHITE_STAINED_GLASS_PANE, + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + Material.BROWN_STAINED_GLASS_PANE + }; - final ItemStack itemstack = new ItemStack(Material.STAINED_GLASS_PANE, 1, b); + final ItemStack itemstack = new ItemStack(table[playerdata.giganticBerserk().stage()], 1); final ItemMeta itemmeta = itemstack.getItemMeta(); if (playerdata.giganticBerserk().stage() >= 4) { @@ -570,7 +582,7 @@ private static ItemStack buildPlayerSkull(final String name, final List } private static ItemStack buildPlayerSkull(final String name, final List lore, final String owner, final Consumer modify) { - final ItemStack ret = new ItemStack(Material.SKULL_ITEM, 1, PLAYER_SKULL); + final ItemStack ret = new ItemStack(Material.PLAYER_HEAD, 1, PLAYER_SKULL); final SkullMeta sm = ItemMetaFactory.SKULL.getValue(); if (name != null) { sm.setDisplayName(name); diff --git a/src/main/scala/com/github/unchama/seichiassist/data/player/GiganticBerserk.scala b/src/main/scala/com/github/unchama/seichiassist/data/player/GiganticBerserk.scala index 823d126560..e7e343e342 100644 --- a/src/main/scala/com/github/unchama/seichiassist/data/player/GiganticBerserk.scala +++ b/src/main/scala/com/github/unchama/seichiassist/data/player/GiganticBerserk.scala @@ -25,12 +25,12 @@ case class GiganticBerserk( def materialOnUI(): Material = { stage match { - case 0 => Material.WOOD_SWORD + case 0 => Material.WOODEN_SWORD case 1 => Material.STONE_SWORD - case 2 => Material.GOLD_SWORD + case 2 => Material.GOLDEN_SWORD case 3 => Material.IRON_SWORD case 4 => Material.DIAMOND_SWORD - case 5 => Material.WOOD_SWORD + case 5 => Material.WOODEN_SWORD case _ => throw new RuntimeException("This branch should not be reached") } } diff --git a/src/main/scala/com/github/unchama/seichiassist/data/player/PlayerData.scala b/src/main/scala/com/github/unchama/seichiassist/data/player/PlayerData.scala index 35ba034cf3..5122d81c7b 100644 --- a/src/main/scala/com/github/unchama/seichiassist/data/player/PlayerData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/data/player/PlayerData.scala @@ -220,7 +220,7 @@ class PlayerData(@Deprecated() val uuid: UUID, val name: String) { // 総プレイ時間を更新する def updatePlayTick(): Unit = { // WARN: 1分毎にupdatePlayTickが呼び出されるというコンテクストに依存している. - val nowTotalPlayTick = player.getStatistic(Statistic.PLAY_ONE_TICK).toLong + val nowTotalPlayTick = player.getStatistic(Statistic.PLAY_ONE_MINUTE).toLong val diff = nowTotalPlayTick - totalPlayTick.getOrElse(nowTotalPlayTick) totalPlayTick = Some(nowTotalPlayTick) diff --git a/src/main/scala/com/github/unchama/seichiassist/data/player/settings/PlayerSettings.scala b/src/main/scala/com/github/unchama/seichiassist/data/player/settings/PlayerSettings.scala index a4f9e1b93f..9d4f08533b 100644 --- a/src/main/scala/com/github/unchama/seichiassist/data/player/settings/PlayerSettings.scala +++ b/src/main/scala/com/github/unchama/seichiassist/data/player/settings/PlayerSettings.scala @@ -48,7 +48,7 @@ class PlayerSettings { val toggleHalfBreakFlag: TargetedEffect[Player] = DeferredEffect(IO { allowBreakingHalfBlocks = !allowBreakingHalfBlocks - val newStatus = if (allowBreakingHalfBlocks) s"${GREEN}破壊可能" else "${RED}破壊不可能" + val newStatus = if (allowBreakingHalfBlocks) s"${GREEN}破壊可能" else s"${RED}破壊不可能" val responseMessage = s"現在ハーフブロックは$newStatus${RESET}です." MessageEffect(responseMessage) diff --git a/src/main/scala/com/github/unchama/seichiassist/domain/explevel/FiniteExpLevelTable.scala b/src/main/scala/com/github/unchama/seichiassist/domain/explevel/FiniteExpLevelTable.scala index ca722bada6..c5844b9b60 100644 --- a/src/main/scala/com/github/unchama/seichiassist/domain/explevel/FiniteExpLevelTable.scala +++ b/src/main/scala/com/github/unchama/seichiassist/domain/explevel/FiniteExpLevelTable.scala @@ -22,6 +22,7 @@ class FiniteExpLevelTable[L: PositiveInt, ExpAmount: Order: LowerBounded]( internalTable.sliding(2).forall { case Seq(x1, x2) => x1 <= x2 + case _ => false } }, "internalTable must be sorted" diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/BuildMainMenuOpener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/BuildMainMenuOpener.scala index 3cd8534404..7784de4316 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/BuildMainMenuOpener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/BuildMainMenuOpener.scala @@ -21,18 +21,15 @@ class BuildMainMenuOpener( @EventHandler def onPlayerLeftClickWithStick(event: PlayerInteractEvent): Unit = { val player = event.getPlayer + val action = event.getAction - event.getAction match { - case Action.LEFT_CLICK_AIR | Action.LEFT_CLICK_BLOCK => - case _ => return - } + if (action != Action.LEFT_CLICK_AIR && action != Action.LEFT_CLICK_BLOCK) return - { - val hasStickOnMainHand = player.getInventory.getItemInMainHand.getType == Material.STICK - val actionWasOnMainHand = event.getHand == EquipmentSlot.HAND + val hasNotStickOnMainHand = + player.getInventory.getItemInMainHand.getType != Material.STICK + val actionWasNotOnMainHand = event.getHand != EquipmentSlot.HAND - if (!hasStickOnMainHand || !actionWasOnMainHand) return - } + if (hasNotStickOnMainHand || actionWasNotOnMainHand) return effectEnvironment.unsafeRunAsyncTargetedEffect(player)( SequentialEffect( diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/EntityListener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/EntityListener.scala index a3fd697648..55063127d2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/EntityListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/EntityListener.scala @@ -18,6 +18,7 @@ import org.bukkit.enchantments.Enchantment import org.bukkit.entity.{Player, Projectile} import org.bukkit.event.entity._ import org.bukkit.event.{EventHandler, Listener} +import org.bukkit.inventory.meta.Damageable class EntityListener( implicit effectEnvironment: EffectEnvironment, @@ -77,16 +78,21 @@ class EntityListener( ) // 耐久値がマイナスかつ耐久無限ツールでない時処理を終了 - if (tool.getDurability > tool.getType.getMaxDurability && !tool.getItemMeta.isUnbreakable) + if ( + tool.getItemMeta.asInstanceOf[Damageable].getDamage > tool + .getType + .getMaxDurability && !tool.getItemMeta.isUnbreakable + ) return - runArrowSkillOfHitBlock(player, block, tool) + runArrowSkillOfHitBlock(player, block, tool, projectile) } private def runArrowSkillOfHitBlock( player: Player, hitBlock: BlockBreakableBySkill, - tool: BreakTool + tool: BreakTool, + projectile: Projectile ): Unit = { val playerData = playermap(player.getUniqueId) @@ -132,7 +138,7 @@ class EntityListener( val nextDurability = { val durabilityEnchantment = tool.getEnchantmentLevel(Enchantment.DURABILITY) - tool.getDurability + + tool.getItemMeta.asInstanceOf[Damageable].getDamage + BreakUtil.calcDurability( durabilityEnchantment, breakBlocks.size + 10 * (lavaBlocks.size + waterBlocks.size) @@ -157,7 +163,11 @@ class EntityListener( return // 耐久値を減らす - if (!tool.getItemMeta.isUnbreakable) tool.setDurability(nextDurability) + if (!tool.getItemMeta.isUnbreakable) { + val meta = tool.getItemMeta + meta.asInstanceOf[Damageable].setDamage(nextDurability) + tool.setItemMeta(meta) + } // 以降破壊する処理 // 溶岩と水を破壊する @@ -166,6 +176,8 @@ class EntityListener( // 元ブロックの真ん中の位置 val centerOfBlock = hitBlock.getLocation.add(0.5, 0.5, 0.5) + projectile.remove() + effectEnvironment.unsafeRunEffectAsync( "破壊エフェクトを再生する", playerData diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerBlockBreakListener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerBlockBreakListener.scala index d46674543f..25b56e6df9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerBlockBreakListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerBlockBreakListener.scala @@ -15,21 +15,23 @@ import com.github.unchama.seichiassist.subsystems.mana.ManaApi import com.github.unchama.seichiassist.subsystems.mana.domain.ManaAmount import com.github.unchama.seichiassist.subsystems.minestack.MineStackAPI import com.github.unchama.seichiassist.util.BreakUtil -import com.github.unchama.seichiassist.util.BreakUtil.BlockBreakResult import com.github.unchama.seichiassist.{MaterialSets, SeichiAssist} import com.github.unchama.targetedeffect.player.FocusedSoundEffect import com.github.unchama.util.effect.BukkitResources -import com.github.unchama.util.external.ExternalPlugins +import com.github.unchama.util.external.WorldGuardWrapper import org.bukkit.ChatColor.RED import org.bukkit._ import org.bukkit.block.Block +import org.bukkit.block.data.`type`.Slab import org.bukkit.enchantments.Enchantment import org.bukkit.entity.Player import org.bukkit.event.block.BlockBreakEvent import org.bukkit.event.{EventHandler, EventPriority, Listener} import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.Damageable import scala.collection.mutable.ArrayBuffer +import scala.jdk.CollectionConverters.CollectionHasAsScala import scala.util.control.Breaks class PlayerBlockBreakListener( @@ -48,6 +50,8 @@ class PlayerBlockBreakListener( def onPlayerActiveSkillEvent(event: BlockBreakEvent): Unit = { val player = event.getPlayer + if (!player.getWorld.isSeichiSkillAllowed) return + val block = MaterialSets .refineBlock(event.getBlock, MaterialSets.materials) .getOrElse( @@ -68,14 +72,6 @@ class PlayerBlockBreakListener( return } - if (!player.getWorld.isSeichiSkillAllowed) return - - // 破壊不可能ブロックの時処理を終了 - if (!BreakUtil.canBreakWithSkill(player, block)) { - event.setCancelled(true) - return - } - // 実際に使用するツール val tool: BreakTool = MaterialSets .refineItemStack(player.getInventory.getItemInMainHand, MaterialSets.breakToolMaterials) @@ -83,8 +79,14 @@ class PlayerBlockBreakListener( return ) + println(tool) + // 耐久値がマイナスかつ耐久無限ツールでない時処理を終了 - if (tool.getDurability > tool.getType.getMaxDurability && !tool.getItemMeta.isUnbreakable) + if ( + tool.getItemMeta.asInstanceOf[Damageable].getDamage > tool + .getType + .getMaxDurability && !tool.getItemMeta.isUnbreakable + ) return // もしサバイバルでなければ、またはフライ中なら終了 @@ -93,8 +95,6 @@ class PlayerBlockBreakListener( val playerData = SeichiAssist.playermap(player.getUniqueId) val skillState = playerData.skillState.get.unsafeRunSync() - if (!player.getWorld.isSeichiSkillAllowed) return - // クールダウンタイム中は処理を終了 if (!activeSkillAvailability(player).get.unsafeRunSync()) { // SEを再生 @@ -116,6 +116,12 @@ class PlayerBlockBreakListener( if (!selectedSkill.range.isInstanceOf[MultiArea] || skillState.usageMode == Disabled) return + // 破壊不可能ブロックの時処理を終了 + if (!BreakUtil.canBreakWithSkill(player, block)) { + event.setCancelled(true) + return + } + event.setCancelled(true) { @@ -140,7 +146,7 @@ class PlayerBlockBreakListener( // 壊される水ブロックの全てのリストデータ val multiWaterList = new ArrayBuffer[Set[Block]] // 全ての耐久消費量 - var toolDamageToSet = tool.getDurability.toInt + var toolDamageToSet = tool.getItemMeta.asInstanceOf[Damageable].getDamage // 消費が予約されたマナ val reservedMana = new ArrayBuffer[ManaAmount] @@ -272,12 +278,16 @@ class PlayerBlockBreakListener( // ツールの耐久値を減らす val adjustManaAndDurability = IO { - if (!tool.getItemMeta.isUnbreakable) tool.setDurability(toolDamageToSet.toShort) + if (!tool.getItemMeta.isUnbreakable) { + val meta = tool.getItemMeta + meta.asInstanceOf[Damageable].setDamage(toolDamageToSet) + tool.setItemMeta(meta) + } } effectEnvironment.unsafeRunEffectAsync( "複数破壊エフェクトを実行する", - effectPrograms.toList.sequence[IO, Fiber[IO, Unit]] + effectPrograms.sequence[IO, Fiber[IO, Unit]] ) effectEnvironment.unsafeRunEffectAsync( "複数破壊エフェクトの後処理を実行する", @@ -302,46 +312,32 @@ class PlayerBlockBreakListener( SeichiAssist.instance.breakCountSystem.api.incrementSeichiExp.of(player, amount).toIO ) - val tool: BreakTool = MaterialSets - .refineItemStack(player.getInventory.getItemInMainHand, MaterialSets.breakToolMaterials) - .getOrElse( - return - ) - - /** - * 手彫りで破壊したアイテムを直接MineStackに入れる - * 一つのBlockBreakEventから複数の種類のアイテムが出てくることはない。 - * チェスト等のインベントリスロットのあるブロック`b`を破壊したときは、 - * 破壊された`b`のみが`BlockBreakEvent`のドロップ対象となるため、 - * 中身のドロップがキャンセルされることはない。 - */ - val drops = BreakUtil - .dropItemOnTool(tool)((block.getLocation(), block.getType, block.getData)) - .getOrElse( - return - ) - - drops match { - case BlockBreakResult.ItemDrop(itemStack) => - val program = for { - currentAutoMineStackState <- mineStackAPI.autoMineStack(player) - isSucceedTryIntoMineStack <- whenAOrElse(currentAutoMineStackState)( + val program = for { + currentAutoMineStackState <- mineStackAPI.autoMineStack(player) + isSucceedTryIntoMineStack <- whenAOrElse(currentAutoMineStackState)( + event + .getBlock + .getDrops(player.getInventory.getItemInMainHand) + .asScala + .toList + .traverse { itemStack => mineStackAPI .mineStackRepository - .tryIntoMineStack(player, itemStack, itemStack.getAmount), - false - ) - } yield { - if (isSucceedTryIntoMineStack) event.setDropItems(false) - else () - } - program.unsafeRunSync() - case _ => () + .tryIntoMineStack(player, itemStack, itemStack.getAmount) + } + .map(_.forall(_ == true)), + false + ) + } yield { + if (isSucceedTryIntoMineStack) event.setDropItems(false) + else () } + program.unsafeRunSync() + } /** - * y5ハーフブロック破壊抑制 + * y-59ハーフブロック破壊抑制 * * @param event * BlockBreakEvent @@ -349,22 +345,22 @@ class PlayerBlockBreakListener( @EventHandler(priority = EventPriority.LOWEST) @SuppressWarnings(Array("deprecation")) def onPlayerBlockHalf(event: BlockBreakEvent): Unit = { - val p = event.getPlayer - val b = event.getBlock - val world = p.getWorld + val player = event.getPlayer + val block = event.getBlock + val world = player.getWorld // そもそも自分の保護じゃなきゃ処理かけない - if (!ExternalPlugins.getWorldGuard.canBuild(p, b.getLocation)) return - if ((b.getType eq Material.DOUBLE_STEP) && b.getData == 0) { - b.setType(Material.STEP) - b.setData(0.toByte) - val location = b.getLocation - world.dropItemNaturally(location, new ItemStack(Material.STEP)) + if (!WorldGuardWrapper.canBuild(player, block.getLocation)) return + block.getBlockData match { + case slab: Slab if slab.getType == Slab.Type.DOUBLE => + val location = block.getLocation + world.dropItemNaturally(location, new ItemStack(block.getType)) + case _: Slab => + case _ => return } - if (b.getType ne Material.STEP) return - if (b.getY > 5) return - if (b.getData != 0) return + if (block.getY > -59) return + if (block.getBlockData.asInstanceOf[Slab].getType != Slab.Type.BOTTOM) return if (!world.isSeichi) return event.setCancelled(true) - p.sendMessage(s"${RED}Y5以下に敷かれたハーフブロックは破壊不可能です。") + player.sendMessage(s"${RED}Y-59以下に敷かれたハーフブロックは破壊不可能です。") } } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerClickListener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerClickListener.scala index 6ddf552e27..b8521d7972 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerClickListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerClickListener.scala @@ -116,7 +116,7 @@ class PlayerClickListener( val equipmentSlot = event.getHand val currentItem = player.getInventory.getItemInMainHand.getType - if (currentItem == Material.STICK || currentItem == Material.SKULL_ITEM) return + if (currentItem == Material.STICK || currentItem == Material.PLAYER_HEAD) return val playerData = playerMap(player.getUniqueId) val playerLevel = SeichiAssist @@ -242,7 +242,7 @@ class PlayerClickListener( val targetBlock = e.getClickedBlock // 頭じゃない場合無視 - if (targetBlock.getType != Material.SKULL) { + if (targetBlock.getType != Material.PLAYER_HEAD) { return } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerDeathEventListener.java b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerDeathEventListener.java index 3ea7629d96..781156094e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerDeathEventListener.java +++ b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerDeathEventListener.java @@ -35,5 +35,7 @@ public void onDeath(PlayerDeathEvent event) { p.sendMessage(msg); } } + + event.setDeathMessage(null); } } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerInventoryListener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerInventoryListener.scala index 9371b85643..fbb2a2132d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerInventoryListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerInventoryListener.scala @@ -49,7 +49,7 @@ class PlayerInventoryListener( // インベントリサイズが54でない時終了 if (inventory.row != 6) return - if (inventory.getTitle != s"$LIGHT_PURPLE${BOLD}交換したい鉱石を入れてください") return + if (event.getView.getTitle != s"$LIGHT_PURPLE${BOLD}交換したい鉱石を入れてください") return /* * step1 for文でinventory内の対象商品の個数を計算 @@ -57,36 +57,40 @@ class PlayerInventoryListener( */ // 石炭とラピスラズリを適切に処理するため、typeとdurabilityを持つクラスを用意 - case class ExchangeableMaterial(materialType: Material, durability: Short) + case class ExchangeableMaterial(materialType: Material) val requiredAmountPerTicket = Map( - ExchangeableMaterial(Material.COAL_ORE, 0) -> 128, - ExchangeableMaterial(Material.IRON_ORE, 0) -> 64, - ExchangeableMaterial(Material.GOLD_ORE, 0) -> 8, - ExchangeableMaterial(Material.LAPIS_ORE, 0) -> 8, - ExchangeableMaterial(Material.DIAMOND_ORE, 0) -> 4, - ExchangeableMaterial(Material.REDSTONE_ORE, 0) -> 32, - ExchangeableMaterial(Material.EMERALD_ORE, 0) -> 4, - ExchangeableMaterial(Material.QUARTZ_ORE, 0) -> 16, - ExchangeableMaterial(Material.COAL, 0) -> 432, - ExchangeableMaterial(Material.REDSTONE, 0) -> 288, - ExchangeableMaterial(Material.INK_SACK, 4) -> 64, - ExchangeableMaterial(Material.DIAMOND, 0) -> 8 + ExchangeableMaterial(Material.COAL_ORE) -> 128, + ExchangeableMaterial(Material.COPPER_ORE) -> 128, + ExchangeableMaterial(Material.IRON_ORE) -> 64, + ExchangeableMaterial(Material.GOLD_ORE) -> 8, + ExchangeableMaterial(Material.LAPIS_ORE) -> 8, + ExchangeableMaterial(Material.DIAMOND_ORE) -> 4, + ExchangeableMaterial(Material.REDSTONE_ORE) -> 32, + ExchangeableMaterial(Material.EMERALD_ORE) -> 4, + ExchangeableMaterial(Material.NETHER_QUARTZ_ORE) -> 16, + ExchangeableMaterial(Material.NETHER_GOLD_ORE) -> 32, + ExchangeableMaterial(Material.DEEPSLATE_COAL_ORE) -> 128, + ExchangeableMaterial(Material.DEEPSLATE_COPPER_ORE) -> 128, + ExchangeableMaterial(Material.DEEPSLATE_IRON_ORE) -> 64, + ExchangeableMaterial(Material.DEEPSLATE_GOLD_ORE) -> 8, + ExchangeableMaterial(Material.DEEPSLATE_LAPIS_ORE) -> 8, + ExchangeableMaterial(Material.DEEPSLATE_DIAMOND_ORE) -> 4, + ExchangeableMaterial(Material.DEEPSLATE_REDSTONE_ORE) -> 32, + ExchangeableMaterial(Material.DEEPSLATE_EMERALD_ORE) -> 4 ) val inventoryContents = inventory.getContents.filter(_ != null) val (itemsToExchange, rejectedItems) = inventoryContents.partition { stack => - requiredAmountPerTicket.contains( - ExchangeableMaterial(stack.getType, stack.getDurability) - ) + requiredAmountPerTicket.contains(ExchangeableMaterial(stack.getType)) } - val exchangingAmount = itemsToExchange - .groupBy(stacks => ExchangeableMaterial(stacks.getType, stacks.getDurability)) - .toList - .map { case (key, stacks) => key -> stacks.map(_.getAmount).sum } + val exchangingAmount = + itemsToExchange.groupBy(stacks => ExchangeableMaterial(stacks.getType)).toList.map { + case (key, stacks) => key -> stacks.map(_.getAmount).sum + } val ticketAmount = exchangingAmount.map { case (exchangeableMaterial, amount) => @@ -139,13 +143,7 @@ class PlayerInventoryListener( case (exchangedMaterial, exchangedAmount) => val returningAmount = exchangedAmount % requiredAmountPerTicket(exchangedMaterial) if (returningAmount != 0) - Some( - new ItemStack( - exchangedMaterial.materialType, - returningAmount, - exchangedMaterial.durability - ) - ) + Some(new ItemStack(exchangedMaterial.materialType, returningAmount)) else None } @@ -186,15 +184,15 @@ class PlayerInventoryListener( val uuid = player.getUniqueId val playerdata = playerMap(uuid) - if (topinventory.getTitle == DARK_PURPLE.toString + "" + BOLD + "スキルを進化させますか?") { + if (view.getTitle == DARK_PURPLE.toString + "" + BOLD + "スキルを進化させますか?") { event.setCancelled(true) if (itemstackcurrent.getType == Material.NETHER_STAR) { playerdata.giganticBerserk = GiganticBerserk(0, 0, playerdata.giganticBerserk.stage + 1) player.playSound(player.getLocation, Sound.BLOCK_END_GATEWAY_SPAWN, 1f, 0.5f) - player.playSound(player.getLocation, Sound.ENTITY_ENDERDRAGON_AMBIENT, 1f, 0.8f) + player.playSound(player.getLocation, Sound.ENTITY_ENDER_DRAGON_AMBIENT, 1f, 0.8f) player.openInventory(MenuInventoryData.getGiganticBerserkAfterEvolutionMenu(player)) } - } else if (topinventory.getTitle == LIGHT_PURPLE.toString + "" + BOLD + "スキルを進化させました") { + } else if (view.getTitle == LIGHT_PURPLE.toString + "" + BOLD + "スキルを進化させました") { event.setCancelled(true) } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerJoinListener.scala b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerJoinListener.scala index 8a219d981b..dfb2ac85b3 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/PlayerJoinListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/PlayerJoinListener.scala @@ -13,7 +13,7 @@ import com.github.unchama.seichiassist.subsystems.mebius.domain.property.{ } import com.github.unchama.seichiassist.util.{SendMessageEffect, SendSoundEffect} import com.github.unchama.targetedeffect.player.FocusedSoundEffect -import net.coreprotect.model.Config +import net.coreprotect.config.ConfigHandler import org.bukkit.ChatColor._ import org.bukkit.enchantments.Enchantment import org.bukkit.entity.Player @@ -97,12 +97,17 @@ class PlayerJoinListener extends Listener { // 初見さんへの処理 if (!player.hasPlayedBefore) { // 初見さんであることを全体告知 - SendMessageEffect.sendMessageToEveryoneIgnoringPreference( - s"$LIGHT_PURPLE$BOLD${player.getName}さんはこのサーバーに初めてログインしました!" - ) - SendMessageEffect.sendMessageToEveryoneIgnoringPreference( - s"${WHITE}webサイトはもう読みましたか?→$YELLOW${UNDERLINE}https://www.seichi.network/gigantic" - ) + SendMessageEffect + .sendMessageToEveryoneIgnoringPreferenceIO( + s"$LIGHT_PURPLE$BOLD${player.getName}さんはこのサーバーに初めてログインしました!" + ) + .unsafeRunAsyncAndForget() + SendMessageEffect + .sendMessageToEveryoneIgnoringPreferenceIO( + s"${WHITE}webサイトはもう読みましたか?→$YELLOW${UNDERLINE}https://www.seichi.network/gigantic" + ) + .unsafeRunAsyncAndForget() + SendSoundEffect.sendEverySound(Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f) // 同時に【はじめての方へ】ページに誘導したほうがただWebサイトに誘導するよりまだ可能性がありそう @@ -125,10 +130,14 @@ class PlayerJoinListener extends Listener { // 初見プレイヤー向けの Lore (説明文) を設定 // /stick で入手できる木の棒は、簡略化された説明文にしておく。 val stickLore = List( - "この棒を持って右クリックもしくは左クリックするとメニューが開きます。", - "メニューからはいろんな機能が使えます。試してみよう。", - "この棒をなくしても /stick コマンドを実行すると再入手できます。", - "ヒント: もしサーバー内で迷子になったら /spawn コマンドを実行することでいつでも戻れます。" + "この棒を持って右クリックもしくは", + "左クリックするとメニューが開きます。", + "試してみよう。", + "", + "この棒をなくしても /stick コマンドを", + "実行すると再入手できます。", + "ヒント: もしサーバー内で迷子になったら /spawn", + "コマンドを実行することでいつでも戻れます。" ) val stick = new ItemStack(Material.STICK, 1).tap { itemStack => import itemStack._ @@ -144,13 +153,13 @@ class PlayerJoinListener extends Listener { // 耐久Ⅲ .tap(_.addEnchantment(Enchantment.DURABILITY, 3)) inv.addItem(pickaxe) - inv.addItem(new ItemStack(Material.DIAMOND_SPADE)) + inv.addItem(new ItemStack(Material.DIAMOND_SHOVEL)) inv.addItem( - new ItemStack(Material.LOG, 64, 0.toShort), - new ItemStack(Material.LOG, 64, 0.toShort), - new ItemStack(Material.LOG, 64, 2.toShort), - new ItemStack(Material.LOG_2, 64, 1.toShort) + new ItemStack(Material.OAK_LOG, 64), + new ItemStack(Material.OAK_LOG, 64), + new ItemStack(Material.BIRCH_LOG, 64), + new ItemStack(Material.DARK_OAK_LOG, 64) ) inv.addItem(new ItemStack(Material.BAKED_POTATO, 64)) @@ -196,8 +205,7 @@ class PlayerJoinListener extends Listener { BukkitMebiusItemStackCodec.materialize( // **getDisplayNameは二つ名も含むのでMCIDにはgetNameが適切** MebiusProperty - .initialProperty(NormalMebius, player.getName, player.getUniqueId.toString), - damageValue = 0.toShort + .initialProperty(NormalMebius, player.getName, player.getUniqueId.toString) ) ) @@ -215,7 +223,7 @@ class PlayerJoinListener extends Listener { // 整地専用サーバーの場合は上級者向けのサーバーである旨を通知 if (SeichiAssist.seichiAssistConfig.getServerNum == 5) player.sendTitle( - s"${WHITE}ここは$BLUE${UNDERLINE}上級者向けのサーバー${WHITE}", + s"${WHITE}ここは$BLUE${UNDERLINE}上級者向けのサーバー$WHITE", s"${WHITE}始めたては他がおすすめ", 10, 70, @@ -226,14 +234,12 @@ class PlayerJoinListener extends Listener { // TODO: エデンサーバーの不具合が解消されたら削除すること if (SeichiAssist.seichiAssistConfig.getServerNum == 2) { player.sendMessage( - Array( - s"${RED}${BOLD}${UNDERLINE}【ご注意ください】${RESET}", - s"${YELLOW}${BOLD}エデンサーバーは現在、管理者の意図しないタイミングでシャットダウン(いわゆる「鯖落ち」)が起こることがあります。", - s"${YELLOW}${BOLD}もし鯖落ちによりアイテムの消失等が発生しても、補償はできかねます。", - s"${YELLOW}${BOLD}当サーバーは以上の内容をご理解の上ご利用ください。", - s"${YELLOW}${BOLD}不安な場合はアルカディアサーバーやヴァルハラサーバーのご利用をおすすめいたします。", - s"${YELLOW}${BOLD}ご迷惑をおかけいたしまして申し訳ございません。。" - ) + s"${RED}${BOLD}${UNDERLINE}【ご注意ください】${RESET}", + s"${YELLOW}${BOLD}エデンサーバーは現在、管理者の意図しないタイミングでシャットダウン(いわゆる「鯖落ち」)が起こることがあります。", + s"${YELLOW}${BOLD}もし鯖落ちによりアイテムの消失等が発生しても、補償はできかねます。", + s"${YELLOW}${BOLD}当サーバーは以上の内容をご理解の上ご利用ください。", + s"${YELLOW}${BOLD}不安な場合はアルカディアサーバーやヴァルハラサーバーのご利用をおすすめいたします。", + s"${YELLOW}${BOLD}ご迷惑をおかけいたしまして申し訳ございません。。" ) } } @@ -249,10 +255,10 @@ class PlayerJoinListener extends Listener { // coreprotectを切る // inspectマップにtrueで登録されている場合 - if (Config.inspecting.getOrDefault(p.getName, false)) { + if (ConfigHandler.inspecting.getOrDefault(p.getName, false)) { // falseに変更する p.sendMessage("§3CoreProtect §f- Inspector now disabled.") - Config.inspecting.put(p.getName, false) + ConfigHandler.inspecting.put(p.getName, false) } // アサルトスキルを切る diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/SpawnRegionProjectileInterceptor.scala b/src/main/scala/com/github/unchama/seichiassist/listener/SpawnRegionProjectileInterceptor.scala index 5f7cb471e8..294ad05168 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/SpawnRegionProjectileInterceptor.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/SpawnRegionProjectileInterceptor.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.listener -import com.github.unchama.util.external.WorldGuardWrapper.getRegions +import com.github.unchama.util.external.WorldGuardWrapper.getRegion import org.bukkit.Material._ import org.bukkit.event.block.Action import org.bukkit.event.player.PlayerInteractEvent @@ -19,10 +19,10 @@ object SpawnRegionProjectileInterceptor extends Listener { BOW, EGG, ENDER_PEARL, - EXP_BOTTLE, - EYE_OF_ENDER, + EXPERIENCE_BOTTLE, + ENDER_EYE, LINGERING_POTION, - SNOW_BALL, + SNOWBALL, SPLASH_POTION ) @@ -34,7 +34,7 @@ object SpawnRegionProjectileInterceptor extends Listener { val isRightClickEvent = action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK val isInSpawnRegion = - getRegions(player.getLocation).map(_.getId).exists(spawnRegionNames.contains) + getRegion(player.getLocation).map(_.getId).exists(spawnRegionNames.contains) // Projectileを持った状態で右クリックし、playerがいる保護がspawn保護の中であった場合はイベントをキャンセルする if (hasProjectile && isRightClickEvent && isInSpawnRegion) { diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/WorldRegenListener.java b/src/main/scala/com/github/unchama/seichiassist/listener/WorldRegenListener.java index 93d27d1800..06e201cbd9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/WorldRegenListener.java +++ b/src/main/scala/com/github/unchama/seichiassist/listener/WorldRegenListener.java @@ -2,15 +2,15 @@ import com.github.unchama.seichiassist.Config; import com.github.unchama.seichiassist.SeichiAssist; -import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.wimbli.WorldBorder.CoordXZ; @@ -20,10 +20,14 @@ import io.monchi.regenworld.event.RegenWorldEvent; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import java.util.Collection; +import java.util.Objects; + /** * @author Mon_chi */ @@ -33,8 +37,6 @@ public class WorldRegenListener implements Listener { private final int roadLength; private final int spaceHeight; private final int worldSize; - private final BaseBlock roadBlock; - private final BaseBlock spaceBlock; private final WorldEdit worldEdit; private final WorldGuardPlugin worldGuard; @@ -46,8 +48,6 @@ public WorldRegenListener() { this.roadLength = config.getRoadLength(); this.spaceHeight = config.getSpaceHeight(); this.worldSize = config.getWorldSize(); - this.roadBlock = new BaseBlock(config.getRoadBlockID(), config.getRoadBlockDamage()); - this.spaceBlock = new BaseBlock(0); this.worldEdit = WorldEdit.getInstance(); this.worldGuard = WorldGuardPlugin.inst(); @@ -73,20 +73,26 @@ public void onWorldRegen(RegenWorldEvent event) { com.wimbli.WorldBorder.Config.fillTask.setTaskID(task); } - RegionManager regionManager = worldGuard.getRegionManager(world); - regionManager.getRegions().keySet().stream() - .filter(region -> !region.equalsIgnoreCase("__global__")) - .forEach(regionManager::removeRegion); + Collection regions = Objects.requireNonNull(WorldGuard.getInstance().getPlatform() + .getRegionContainer() + .get(BukkitAdapter.adapt(world))) + .getRegions() + .values(); + + regions.forEach(region -> { + Objects.requireNonNull(WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world))).removeRegion(region.getId()); + }); + EditSession session = worldEdit.getEditSessionFactory().getEditSession(bukkitWorld, 99999999); try { // spawnの地形造成 - setupRoadWithWorldGuard(session, world, "spawn", new BlockVector(0, roadY, 0), new BlockVector(15, roadY, 15)); + setupRoadWithWorldGuard(session, world, "spawn", BlockVector3.at(0, roadY, 0), BlockVector3.at(15, roadY, 15)); // 東西南北へ続くroadの地形造成 - setupRoad(session, world, new BlockVector(16, roadY, 0), new BlockVector(15 + 16 * roadLength, roadY, 15)); - setupRoad(session, world, new BlockVector(-1, roadY, 0), new BlockVector(-(16 * roadLength), roadY, 15)); - setupRoad(session, world, new BlockVector(0, roadY, 16), new BlockVector(15, roadY, 15 + 16 * roadLength)); - setupRoad(session, world, new BlockVector(0, roadY, -1), new BlockVector(15, roadY, -(16 * roadLength))); + setupRoad(session, world, BlockVector3.at(16, roadY, 0), BlockVector3.at(15 + 16 * roadLength, roadY, 15)); + setupRoad(session, world, BlockVector3.at(-1, roadY, 0), BlockVector3.at(-(16 * roadLength), roadY, 15)); + setupRoad(session, world, BlockVector3.at(0, roadY, 16), BlockVector3.at(15, roadY, 15 + 16 * roadLength)); + setupRoad(session, world, BlockVector3.at(0, roadY, -1), BlockVector3.at(15, roadY, -(16 * roadLength))); } catch (MaxChangedBlocksException e) { e.printStackTrace(); } @@ -95,33 +101,24 @@ public void onWorldRegen(RegenWorldEvent event) { /** * 地形造成を行う * - * @param session - * @param world - * @param pos1 - * @param pos2 * @throws MaxChangedBlocksException */ - private void setupRoad(EditSession session, World world, BlockVector pos1, BlockVector pos2) throws MaxChangedBlocksException { + private void setupRoad(EditSession session, World world, BlockVector3 pos1, BlockVector3 pos2) throws MaxChangedBlocksException { BukkitWorld bukkitWorld = new BukkitWorld(world); - session.setBlocks(new CuboidRegion(bukkitWorld, pos1, pos2), roadBlock); - session.setBlocks(new CuboidRegion(bukkitWorld, pos1.add(0, 1, 0), pos2.add(0, 1 + spaceHeight, 0)), spaceBlock); + session.setBlocks(new CuboidRegion(bukkitWorld, pos1, pos2), BukkitAdapter.adapt(Material.BEDROCK.createBlockData())); + session.setBlocks(new CuboidRegion(bukkitWorld, pos1.add(0, 1, 0), pos2.add(0, 1 + spaceHeight, 0)), BukkitAdapter.adapt(Material.AIR.createBlockData())); } /** * 地形造成と、地形造成を行った場所にWorldGuardRegionも設定する * - * @param session - * @param world - * @param protName - * @param pos1 - * @param pos2 * @throws MaxChangedBlocksException */ - private void setupRoadWithWorldGuard(EditSession session, World world, String protName, BlockVector pos1, BlockVector pos2) throws MaxChangedBlocksException { + private void setupRoadWithWorldGuard(EditSession session, World world, String protName, BlockVector3 pos1, BlockVector3 pos2) throws MaxChangedBlocksException { BukkitWorld bukkitWorld = new BukkitWorld(world); - session.setBlocks(new CuboidRegion(bukkitWorld, pos1, pos2), roadBlock); - session.setBlocks(new CuboidRegion(bukkitWorld, pos1.add(0, 1, 0), pos2.add(0, 1 + spaceHeight, 0)), spaceBlock); - ProtectedRegion region = new ProtectedCuboidRegion(protName, new BlockVector(pos1.getX(), 0, pos1.getZ()), new BlockVector(pos2.getX(), 255, pos2.getZ())); - WorldGuardPlugin.inst().getRegionManager(world).addRegion(region); + session.setBlocks(new CuboidRegion(bukkitWorld, pos1, pos2), BukkitAdapter.adapt(Material.BEDROCK.createBlockData())); + session.setBlocks(new CuboidRegion(bukkitWorld, pos1.add(0, 1, 0), pos2.add(0, 1 + spaceHeight, 0)), BukkitAdapter.adapt(Material.AIR.createBlockData())); + ProtectedRegion region = new ProtectedCuboidRegion(protName, BlockVector3.at(pos1.getX(), 0, pos1.getZ()), BlockVector3.at(pos2.getX(), 255, pos2.getZ())); + WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world)).addRegion(region); } } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/Y5DoubleSlabCanceller.scala b/src/main/scala/com/github/unchama/seichiassist/listener/YMinus59DoubleSlabCanceller.scala similarity index 60% rename from src/main/scala/com/github/unchama/seichiassist/listener/Y5DoubleSlabCanceller.scala rename to src/main/scala/com/github/unchama/seichiassist/listener/YMinus59DoubleSlabCanceller.scala index fd84ecbdfa..f2d85be0e5 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/Y5DoubleSlabCanceller.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/YMinus59DoubleSlabCanceller.scala @@ -1,11 +1,11 @@ package com.github.unchama.seichiassist.listener import com.github.unchama.seichiassist.ManagedWorld._ -import org.bukkit.Material +import org.bukkit.block.data.`type`.Slab import org.bukkit.event.block.BlockPlaceEvent import org.bukkit.event.{EventHandler, Listener} -object Y5DoubleSlabCanceller extends Listener { +object YMinus59DoubleSlabCanceller extends Listener { /** * 以下の条件をすべて満たすときにブロックの設置をキャンセルし、その旨を示すメッセージを送出する @@ -13,22 +13,22 @@ object Y5DoubleSlabCanceller extends Listener { * - プレイヤーが手に持っているブロックが焼き石のハーフブロックである * - 対象座標の改変後ブロックが焼き石の二段重ねハーフブロックである * - 対象座標が整地ワールドを指している - * - 対象ブロックのY座標が5である + * - 対象ブロックのY座標が-59である * @see * https://github.com/GiganticMinecraft/SeichiAssist/issues/775 * @param event * 対象イベント */ @EventHandler - def onPlaceDoubleSlabAtY5(event: BlockPlaceEvent): Unit = { + def onPlaceDoubleSlabAtYMinus59(event: BlockPlaceEvent): Unit = { if (!event.canBuild) return - if (event.getItemInHand.getType ne Material.STEP) return - if (event.getItemInHand.getDurability != 0) return - if (event.getBlockPlaced.getType ne Material.DOUBLE_STEP) return - if (event.getBlockPlaced.getData != 0) return if (!event.getBlockPlaced.getWorld.isSeichi) return - if (event.getBlockPlaced.getY != 5) return - event.setCancelled(true) - event.getPlayer.sendMessage("Y5のハーフブロックを二段重ねにすることはできません。") + if (event.getBlockPlaced.getY != -59) return + event.getBlockPlaced.getBlockData match { + case slab: Slab if slab.getType == Slab.Type.DOUBLE => + event.setCancelled(true) + event.getPlayer.sendMessage("Y-59のハーフブロックを二段重ねにすることはできません。") + case _ => + } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/listener/invlistener/OnClickTitleMenu.scala b/src/main/scala/com/github/unchama/seichiassist/listener/invlistener/OnClickTitleMenu.scala index 4122f4b310..bcb60755ee 100644 --- a/src/main/scala/com/github/unchama/seichiassist/listener/invlistener/OnClickTitleMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/listener/invlistener/OnClickTitleMenu.scala @@ -57,7 +57,11 @@ object OnClickTitleMenu { if (topInventory.row != 4) { return } - val current = event.getCurrentItem + val current = event + .getCurrentItem + .ifNull( + return + ) val player = he.asInstanceOf[Player] val pd = SeichiAssist.playermap(player.getUniqueId) @@ -68,191 +72,169 @@ object OnClickTitleMenu { } val mat = current.getType - val isSkull = mat == Material.SKULL_ITEM - topInventory.getTitle match { + val isSkull = mat == Material.PLAYER_HEAD + view.getTitle match { case MenuType.HEAD.invName => event.setCancelled(true) - mat match { - case Material.WATER_BUCKET => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - - val id = current.getItemMeta.getDisplayName.toInt - val length = Nicknames - .getCombinedNicknameFor(id, pd.settings.nickname.id2, pd.settings.nickname.id3) - .getOrElse("") - .length - if (length > MAX_LENGTH) { - player.sendMessage(LENGTH_LIMIT_EXCEEDED) - } else { - pd.updateNickname(id1 = id) - player.sendMessage( - "前パーツ「" + Nicknames - .getHeadPartFor(pd.settings.nickname.id1) - .getOrElse("") + "」をセットしました。" - ) - } - - case Material.GRASS => - // unselect - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - pd.updateNickname(id1 = 0) - player.sendMessage("前パーツの選択を解除しました。") - - case Material.BARRIER => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() - - case _ if isSkull && isApplicableAsNextPageButton(current) => - // 次ページ - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - val uuid = player.getUniqueId - val menuType = MenuInventoryData.MenuType.HEAD - MenuInventoryData.setHeadingIndex( - uuid, - menuType, - MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + if (mat == Material.WATER_BUCKET) { + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + + val id = current.getItemMeta.getDisplayName.toInt + val length = Nicknames + .getCombinedNicknameFor(id, pd.settings.nickname.id2, pd.settings.nickname.id3) + .getOrElse("") + .length + if (length > MAX_LENGTH) { + player.sendMessage(LENGTH_LIMIT_EXCEEDED) + } else { + pd.updateNickname(id1 = id) + player.sendMessage( + "前パーツ「" + Nicknames + .getHeadPartFor(pd.settings.nickname.id1) + .getOrElse("") + "」をセットしました。" ) - player.openInventory(MenuInventoryData.computeHeadPartCustomMenu(player)) - - case _ => + } + } else if (mat == Material.GRASS) { + // unselect + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + pd.updateNickname(id1 = 0) + player.sendMessage("前パーツの選択を解除しました。") + } else if (mat == Material.BARRIER) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() + } else if (isSkull && isApplicableAsNextPageButton(current)) { + // 次ページ + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + val uuid = player.getUniqueId + val menuType = MenuInventoryData.MenuType.HEAD + MenuInventoryData.setHeadingIndex( + uuid, + menuType, + MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + ) + player.openInventory(MenuInventoryData.computeHeadPartCustomMenu(player)) } case MenuType.MIDDLE.invName => event.setCancelled(true) - mat match { - case Material.MILK_BUCKET => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - - val id = current.getItemMeta.getDisplayName.toInt - val length = Nicknames - .getCombinedNicknameFor(pd.settings.nickname.id1, id, pd.settings.nickname.id3) - .getOrElse("") - .length - if (length > MAX_LENGTH) { - player.sendMessage(LENGTH_LIMIT_EXCEEDED) - } else { - pd.updateNickname(id2 = id) - player.sendMessage( - "中パーツ「" + Nicknames - .getMiddlePartFor(pd.settings.nickname.id2) - .getOrElse("") + "」をセットしました。" - ) - } - - case Material.GRASS => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - pd.updateNickname(id2 = 0) - player.sendMessage("中パーツの選択を解除しました。") - case Material.BARRIER => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() - - case _ if isSkull && isApplicableAsNextPageButton(current) => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - val uuid = player.getUniqueId - val menuType = MenuInventoryData.MenuType.MIDDLE - MenuInventoryData.setHeadingIndex( - uuid, - menuType, - MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + if (mat == Material.MILK_BUCKET) { + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + + val id = current.getItemMeta.getDisplayName.toInt + val length = Nicknames + .getCombinedNicknameFor(pd.settings.nickname.id1, id, pd.settings.nickname.id3) + .getOrElse("") + .length + if (length > MAX_LENGTH) { + player.sendMessage(LENGTH_LIMIT_EXCEEDED) + } else { + pd.updateNickname(id2 = id) + player.sendMessage( + "中パーツ「" + Nicknames + .getMiddlePartFor(pd.settings.nickname.id2) + .getOrElse("") + "」をセットしました。" ) - player.openInventory(MenuInventoryData.computeMiddlePartCustomMenu(player)) - - case _ => + } + } else if (mat == Material.GRASS) { + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + pd.updateNickname(id2 = 0) + player.sendMessage("中パーツの選択を解除しました。") + } else if (mat == Material.BARRIER) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() + } else if (isSkull && isApplicableAsNextPageButton(current)) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + val uuid = player.getUniqueId + val menuType = MenuInventoryData.MenuType.MIDDLE + MenuInventoryData.setHeadingIndex( + uuid, + menuType, + MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + ) + player.openInventory(MenuInventoryData.computeMiddlePartCustomMenu(player)) } case MenuType.TAIL.invName => event.setCancelled(true) - mat match { - case Material.LAVA_BUCKET => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - - val id = current.getItemMeta.getDisplayName.toInt - val length = Nicknames - .getCombinedNicknameFor(pd.settings.nickname.id1, pd.settings.nickname.id2, id) - .getOrElse("") - .length - if (length > MAX_LENGTH) { - player.sendMessage(LENGTH_LIMIT_EXCEEDED) - } else { - pd.updateNickname(id3 = id) - player.sendMessage( - "後パーツ「" + Nicknames - .getTailPartFor(pd.settings.nickname.id3) - .getOrElse("") + "」をセットしました。" - ) - } - case Material.GRASS => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - pd.updateNickname(id3 = 0) - player.sendMessage("後パーツの選択を解除しました。") - - case Material.BARRIER => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() - - case _ if isSkull && isApplicableAsNextPageButton(current) => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - val uuid = player.getUniqueId - val menuType = MenuInventoryData.MenuType.TAIL - MenuInventoryData.setHeadingIndex( - uuid, - menuType, - MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + if (mat == Material.LAVA_BUCKET) { + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + + val id = current.getItemMeta.getDisplayName.toInt + val length = Nicknames + .getCombinedNicknameFor(pd.settings.nickname.id1, pd.settings.nickname.id2, id) + .getOrElse("") + .length + if (length > MAX_LENGTH) { + player.sendMessage(LENGTH_LIMIT_EXCEEDED) + } else { + pd.updateNickname(id3 = id) + player.sendMessage( + "後パーツ「" + Nicknames + .getTailPartFor(pd.settings.nickname.id3) + .getOrElse("") + "」をセットしました。" ) - player.openInventory(MenuInventoryData.computeTailPartCustomMenu(player)) - - case _ => + } + } else if (mat == Material.GRASS) { + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + pd.updateNickname(id3 = 0) + player.sendMessage("後パーツの選択を解除しました。") + } else if (mat == Material.BARRIER) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() + } else if (isSkull && isApplicableAsNextPageButton(current)) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + val uuid = player.getUniqueId + val menuType = MenuInventoryData.MenuType.TAIL + MenuInventoryData.setHeadingIndex( + uuid, + menuType, + MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + ) + player.openInventory(MenuInventoryData.computeTailPartCustomMenu(player)) } case MenuType.SHOP.invName => event.setCancelled(true) - mat match { + if (mat == Material.EMERALD_ORE) { // 実績ポイント最新化 - case Material.EMERALD_ORE => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - pd.recalculateAchievePoint() - pd.samepageflag = true - player.openInventory(MenuInventoryData.computePartsShopMenu(player)) - + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + pd.recalculateAchievePoint() + pd.samepageflag = true + player.openInventory(MenuInventoryData.computePartsShopMenu(player)) + } else if (mat == Material.BEDROCK) { // 購入処理 - case Material.BEDROCK => - clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) - - val num = current.getItemMeta.getDisplayName.toInt - val isHead = num < 9900 - val required = if (isHead) 20 else 35 - val getPart = if (isHead) { num => Nicknames.getHeadPartFor(num) } - else { num => Nicknames.getMiddlePartFor(num) } - - if (pd.achievePoint.left >= required) { - pd.TitleFlags.addOne(num) - pd.consumeAchievePoint(required) - player.sendMessage("パーツ「" + getPart(num).getOrElse("") + "」を購入しました。") - pd.samepageflag = true - player.openInventory(MenuInventoryData.computePartsShopMenu(player)) - } else { - player.sendMessage("実績ポイントが不足しています。") - } - - case Material.BARRIER => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() - - case _ if isSkull && isApplicableAsNextPageButton(current) => - clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) - val uuid = player.getUniqueId - val menuType = MenuInventoryData.MenuType.SHOP - MenuInventoryData.setHeadingIndex( - uuid, - menuType, - MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE - ) + clickedSound(player, Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1.0f) + + val num = current.getItemMeta.getDisplayName.toInt + val isHead = num < 9900 + val required = if (isHead) 20 else 35 + val getPart = if (isHead) { num => Nicknames.getHeadPartFor(num) } + else { num => Nicknames.getMiddlePartFor(num) } + + if (pd.achievePoint.left >= required) { + pd.TitleFlags.addOne(num) + pd.consumeAchievePoint(required) + player.sendMessage("パーツ「" + getPart(num).getOrElse("") + "」を購入しました。") + pd.samepageflag = true player.openInventory(MenuInventoryData.computePartsShopMenu(player)) - - case _ => + } else { + player.sendMessage("実績ポイントが不足しています。") + } + } else if (mat == Material.BARRIER) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + ioCanOpenNicknameMenu.open(NickNameMenu).apply(player).unsafeRunAsyncAndForget() + } else if (isSkull && isApplicableAsNextPageButton(current)) { + clickedSound(player, Sound.BLOCK_FENCE_GATE_OPEN, 0.1f) + val uuid = player.getUniqueId + val menuType = MenuInventoryData.MenuType.SHOP + MenuInventoryData.setHeadingIndex( + uuid, + menuType, + MenuInventoryData.getHeadingIndex(uuid, menuType).get + PER_PAGE + ) + player.openInventory(MenuInventoryData.computePartsShopMenu(player)) } // それ以外のインベントリの名前だった場合何もしない! diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/BuildMainMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/BuildMainMenu.scala index f655e40618..c053b46656 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/BuildMainMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/BuildMainMenu.scala @@ -207,7 +207,7 @@ private case class ButtonComputations(player: Player)( IO { val openerData = BuildAssist.instance.temporaryData(getUniqueId) - val iconItemStack = new IconItemStackBuilder(Material.WOOD) + val iconItemStack = new IconItemStackBuilder(Material.OAK_PLANKS) .title(s"$YELLOW${EMPHASIZE}直列設置: ${BuildAssist.line_up_str(openerData.line_up_flg)}") .lore( s"$RESET${GRAY}オフハンドに木の棒、メインハンドに設置したいブロックを持って", @@ -279,7 +279,7 @@ private case class ButtonComputations(player: Player)( def computeButtonToOpenMenuToCraftItemsWhereMineStack( implicit canOpenMassCraftMenu: CanOpen[IO, MineStackMassCraftMenu] ): IO[Button] = IO { - val iconItemStackBuilder = new IconItemStackBuilder(Material.WORKBENCH) + val iconItemStackBuilder = new IconItemStackBuilder(Material.CRAFTING_TABLE) .title(s"$YELLOW${EMPHASIZE}MineStackブロック一括クラフト画面へ") .lore(s"$RESET$DARK_RED${UNDERLINE}クリックで移動") .build() diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/RegionMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/RegionMenu.scala index e8d1a01e54..126952108e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/RegionMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/RegionMenu.scala @@ -15,7 +15,8 @@ import com.github.unchama.seichiassist.menus.gridregion.GridRegionMenu import com.github.unchama.seichiassist.subsystems.gridregion.GridRegionAPI import com.github.unchama.targetedeffect.commandsender.MessageEffect import com.github.unchama.targetedeffect.player.{CommandEffect, FocusedSoundEffect} -import com.github.unchama.util.external.ExternalPlugins +import com.sk89q.worldedit.WorldEdit +import com.sk89q.worldedit.bukkit.BukkitAdapter import org.bukkit.ChatColor._ import org.bukkit.entity.Player import org.bukkit.event.inventory.InventoryType @@ -69,34 +70,34 @@ object RegionMenu extends Menu { val computeButtonToClaimRegion: IO[Button] = for { regionCount <- gridRegionAPI.regionCount(player) } yield { - val selection = ExternalPlugins.getWorldEdit.getSelection(player) - + val session = WorldEdit.getInstance().getSessionManager.get(BukkitAdapter.adapt(player)) + val world = BukkitAdapter.adapt(player.getWorld) + val isSelected = session.isSelectionDefined(world) val playerHasPermission = player.hasPermission("worldguard.region.claim") - val isSelectionNull = selection == null + + val selectionOpt = Option.when(isSelected)(session.getSelection(world)) val selectionHasEnoughSpace = - if (!isSelectionNull) - selection.getLength >= 10 && selection.getWidth >= 10 - else false + selectionOpt.exists(selection => selection.getLength >= 10 && selection.getWidth >= 10) - val canMakeRegion = playerHasPermission && !isSelectionNull && selectionHasEnoughSpace + val canMakeRegion = playerHasPermission && !isSelected && selectionHasEnoughSpace val iconItemStack = { - val lore = { - if (!playerHasPermission) + if (!playerHasPermission) { Seq(s"${RED}このワールドでは", s"${RED}保護を作成できません") - else if (isSelectionNull) + } else if (!isSelected) { Seq(s"${RED}範囲指定されていません", s"${RED}先に木の斧で2か所クリックしてネ") - else if (!selectionHasEnoughSpace) + } else if (!selectionHasEnoughSpace) { Seq(s"${RED}選択された範囲が狭すぎます", s"${RED}一辺当たり最低10ブロック以上にしてネ") - else + } else { Seq(s"$DARK_GREEN${UNDERLINE}範囲指定されています", s"$DARK_GREEN${UNDERLINE}クリックすると保護を作成します") + } } ++ { if (playerHasPermission) Seq( s"${GRAY}Y座標は自動で全範囲保護されます", s"${YELLOW}A new region has been claimed", - s"${YELLOW}named '${getName}_$regionCount'.", + s"${YELLOW}named '${getName}_${regionCount.value}'.", s"${GRAY}と出れば保護設定完了です", s"${RED}赤色で別の英文が出た場合", s"${GRAY}保護の設定に失敗しています", @@ -108,7 +109,7 @@ object RegionMenu extends Menu { } import scala.util.chaining._ - new IconItemStackBuilder(Material.GOLD_AXE) + new IconItemStackBuilder(Material.GOLDEN_AXE) .tap { b => if (canMakeRegion) b.enchanted() } .title(s"$YELLOW$UNDERLINE${BOLD}保護の作成") .lore(lore.toList) @@ -120,7 +121,7 @@ object RegionMenu extends Menu { action.FilteredButtonEffect(ClickEventFilter.LEFT_CLICK)(_ => if (!playerHasPermission) MessageEffect(s"${RED}このワールドでは保護を作成できません") - else if (isSelectionNull) + else if (!isSelected) SequentialEffect( MessageEffect(s"${RED}先に木の斧で範囲を指定してからこのボタンを押してください"), FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 0.5f) @@ -133,7 +134,7 @@ object RegionMenu extends Menu { else SequentialEffect( CommandEffect("/expand vert"), - CommandEffect(s"rg claim ${player.getName}_$regionCount"), + CommandEffect(s"rg claim ${player.getName}_${regionCount.value}"), gridRegionAPI.createAndClaimRegionSelectedOnWorldGuard, CommandEffect("/sel"), FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f) @@ -153,7 +154,7 @@ object RegionMenu extends Menu { s"$GREEN④メニューの${YELLOW}金の斧${GREEN}をクリック" ) - val iconItemStack = new IconItemStackBuilder(Material.WOOD_AXE) + val iconItemStack = new IconItemStackBuilder(Material.WOODEN_AXE) .title(s"$YELLOW$UNDERLINE${BOLD}保護設定用の木の斧を召喚") .lore( wandUsage ++ List( diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/ServerSwitchMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/ServerSwitchMenu.scala index f037604ab3..bf06a2b42b 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/ServerSwitchMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/ServerSwitchMenu.scala @@ -53,7 +53,7 @@ object ServerSwitchMenu extends Menu { ) case object EDEN - extends Server(s"$YELLOW${BOLD}エデン", "s2", ChestSlotRef(0, 1), Material.DIAMOND_SPADE) + extends Server(s"$YELLOW${BOLD}エデン", "s2", ChestSlotRef(0, 1), Material.DIAMOND_SHOVEL) case object VALHALLA extends Server(s"$YELLOW${BOLD}ヴァルハラ", "s3", ChestSlotRef(0, 2), Material.DIAMOND_AXE) diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala b/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala index b31e314295..6cf377d8f2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala @@ -15,7 +15,7 @@ import com.github.unchama.seichiassist.menus.home.{ConfirmationMenuEnvironment, import com.github.unchama.seichiassist.menus.minestack.{ CategorizedMineStackMenu, MineStackMainMenu, - MineStackSelectItemColorMenu + MineStackSelectItemKindMenu } import com.github.unchama.seichiassist.menus.nicknames.NickNameMenu import com.github.unchama.seichiassist.menus.ranking.{RankingMenu, RankingRootMenu} @@ -134,9 +134,8 @@ object TopLevelRouter { new AchievementGroupMenu.Environment implicit lazy val passiveSkillMenuEnv: PassiveSkillMenu.Environment = new PassiveSkillMenu.Environment - implicit lazy val mineStackSelectItemColorMenuEnv - : MineStackSelectItemColorMenu.Environment = - new MineStackSelectItemColorMenu.Environment + implicit lazy val mineStackSelectItemColorMenuEnv: MineStackSelectItemKindMenu.Environment = + new MineStackSelectItemKindMenu.Environment implicit lazy val seichiRankingMenuEnv: RankingMenu[SeichiAmountData]#Environment = new RankingMenu.Environment @@ -163,7 +162,7 @@ object TopLevelRouter { implicit lazy val ioCanOpenNickNameMenu: IO CanOpen NickNameMenu.type = _.open - implicit lazy val ioCanOpenSelectItemColorMenu: IO CanOpen MineStackSelectItemColorMenu = + implicit lazy val ioCanOpenSelectItemColorMenu: IO CanOpen MineStackSelectItemKindMenu = _.open implicit lazy val ioCanOpenAchievementGroupMenu: IO CanOpen AchievementGroupMenu = _.open implicit lazy val ioCanOpenHomeConfirmationMenu diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/VoteMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/VoteMenu.scala index 14b414cf4c..a8c87009d3 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/VoteMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/VoteMenu.scala @@ -149,7 +149,7 @@ object VoteMenu extends Menu { } val showVoteURLButton: Button = Button( - new IconItemStackBuilder(Material.BOOK_AND_QUILL) + new IconItemStackBuilder(Material.WRITABLE_BOOK) .title(s"$YELLOW$UNDERLINE${BOLD}投票ページにアクセス") .lore( List( @@ -181,7 +181,7 @@ object VoteMenu extends Menu { fairySummonCost <- fairyAPI.fairySummonCost(player) } yield { Button( - new IconItemStackBuilder(Material.WATCH) + new IconItemStackBuilder(Material.CLOCK) .title(s"$AQUA$UNDERLINE${BOLD}マナ妖精 時間設定") .lore( List( @@ -288,7 +288,7 @@ object VoteMenu extends Menu { LeftClickButtonEffect { SequentialEffect( FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f), - DeferredEffect(IO(fairySpeechAPI.togglePlaySoundOnSpeech)) + fairySpeechAPI.togglePlaySoundOnSpeech ) } ) diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementCategoryMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementCategoryMenu.scala index 587499d69b..82b9028da4 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementCategoryMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementCategoryMenu.scala @@ -37,12 +37,12 @@ object AchievementCategoryMenu { ChestSlotRef(1, 5) -> (BrokenBlockRanking, Material.DIAMOND_PICKAXE) ) case Building => - Map(ChestSlotRef(1, 4) -> (PlacedBlockAmount, Material.BIRCH_WOOD_STAIRS)) + Map(ChestSlotRef(1, 4) -> (PlacedBlockAmount, Material.BIRCH_STAIRS)) case Login => Map( ChestSlotRef(1, 1) -> (PlayTime, Material.COMPASS), ChestSlotRef(1, 3) -> (TotalLogins, Material.BOOK), - ChestSlotRef(1, 5) -> (ConsecutiveLogins, Material.BOOK_AND_QUILL), + ChestSlotRef(1, 5) -> (ConsecutiveLogins, Material.WRITABLE_BOOK), ChestSlotRef(1, 7) -> (Anniversaries, Material.NETHER_STAR) ) case Challenges => @@ -53,8 +53,8 @@ object AchievementCategoryMenu { case Specials => Map( ChestSlotRef(1, 2) -> (OfficialEvent, Material.BLAZE_POWDER), - ChestSlotRef(1, 4) -> (VoteCounts, Material.YELLOW_FLOWER), - ChestSlotRef(1, 6) -> (Secrets, Material.DIAMOND_BARDING) + ChestSlotRef(1, 4) -> (VoteCounts, Material.DANDELION), + ChestSlotRef(1, 6) -> (Secrets, Material.DIAMOND_HORSE_ARMOR) ) } diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementMenu.scala index fe318872ad..be837b5c4c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/achievement/AchievementMenu.scala @@ -40,11 +40,11 @@ object AchievementMenu extends Menu { val categoryLayout: Map[Int, AchievementCategoryRepr] = Map( - ChestSlotRef(1, 1) -> (BrokenBlock, Material.GOLD_PICKAXE), + ChestSlotRef(1, 1) -> (BrokenBlock, Material.GOLDEN_PICKAXE), ChestSlotRef(1, 3) -> (Building, Material.GLASS), ChestSlotRef(1, 5) -> (Login, Material.COMPASS), ChestSlotRef(1, 7) -> (Challenges, Material.BLAZE_POWDER), - ChestSlotRef(2, 4) -> (Specials, Material.EYE_OF_ENDER) + ChestSlotRef(2, 4) -> (Specials, Material.ENDER_EYE) ) def buttonFor( @@ -88,7 +88,7 @@ object AchievementMenu extends Menu { categoryLayout.view.mapValues(category => buttonFor(category)).toMap val toggleTitleToPlayerLevelButton = Button( - new IconItemStackBuilder(Material.REDSTONE_TORCH_ON) + new IconItemStackBuilder(Material.REDSTONE_TORCH) .title(ColorScheme.navigation("整地Lvを表示")) .lore( List( diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/gridregion/GridRegionMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/gridregion/GridRegionMenu.scala index ed58f828e9..630ee03d79 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/gridregion/GridRegionMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/gridregion/GridRegionMenu.scala @@ -80,7 +80,7 @@ object GridRegionMenu extends Menu { for { currentLengthChangePerClick <- gridRegionAPI.lengthChangePerClick(player) } yield { - val iconItemStack = new IconItemStackBuilder(Material.STAINED_GLASS_PANE, 1) + val iconItemStack = new IconItemStackBuilder(Material.WHITE_STAINED_GLASS_PANE) .title(s"${GREEN}拡張単位の変更") .lore( List( @@ -143,11 +143,15 @@ object GridRegionMenu extends Menu { case HorizontalAxisAlignedSubjectiveDirection.Right => "右へ" } - val stainedGlassPaneDurability = relativeDirection match { - case HorizontalAxisAlignedSubjectiveDirection.Ahead => 14 - case HorizontalAxisAlignedSubjectiveDirection.Left => 10 - case HorizontalAxisAlignedSubjectiveDirection.Behind => 13 - case HorizontalAxisAlignedSubjectiveDirection.Right => 5 + val material = relativeDirection match { + case HorizontalAxisAlignedSubjectiveDirection.Ahead => + Material.RED_STAINED_GLASS_PANE + case HorizontalAxisAlignedSubjectiveDirection.Behind => + Material.GREEN_STAINED_GLASS_PANE + case HorizontalAxisAlignedSubjectiveDirection.Left => + Material.PURPLE_STAINED_GLASS_PANE + case HorizontalAxisAlignedSubjectiveDirection.Right => + Material.YELLOW_STAINED_GLASS_PANE } def updateCurrentRegionShapeTo( @@ -169,10 +173,10 @@ object GridRegionMenu extends Menu { } Button( - new IconItemStackBuilder( - Material.STAINED_GLASS_PANE, - stainedGlassPaneDurability.toShort - ).title(s"$DARK_GREEN${relativeDirectionString}ユニット増やす/減らす").lore(lore).build(), + new IconItemStackBuilder(material) + .title(s"$DARK_GREEN${relativeDirectionString}ユニット増やす/減らす") + .lore(lore) + .build(), LeftClickButtonEffect(updateCurrentRegionShapeTo(expandedShape)), RightClickButtonEffect(updateCurrentRegionShapeTo(contractedShape)) ) @@ -194,7 +198,7 @@ object GridRegionMenu extends Menu { } val resetSettingButton: Button = { - val itemStack = new IconItemStackBuilder(Material.STAINED_GLASS_PANE, 4) + val itemStack = new IconItemStackBuilder(Material.YELLOW_STAINED_GLASS_PANE) .title(s"${RED}全設定リセット") .lore(List(s"$RED${UNDERLINE}取り扱い注意!!")) .build() @@ -225,10 +229,10 @@ object GridRegionMenu extends Menu { s"${GRAY}右方向:${showRegionShapeDimension(shape.right)}", s"${GRAY}左方向:${showRegionShapeDimension(shape.left)}", s"${GRAY}保護ユニット数:$AQUA${shape.regionUnits.count}", - s"${GRAY}保護ユニット上限値:$RED${gridRegionAPI.regionUnitLimit(worldName).limit}" + s"${GRAY}保護ユニット上限値:$RED${gridRegionAPI.regionUnitLimit(worldName).limit.count}" ) - val itemStack = new IconItemStackBuilder(Material.STAINED_GLASS_PANE, 11) + val itemStack = new IconItemStackBuilder(Material.BLUE_STAINED_GLASS_PANE) .title(s"${DARK_GREEN}設定") .lore(lore) .build() @@ -245,7 +249,7 @@ object GridRegionMenu extends Menu { canCreateRegionResult match { case RegionCreationResult.Success => Button( - new IconItemStackBuilder(Material.WOOL, 11) + new IconItemStackBuilder(Material.LIGHT_BLUE_WOOL) .title(s"${GREEN}保護作成") .lore(List(s"${DARK_GREEN}保護作成可能です", s"$RED${UNDERLINE}クリックで作成")) .build(), @@ -257,14 +261,14 @@ object GridRegionMenu extends Menu { ) case RegionCreationResult.WorldProhibitsRegionCreation => Button( - new IconItemStackBuilder(Material.WOOL, 14) + new IconItemStackBuilder(Material.RED_WOOL) .title(s"${RED}保護作成") .lore(List(s"$RED${UNDERLINE}このワールドでは保護を作成できません")) .build() ) case RegionCreationResult.Error => Button( - new IconItemStackBuilder(Material.WOOL, 1) + new IconItemStackBuilder(Material.RED_WOOL) .title(s"${RED}以下の原因により保護の作成できません") .lore( List( diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/home/HomeMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/home/HomeMenu.scala index f899665d95..8f92a0279a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/home/HomeMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/home/HomeMenu.scala @@ -200,7 +200,7 @@ case class HomeMenuButtonComputations(player: Player)( homeOpt <- homeReadAPI.get(player.getUniqueId, homeId) } yield { Button( - new IconItemStackBuilder(Material.BED) + new IconItemStackBuilder(Material.WHITE_BED) .title(s"$YELLOW$UNDERLINE${BOLD}ホームポイント${homeNumber}を設定") .lore( List( @@ -231,7 +231,7 @@ case class HomeMenuButtonComputations(player: Player)( homeOpt <- homeReadAPI.get(player.getUniqueId, homeId) } yield { Button( - new IconItemStackBuilder(Material.WOOL, 14) + new IconItemStackBuilder(Material.WHITE_WOOL) .title(s"$RED$UNDERLINE${BOLD}ホームポイント${homeNumber}を削除") .lore( List( @@ -242,7 +242,7 @@ case class HomeMenuButtonComputations(player: Player)( ) .build(), LeftClickButtonEffect { - FocusedSoundEffect(Sound.BLOCK_ENDERCHEST_CLOSE, 1f, 0.1f) + FocusedSoundEffect(Sound.BLOCK_ENDER_CHEST_CLOSE, 1f, 0.1f) SequentialEffect( environment .ioCanOpenHomeRemoveConfirmationMenu @@ -272,7 +272,7 @@ case class HomeChangeConfirmationMenu(changeHomeNumber: Int, homeName: String = val changeButton: Button = Button( - new IconItemStackBuilder(Material.WOOL, durability = 5).title(s"${GREEN}変更する").build(), + new IconItemStackBuilder(Material.LIME_WOOL).title(s"${GREEN}変更する").build(), LeftClickButtonEffect { SequentialEffect( FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f), @@ -284,7 +284,7 @@ case class HomeChangeConfirmationMenu(changeHomeNumber: Int, homeName: String = def cancelButton(implicit environment: Environment): Button = Button( - new IconItemStackBuilder(Material.WOOL, durability = 14).title(s"${RED}変更しない").build(), + new IconItemStackBuilder(Material.RED_WOOL).title(s"${RED}変更しない").build(), LeftClickButtonEffect { FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f) environment.ioCanOpenHomeMenu.open(new HomeMenu) @@ -324,7 +324,7 @@ case class HomeRemoveConfirmationMenu(removeHomeNumber: Int, homeName: String = val removeButton: Button = Button( - new IconItemStackBuilder(Material.WOOL, durability = 5).title(s"${GREEN}削除する").build(), + new IconItemStackBuilder(Material.LIME_WOOL).title(s"${GREEN}削除する").build(), LeftClickButtonEffect { SequentialEffect( FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f), @@ -336,7 +336,7 @@ case class HomeRemoveConfirmationMenu(removeHomeNumber: Int, homeName: String = def cancelButton(implicit environment: Environment): Button = Button( - new IconItemStackBuilder(Material.WOOL, durability = 14).title(s"${RED}変更しない").build(), + new IconItemStackBuilder(Material.RED_WOOL).title(s"${RED}変更しない").build(), LeftClickButtonEffect { FocusedSoundEffect(Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1f, 1f) environment.ioCanOpenHomeMenu.open(new HomeMenu) diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/CategorizedMineStackMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/CategorizedMineStackMenu.scala index 3df3df405d..645d120cd8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/CategorizedMineStackMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/CategorizedMineStackMenu.scala @@ -22,7 +22,7 @@ object CategorizedMineStackMenu { class Environment( implicit val ioCanOpenMineStackMainMenu: IO CanOpen MineStackMainMenu.type, val ioCanOpenCategorizedMenu: IO CanOpen CategorizedMineStackMenu, - val ioCanOpenSelectItemColorMenu: IO CanOpen MineStackSelectItemColorMenu, + val ioCanOpenSelectItemColorMenu: IO CanOpen MineStackSelectItemKindMenu, val onMainThread: OnMinecraftServerThread[IO], val mineStackAPI: MineStackAPI[IO, Player, ItemStack], implicit val gachaPrizeAPI: GachaPrizeAPI[IO, ItemStack, Player] diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackButtons.scala b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackButtons.scala index 5a2d1ba2fb..19a7bfca12 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackButtons.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackButtons.scala @@ -12,7 +12,7 @@ import com.github.unchama.seichiassist.subsystems.minestack.MineStackAPI import com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobject.{ MineStackObject, MineStackObjectGroup, - MineStackObjectWithColorVariants + MineStackObjectWithKindVariants } import com.github.unchama.seichiassist.util.InventoryOperations.grantItemStacksEffect import com.github.unchama.targetedeffect.commandsender.MessageEffect @@ -38,7 +38,7 @@ private[minestack] case class MineStackButtons(player: Player)( mineStackObjectGroup match { case Left(mineStackObject) => mineStackObject - case Right(MineStackObjectWithColorVariants(representative, _)) => + case Right(MineStackObjectWithKindVariants(representative, _)) => representative } } @@ -69,7 +69,7 @@ private[minestack] case class MineStackButtons(player: Player)( val mineStackObject = mineStackObjectGroup match { case Left(mineStackObject) => mineStackObject - case Right(MineStackObjectWithColorVariants(representative, _)) => + case Right(MineStackObjectWithKindVariants(representative, _)) => representative } @@ -94,17 +94,17 @@ private[minestack] case class MineStackButtons(player: Player)( } setLore { - val itemDetail = List(s"$RESET$GREEN${stackedAmount.formatted("%,d")}個") val operationDetail = if (mineStackObjectGroup.isRight) { - List(s"$RESET${DARK_GREEN}クリックで色選択画面を開きます。") + List(s"$RESET${DARK_GREEN}クリックで種類選択画面を開きます。") } else { List( + s"$RESET$GREEN${String.format("%,d", stackedAmount)}個", s"$RESET$DARK_RED${UNDERLINE}左クリックで1スタック取り出し", s"$RESET$DARK_AQUA${UNDERLINE}右クリックで1個取り出し" ) } - (itemDetail ++ operationDetail).asJava + operationDetail.asJava } setAmount(1) @@ -120,7 +120,7 @@ private[minestack] case class MineStackButtons(player: Player)( oldPage: Int )( implicit onMainThread: OnMinecraftServerThread[IO], - canOpenCategorizedMineStackMenu: IO CanOpen MineStackSelectItemColorMenu + canOpenCategorizedMineStackMenu: IO CanOpen MineStackSelectItemKindMenu ): IO[Button] = RecomputedButton { for { itemStack <- getMineStackObjectIconItemStack(mineStackObjectGroup) @@ -152,7 +152,7 @@ private[minestack] case class MineStackButtons(player: Player)( oldPage: Int )( implicit onMainThread: OnMinecraftServerThread[IO], - canOpenMineStackSelectItemColorMenu: IO CanOpen MineStackSelectItemColorMenu + canOpenMineStackSelectItemColorMenu: IO CanOpen MineStackSelectItemKindMenu ): Kleisli[IO, Player, Unit] = { mineStackObjectGroup match { case Left(mineStackObject) => @@ -168,7 +168,7 @@ private[minestack] case class MineStackButtons(player: Player)( ) case Right(mineStackObjectWithColorVariants) => canOpenMineStackSelectItemColorMenu.open( - MineStackSelectItemColorMenu(mineStackObjectWithColorVariants, oldPage) + MineStackSelectItemKindMenu(mineStackObjectWithColorVariants, oldPage) ) } } diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackMainMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackMainMenu.scala index dadbab3c2c..198f52f0bb 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackMainMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackMainMenu.scala @@ -39,8 +39,8 @@ object MineStackMainMenu extends Menu { def iconMaterialFor(category: MineStackObjectCategory): Material = category match { case ORES => Material.DIAMOND_ORE case MOB_DROP => Material.ENDER_PEARL - case AGRICULTURAL => Material.SEEDS - case BUILDING => Material.SMOOTH_BRICK + case AGRICULTURAL => Material.WHEAT_SEEDS + case BUILDING => Material.STONE_BRICKS case REDSTONE_AND_TRANSPORTATION => Material.REDSTONE case GACHA_PRIZES => Material.GOLDEN_APPLE } diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemColorMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemKindMenu.scala similarity index 84% rename from src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemColorMenu.scala rename to src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemKindMenu.scala index 4b150c03a2..64043c1a13 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemColorMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/minestack/MineStackSelectItemKindMenu.scala @@ -10,13 +10,13 @@ import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMain import com.github.unchama.seichiassist.menus.CommonButtons import com.github.unchama.seichiassist.subsystems.gachaprize.GachaPrizeAPI import com.github.unchama.seichiassist.subsystems.minestack.MineStackAPI -import com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobject.MineStackObjectWithColorVariants +import com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobject.MineStackObjectWithKindVariants import eu.timepit.refined.auto._ import org.bukkit.ChatColor.{BOLD, DARK_BLUE} import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack -object MineStackSelectItemColorMenu { +object MineStackSelectItemKindMenu { class Environment( implicit val canOpenCategorizedMineStackMenu: CanOpen[IO, CategorizedMineStackMenu], @@ -26,22 +26,22 @@ object MineStackSelectItemColorMenu { } -case class MineStackSelectItemColorMenu( - group: MineStackObjectWithColorVariants[ItemStack], +case class MineStackSelectItemKindMenu( + group: MineStackObjectWithKindVariants[ItemStack], oldPage: Int ) extends Menu { import com.github.unchama.menuinventory.syntax._ - override type Environment = MineStackSelectItemColorMenu.Environment + override type Environment = MineStackSelectItemKindMenu.Environment override val frame: MenuFrame = - MenuFrame(6.chestRows, s"$DARK_BLUE${BOLD}MineStack(アイテム色選択)") + MenuFrame(6.chestRows, s"$DARK_BLUE${BOLD}MineStack(アイテム種類選択)") override def computeMenuLayout( player: Player )(implicit environment: Environment): IO[MenuSlotLayout] = { import environment._ - val buttonMapping = (List(group.representative) ++ group.coloredVariants).zipWithIndex.map { + val buttonMapping = (List(group.representative) ++ group.kindVariants).zipWithIndex.map { case (inListMineStackObj, index) => index -> MineStackButtons(player).getMineStackObjectButtonOf(inListMineStackObj) } ++ List( diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/ranking/RankingMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/ranking/RankingMenu.scala index 8b45a77a6b..12bf1e7667 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/ranking/RankingMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/ranking/RankingMenu.scala @@ -160,7 +160,7 @@ case class RankingMenu[R](template: RankingMenuTemplate[R], pageIndex: Int = 0) private def rankingSection(ranking: Ranking[R]): Seq[(Int, Button)] = { def entry(position: Int, record: RankingRecord[R]): Button = { Button( - new SkullItemStackBuilder(record.playerName) + new SkullItemStackBuilder(record.uuid) .title(s"$YELLOW$BOLD${position}位:$WHITE${record.playerName}") .lore(template.recordDataLore(record.value)) .build() diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/skill/ActiveSkillMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/skill/ActiveSkillMenu.scala index 7ad8f10c9b..fd726662ce 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/skill/ActiveSkillMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/skill/ActiveSkillMenu.scala @@ -3,7 +3,6 @@ package com.github.unchama.seichiassist.menus.skill import cats.data.Kleisli import cats.effect.concurrent.Ref import cats.effect.{ConcurrentEffect, IO, SyncIO} -import com.github.unchama.concurrent.NonServerThreadContextShift import com.github.unchama.generic.effect.concurrent.TryableFiber import com.github.unchama.itemstackbuilder.{ AbstractItemStackBuilder, @@ -155,7 +154,7 @@ object ActiveSkillMenu extends Menu { case skill: ActiveSkill => skill match { case SeichiSkill.DualBreak => - new IconItemStackBuilder(Material.GRASS) + new IconItemStackBuilder(Material.GRASS_BLOCK) case SeichiSkill.TrialBreak => new IconItemStackBuilder(Material.STONE) case SeichiSkill.Explosion => @@ -178,11 +177,11 @@ object ActiveSkillMenu extends Menu { case SeichiSkill.Thunderstorm => new IconItemStackBuilder(Material.MINECART) case SeichiSkill.StarlightBreaker => - new IconItemStackBuilder(Material.STORAGE_MINECART) + new IconItemStackBuilder(Material.CHEST_MINECART) case SeichiSkill.EarthDivide => - new IconItemStackBuilder(Material.POWERED_MINECART) + new IconItemStackBuilder(Material.FURNACE_MINECART) case SeichiSkill.HeavenGaeBolg => - new IconItemStackBuilder(Material.EXPLOSIVE_MINECART) + new IconItemStackBuilder(Material.TNT_MINECART) case SeichiSkill.Decision => new IconItemStackBuilder(Material.HOPPER_MINECART) @@ -210,9 +209,9 @@ object ActiveSkillMenu extends Menu { case SeichiSkill.LavaCondensation => new IconItemStackBuilder(Material.NETHERRACK) case SeichiSkill.MoerakiBoulders => - new IconItemStackBuilder(Material.NETHER_BRICK) + new IconItemStackBuilder(Material.NETHER_BRICKS) case SeichiSkill.Eldfell => - new IconItemStackBuilder(Material.MAGMA) + new IconItemStackBuilder(Material.MAGMA_BLOCK) case SeichiSkill.VenderBlizzard => new IconItemStackBuilder(Material.NETHER_STAR) case SeichiSkill.AssaultArmor => @@ -282,9 +281,7 @@ object ActiveSkillMenu extends Menu { } } - def seichiSkillButton[F[ - _ - ]: ConcurrentEffect: NonServerThreadContextShift: DiscordNotificationAPI]( + def seichiSkillButton[F[_]: ConcurrentEffect: DiscordNotificationAPI]( state: SkillSelectionState, skill: SeichiSkill )(implicit environment: Environment): Button = { @@ -380,12 +377,12 @@ object ActiveSkillMenu extends Menu { .sendPlainText(notificationMessage) .toIO ), - Kleisli.liftF(IO { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference( + Kleisli.liftF( + SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO( s"$GOLD$BOLD$notificationMessage" ) - }), - BroadcastSoundEffect(Sound.ENTITY_ENDERDRAGON_DEATH, 1.0f, 1.2f) + ), + BroadcastSoundEffect(Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 1.2f) ) ) } else (unlockedState, emptyEffect) diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/FirstPage.scala b/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/FirstPage.scala index 8724203955..04dd4d1cce 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/FirstPage.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/FirstPage.scala @@ -279,14 +279,13 @@ object FirstPage extends Menu { val computeRegionMenuButton: IO[Button] = IO { val (buttonLore, effect) = { val world = getWorld - val regionManager = WorldGuardWrapper.getRegionManager(world) - if (regionManager.isEmpty) { + if (!WorldGuardWrapper.canProtectionWorld(world)) { (List(s"${GRAY}このワールドでは土地の保護は行なえません"), LeftClickButtonEffect(emptyEffect)) } else { - val maxRegionCount = WorldGuardWrapper.getMaxRegionCount(player, world) + val maxRegionCount = WorldGuardWrapper.getWorldMaxRegion(world) val currentPlayerRegionCount = - WorldGuardWrapper.getRegionCountOfPlayer(player, world) + WorldGuardWrapper.getMaxRegion(player, world) ( List( @@ -370,7 +369,7 @@ object FirstPage extends Menu { s"$RESET$DARK_GREEN${UNDERLINE}クリックで開く" ) - new IconItemStackBuilder(Material.ENDER_PORTAL_FRAME) + new IconItemStackBuilder(Material.END_PORTAL_FRAME) .title(s"$YELLOW$UNDERLINE${BOLD}4次元ポケットを開く") .lore(loreHeading ++ loreAnnotation) .build() @@ -405,10 +404,10 @@ object FirstPage extends Menu { environment.enderChestAccessApi.openEnderChestOrNotifyInsufficientLevel.flatMap { case Right(_) => // 開くのに成功した場合の音 - FocusedSoundEffect(Sound.BLOCK_GRASS_PLACE, 1.0f, 0.1f) + FocusedSoundEffect(Sound.BLOCK_ENDER_CHEST_OPEN, 1.0f, 1.0f) case Left(_) => // 開くのに失敗した場合の音 - FocusedSoundEffect(Sound.BLOCK_ENDERCHEST_OPEN, 1.0f, 1.0f) + FocusedSoundEffect(Sound.BLOCK_GRASS_PLACE, 1.0f, 0.1f) } ) ) @@ -657,7 +656,7 @@ object FirstPage extends Menu { def homePointMenuButton(implicit ioCanOpenHomeMenu: IO CanOpen HomeMenu): Button = { val iconItemStack = - new IconItemStackBuilder(Material.BED) + new IconItemStackBuilder(Material.WHITE_BED) .title(s"$YELLOW$UNDERLINE${BOLD}ホームメニューを開く") .lore(List(s"$RESET${GRAY}ホームポイントに関するメニュー", s"$RESET$DARK_RED${UNDERLINE}クリックで開く")) .build() @@ -673,7 +672,7 @@ object FirstPage extends Menu { val fastCraftButton: Button = { val iconItemStack = - new IconItemStackBuilder(Material.WORKBENCH) + new IconItemStackBuilder(Material.CRAFTING_TABLE) .title(s"$YELLOW$UNDERLINE${BOLD}FastCraft機能") .lore( List( diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/SecondPage.scala b/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/SecondPage.scala index 00963b7a50..fd54ffdb6a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/SecondPage.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/stickmenu/SecondPage.scala @@ -489,17 +489,18 @@ object SecondPage extends Menu { } val JMSNavigationButton: Button = { - val iconItemStack = new IconItemStackBuilder(Material.SIGN) - .title(s"$YELLOW$UNDERLINE${BOLD}JapanMinecraftServerリンク") - .lore( - List( - s"$RESET${DARK_GRAY}クリックするとチャット欄に", - s"$RESET${DARK_GRAY}URLが表示されますので", - s"$RESET${DARK_GRAY}Tキーを押してから", - s"$RESET${DARK_GRAY}そのURLをクリックしてください" + val iconItemStack = + new IconItemStackBuilder(Material.OAK_SIGN) // 1.16からSIGNが素材ごとに別れたので、オークに決めうちしておく + .title(s"$YELLOW$UNDERLINE${BOLD}JapanMinecraftServerリンク") + .lore( + List( + s"$RESET${DARK_GRAY}クリックするとチャット欄に", + s"$RESET${DARK_GRAY}URLが表示されますので", + s"$RESET${DARK_GRAY}Tキーを押してから", + s"$RESET${DARK_GRAY}そのURLをクリックしてください" + ) ) - ) - .build() + .build() Button( iconItemStack, @@ -514,7 +515,7 @@ object SecondPage extends Menu { } val appleConversionButton: Button = { - val iconItemStack = new IconItemStackBuilder(Material.GOLDEN_APPLE, durability = 1) + val iconItemStack = new IconItemStackBuilder(Material.GOLDEN_APPLE) .title(s"$YELLOW$UNDERLINE${BOLD}GT景品→椎名林檎変換システム") .lore( List( diff --git a/src/main/scala/com/github/unchama/seichiassist/seichiskill/BlockSearching.scala b/src/main/scala/com/github/unchama/seichiassist/seichiskill/BlockSearching.scala index 9f97c27841..304a22c10b 100644 --- a/src/main/scala/com/github/unchama/seichiassist/seichiskill/BlockSearching.scala +++ b/src/main/scala/com/github/unchama/seichiassist/seichiskill/BlockSearching.scala @@ -5,8 +5,10 @@ import com.github.unchama.seichiassist.MaterialSets import com.github.unchama.seichiassist.MaterialSets.BlockBreakableBySkill import com.github.unchama.seichiassist.data.XYZTuple import com.github.unchama.seichiassist.util.BreakUtil +import com.github.unchama.util.external.ExternalPlugins import org.bukkit.Material import org.bukkit.block.Block +import org.bukkit.block.data.Waterlogged import org.bukkit.entity.Player import scala.collection.{Set, mutable} @@ -37,18 +39,35 @@ object BlockSearching { relativeVectors.collect { case XYZTuple(x, y, z) => val targetBlock = referencePoint.getRelative(x, y, z) + val waterloggedMaterials = Set( + Material.WATER, + Material.BUBBLE_COLUMN, + Material.TALL_SEAGRASS, + Material.SEAGRASS, + Material.KELP, + Material.KELP_PLANT + ) - if (BreakUtil.canBreakWithSkill(player, targetBlock, lockedBlocks)) - targetBlock.getType match { - case Material.STATIONARY_LAVA | Material.LAVA => - lavaBlocks.add(targetBlock) - case Material.STATIONARY_WATER | Material.WATER => - waterBlocks.add(targetBlock) - case _ => - MaterialSets - .refineBlock(targetBlock, MaterialSets.materials) - .foreach(b => solidBlocks.add(b)) + if (BreakUtil.canBreakWithSkill(player, targetBlock, lockedBlocks)) { + if (targetBlock.getType == Material.LAVA) { + lavaBlocks.add(targetBlock) + } else if ( + waterloggedMaterials.contains(targetBlock.getType) || (targetBlock + .getBlockData + .isInstanceOf[Waterlogged] && ExternalPlugins + .getCoreProtectWrapper + .isNotEditedBlock(targetBlock) && targetBlock + .getBlockData + .asInstanceOf[Waterlogged] + .isWaterlogged) + ) { + waterBlocks.add(targetBlock) + } else { + MaterialSets + .refineBlock(targetBlock, MaterialSets.materials) + .foreach(b => solidBlocks.add(b)) } + } } Result(solidBlocks.toList, waterBlocks.toList, lavaBlocks.toList) @@ -63,10 +82,7 @@ object BlockSearching { targetBlock => val blockMaterials = Set(referenceBlock.getType, targetBlock.getType) - val identifications = List( - Set(Material.DIRT, Material.GRASS), - Set(Material.REDSTONE_ORE, Material.GLOWING_REDSTONE_ORE) - ) + val identifications = List(Set(Material.DIRT, Material.GRASS), Set(Material.REDSTONE_ORE)) // マテリアルが同一視により等しくなるかどうか blockMaterials.size == 1 || identifications.exists(blockMaterials.subsetOf) diff --git a/src/main/scala/com/github/unchama/seichiassist/seichiskill/SkillRange.scala b/src/main/scala/com/github/unchama/seichiassist/seichiskill/SkillRange.scala index d5731b0b78..f5ff56819f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/seichiskill/SkillRange.scala +++ b/src/main/scala/com/github/unchama/seichiassist/seichiskill/SkillRange.scala @@ -41,24 +41,22 @@ object AssaultSkillRange { } case class Water(effectChunkSize: XYZTuple) extends AssaultSkillRange { - override val blockMaterialConversion: Material => Material = { - case Material.WATER => Material.ICE - case x => x + override val blockMaterialConversion: Material => Material = { m => + if (m == Material.WATER || m == Material.BUBBLE_COLUMN) Material.ICE else m } } case class Lava(effectChunkSize: XYZTuple) extends AssaultSkillRange { - override val blockMaterialConversion: Material => Material = { - case Material.LAVA => Material.MAGMA - case x => x + override val blockMaterialConversion: Material => Material = { m => + if (m == Material.LAVA) Material.MAGMA_BLOCK else m } } case class Liquid(effectChunkSize: XYZTuple) extends AssaultSkillRange { - override val blockMaterialConversion: Material => Material = { - case Material.WATER => Material.ICE - case Material.LAVA => Material.MAGMA - case x => x + override val blockMaterialConversion: Material => Material = { m => + if (m == Material.WATER || m == Material.BUBBLE_COLUMN) Material.ICE + else if (m == Material.LAVA) Material.MAGMA_BLOCK + else m } } diff --git a/src/main/scala/com/github/unchama/seichiassist/seichiskill/assault/AssaultRoutine.scala b/src/main/scala/com/github/unchama/seichiassist/seichiskill/assault/AssaultRoutine.scala index 190aee7bab..e3a8ac2324 100644 --- a/src/main/scala/com/github/unchama/seichiassist/seichiskill/assault/AssaultRoutine.scala +++ b/src/main/scala/com/github/unchama/seichiassist/seichiskill/assault/AssaultRoutine.scala @@ -18,6 +18,7 @@ import com.github.unchama.seichiassist.{DefaultEffectEnvironment, MaterialSets, import org.bukkit.ChatColor._ import org.bukkit.enchantments.Enchantment import org.bukkit.entity.Player +import org.bukkit.inventory.meta.Damageable import org.bukkit.{GameMode, Location, Material, Sound} object AssaultRoutine { @@ -141,7 +142,7 @@ object AssaultRoutine { // 減る耐久値の計算 val durability = - (toolToBeUsed.getDurability + + (toolToBeUsed.getItemMeta.asInstanceOf[Damageable].getDamage + BreakUtil.calcDurability( toolToBeUsed.getEnchantmentLevel(Enchantment.DURABILITY), breakTargets @@ -161,7 +162,11 @@ object AssaultRoutine { } // 耐久値を減らす - if (!toolToBeUsed.getItemMeta.isUnbreakable) toolToBeUsed.setDurability(durability) + if (!toolToBeUsed.getItemMeta.isUnbreakable) { + val meta = toolToBeUsed.getItemMeta + meta.asInstanceOf[Damageable].setDamage(durability) + toolToBeUsed.setItemMeta(meta) + } // ブロックを書き換える if (shouldBreakAllBlocks) { @@ -178,7 +183,7 @@ object AssaultRoutine { ) } else { if (shouldRemoveOrCondenseWater) foundWaters.foreach(_.setType(Material.PACKED_ICE)) - if (shouldRemoveOrCondenseLava) foundLavas.foreach(_.setType(Material.MAGMA)) + if (shouldRemoveOrCondenseLava) foundLavas.foreach(_.setType(Material.MAGMA_BLOCK)) } Some(newState) diff --git a/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/ActiveSkillEffect.scala b/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/ActiveSkillEffect.scala index b8b8775ab8..74a13cbd83 100644 --- a/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/ActiveSkillEffect.scala +++ b/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/ActiveSkillEffect.scala @@ -22,7 +22,6 @@ import enumeratum.{Enum, EnumEntry} import org.bukkit.ChatColor._ import org.bukkit._ import org.bukkit.entity.{Chicken, Player} -import org.bukkit.material.Wool import scala.util.Random @@ -128,10 +127,12 @@ sealed abstract class ActiveSkillNormalEffect( tool, isSkillDualBreakOrTrialBreak ) - _ <- IO { - explosionLocations.foreach(coordinates => - world.createExplosion(coordinates.toLocation(world), 0f, false) - ) + _ <- ioOnMainThread.runAction { + SyncIO { + explosionLocations.foreach(coordinates => + world.createExplosion(coordinates.toLocation(world), 0f, false) + ) + } } } yield () @@ -248,7 +249,7 @@ object ActiveSkillNormalEffect extends Enum[ActiveSkillNormalEffect] { s"${DARK_RED}メテオ", "隕石を落とす", 100, - Material.FIREBALL + Material.FIRE_CHARGE ) } @@ -277,27 +278,28 @@ sealed abstract class ActiveSkillPremiumEffect( this match { case ActiveSkillPremiumEffect.MAGIC => - val colors = Array(DyeColor.RED, DyeColor.BLUE, DyeColor.YELLOW, DyeColor.GREEN) + val colors = Array( + Material.RED_WOOL, + Material.BLUE_WOOL, + Material.YELLOW_WOOL, + Material.GREEN_WOOL + ) // 破壊するブロックの中心位置 val centerBreak: Location = standard + ((breakArea.begin + breakArea.end) / 2) for { - randomColor <- IO { colors(Random.nextInt(colors.length)) } + randomWool <- IO { colors(Random.nextInt(colors.length)) } _ <- BreakUtil.massBreakBlock( player, breakBlocks, standard, tool, shouldPlayBreakSound = false, - Material.WOOL + randomWool ) _ <- IO { - breakBlocks.foreach { b => - val state = b.getState - state.getData.asInstanceOf[Wool].setColor(randomColor) - state.update() - } + breakBlocks.foreach(_.setType(randomWool)) } period <- IO { if (SeichiAssist.DEBUG) 100 else 10 } @@ -351,7 +353,7 @@ case object ActiveSkillPremiumEffect extends Enum[ActiveSkillPremiumEffect] { s"$RED$UNDERLINE${BOLD}マジック", "鶏が出る手品", 10, - Material.RED_ROSE + Material.POPPY ) } diff --git a/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/arrow/ArrowEffects.scala b/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/arrow/ArrowEffects.scala index a4b55429a7..dcf189630c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/arrow/ArrowEffects.scala +++ b/src/main/scala/com/github/unchama/seichiassist/seichiskill/effect/arrow/ArrowEffects.scala @@ -7,6 +7,7 @@ import com.github.unchama.seichiassist.SeichiAssist import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts import com.github.unchama.targetedeffect.player.FocusedSoundEffect import com.github.unchama.util.effect.BukkitResources +import org.bukkit.entity.AbstractArrow.PickupStatus import org.bukkit.entity._ import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.PotionMeta @@ -28,9 +29,10 @@ object ArrowEffects { def normalArrowEffect( implicit mainThread: OnMinecraftServerThread[IO] ): TargetedEffect[Player] = - arrowEffect[Arrow]( + arrowEffect[AbstractArrow]( ProjectileSpawnConfiguration(1.0, (0.0, 1.6, 0.0)), - Some(Sound.ENTITY_ARROW_SHOOT) + Some(Sound.ENTITY_ARROW_SHOOT), + _.setPickupStatus(PickupStatus.DISALLOWED) ) def singleArrowBlizzardEffect( @@ -65,10 +67,13 @@ object ArrowEffects { def singleArrowMeteoEffect( implicit mainThread: OnMinecraftServerThread[IO] ): TargetedEffect[Player] = - arrowEffect[Arrow]( + arrowEffect[AbstractArrow]( ProjectileSpawnConfiguration(1.0, (0.0, 1.6, 0.0)), Some(Sound.ENTITY_ARROW_SHOOT), - _.setGlowing(true) + { arrow => + arrow.setGlowing(true) + arrow.setPickupStatus(PickupStatus.DISALLOWED) + } ) def singleArrowExplosionEffect( diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/anywhereender/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/anywhereender/System.scala index 0a1f997474..f50b67d17e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/anywhereender/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/anywhereender/System.scala @@ -1,6 +1,5 @@ package com.github.unchama.seichiassist.subsystems.anywhereender -import cats.Functor import cats.data.Kleisli import cats.effect.{Effect, IO, LiftIO} import com.github.unchama.generic.ContextCoercion @@ -25,9 +24,7 @@ object System { import ContextCoercion._ import cats.implicits._ - def wired[F[_]: BreakCountReadAPI[IO, *[_], Player]: Functor: ContextCoercion[*[_], G], G[ - _ - ]: Effect]( + def wired[F[_]: BreakCountReadAPI[IO, *[_], Player]: ContextCoercion[*[_], G], G[_]: Effect]( configuration: SystemConfiguration )(implicit onMainThread: OnMinecraftServerThread[IO]): System[G] = new System[G] { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/System.scala index c3cb3d3782..93baa0ae1c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/System.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.autosave import cats.effect.{Sync, Timer} -import com.github.unchama.minecraft.actions.OnMinecraftServerThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.autosave.application.{ CanNotifySaves, CanSaveWorlds, @@ -12,16 +12,17 @@ import com.github.unchama.seichiassist.subsystems.autosave.bukkit.instances.{ SyncCanNotifyBukkitSaves, SyncCanSaveBukkitWorlds } +import org.bukkit.entity.Player object System { - def backgroundProcess[F[_]: Sync: Timer: OnMinecraftServerThread, G[_]]( + def backgroundProcess[F[_]: Sync: Timer: OnMinecraftServerThread]( + implicit getConnectedPlayers: GetConnectedPlayers[F, Player], configuration: SystemConfiguration ): F[Nothing] = { - implicit val _configuration: SystemConfiguration = configuration - implicit val _canSaveWorlds: CanSaveWorlds[F] = SyncCanSaveBukkitWorlds[F] - implicit val _canNotifySaves: CanNotifySaves[F] = SyncCanNotifyBukkitSaves[F] + implicit val _canNotifySaves: CanNotifySaves[F] = + SyncCanNotifyBukkitSaves[F] WorldSaveRoutine() } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanNotifyBukkitSaves.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanNotifyBukkitSaves.scala index 88e7cc3950..c86feb9364 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanNotifyBukkitSaves.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanNotifyBukkitSaves.scala @@ -1,17 +1,24 @@ package com.github.unchama.seichiassist.subsystems.autosave.bukkit.instances import cats.effect.Sync -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread +import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.subsystems.autosave.application.CanNotifySaves import com.github.unchama.seichiassist.util.SendMessageEffect import org.bukkit.Bukkit +import org.bukkit.entity.Player +import com.github.unchama.minecraft.actions.GetConnectedPlayers object SyncCanNotifyBukkitSaves { - def apply[F[_]: Sync]: CanNotifySaves[F] = (message: String) => - Sync[F].delay { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference(message) - Bukkit.getLogger.info(message) - } + import cats.implicits._ + + def apply[F[_]: Sync: OnMinecraftServerThread]( + implicit getConnectedPlayers: GetConnectedPlayers[F, Player] + ): CanNotifySaves[F] = + (message: String) => + for { + _ <- SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceM[String, F](message) + _ <- Sync[F].delay(Bukkit.getLogger.info(message)) + } yield () } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanSaveBukkitWorlds.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanSaveBukkitWorlds.scala index 1a1e6188d8..f5c505d5a5 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanSaveBukkitWorlds.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/autosave/bukkit/instances/SyncCanSaveBukkitWorlds.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.subsystems.autosave.bukkit.instances -import cats.effect.{Sync, SyncIO} +import cats.effect.SyncIO import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.subsystems.autosave.application.CanSaveWorlds import org.bukkit.{Bukkit, World} @@ -10,7 +10,7 @@ import scala.annotation.tailrec object SyncCanSaveBukkitWorlds { - def apply[F[_]: Sync: OnMinecraftServerThread]: CanSaveWorlds[F] = new CanSaveWorlds[F] { + def apply[F[_]: OnMinecraftServerThread]: CanSaveWorlds[F] = new CanSaveWorlds[F] { val save: SyncIO[Unit] = SyncIO { def saveWorld(world: World): Unit = { // WARNを防ぐためMinecraftサーバーデフォルトの自動セーブは無効化 diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/bookedachivement/bukkit/command/AchievementCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/bookedachivement/bukkit/command/AchievementCommand.scala index b459659a79..50e547825f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/bookedachivement/bukkit/command/AchievementCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/bookedachivement/bukkit/command/AchievementCommand.scala @@ -75,6 +75,7 @@ object AchievementCommand { ) ) + // TODO: パーサーを分けるべき def executor[F[_]: ConcurrentEffect]( implicit service: AchievementBookingService[F] ): TabExecutor = ContextualExecutorBuilder @@ -149,7 +150,7 @@ object AchievementCommand { }.combineAll } - execution() + execution().flatMap(_.apply(sender)) } .asNonBlockingTabExecutor() } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/application/actions/IncrementSeichiExp.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/application/actions/IncrementSeichiExp.scala index 0eb97809c1..4869d51fe4 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/application/actions/IncrementSeichiExp.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/application/actions/IncrementSeichiExp.scala @@ -5,7 +5,6 @@ import cats.effect.concurrent.Ref import cats.effect.{Effect, Sync} import com.github.unchama.datarepository.KeyedDataRepository import com.github.unchama.fs2.workaround.fs3.Fs3Topic -import com.github.unchama.generic.ContextCoercion import com.github.unchama.generic.effect.EffectExtra import com.github.unchama.seichiassist.subsystems.breakcount.domain.SeichiAmountData import com.github.unchama.seichiassist.subsystems.breakcount.domain.level.SeichiExpAmount @@ -27,9 +26,7 @@ object IncrementSeichiExp { /** * 与えられたデータレポジトリと更新を流すトピックを用いてプレーヤーの整地量を増加させるような 代数を作成する。 */ - def using[F[_]: Sync: ClassifyPlayerWorld[*[_], Player], G[_]: Effect: ContextCoercion[F, *[ - _ - ]], Player]( + def using[F[_]: Sync: ClassifyPlayerWorld[*[_], Player], G[_]: Effect, Player]( dataRepository: KeyedDataRepository[Player, Ref[F, SeichiAmountData]], dataTopic: Fs3Topic[G, Option[(Player, SeichiAmountData)]] ): IncrementSeichiExp[F, Player] = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/domain/level/SeichiExpAmount.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/domain/level/SeichiExpAmount.scala index 73def02d89..d2b60991e1 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/domain/level/SeichiExpAmount.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/domain/level/SeichiExpAmount.scala @@ -17,7 +17,7 @@ case class SeichiExpAmount private (amount: BigDecimal) extends AnyVal { def subtract(a: SeichiExpAmount): SeichiExpAmount = mapAmount(_ - a.amount) - def formatted: String = amount.toLong.formatted("%,d") + def formatted: String = String.format("%,d", amount.longValue) } object SeichiExpAmount { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala index b8337299bd..47563698cd 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala @@ -15,20 +15,19 @@ import com.github.unchama.seichiassist.subsystems.breakcount.subsystems.notifica import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI import com.github.unchama.seichiassist.util.{ LaunchFireWorksEffect, - PlayerSendable, SendMessageEffect, SendSoundEffect } import org.bukkit.ChatColor.{BOLD, GOLD} import org.bukkit.Sound import org.bukkit.entity.Player +import com.github.unchama.seichiassist.util.PlayerSendable._ //FIXME ファイル名とやっていることが違うようになっているので修正するべき。 //例えば、10億の倍数到達時の通知はLevelUp時の通知ではない //また、BukkitNotifyLevelUpなのにdiffの展開やいつメッセージを出すかなどを扱うべきでない。 object BukkitNotifyLevelUp { - import PlayerSendable.forString import cats.implicits._ def apply[F[_]: OnMinecraftServerThread: ConcurrentEffect: DiscordNotificationAPI] @@ -44,17 +43,21 @@ object BukkitNotifyLevelUp { .expAmount .amount >= nextTenBillion ) { + // TODO: ここのSyncIOを剥がせそう OnMinecraftServerThread[F].runAction(SyncIO { val notificationMessage = s"${player.getName}の総整地量が${(newBreakAmount.expAmount.amount / 100000000).toInt}億に到達しました!" - SendMessageEffect.sendMessageToEveryoneIgnoringPreference( - s"$GOLD$BOLD$notificationMessage" - )(forString[IO]) + + SendMessageEffect + .sendMessageToEveryoneIgnoringPreferenceIO(s"$GOLD$BOLD$notificationMessage")( + forString[IO] + ) + .unsafeRunAsyncAndForget() DiscordNotificationAPI[F] .sendPlainText(notificationMessage) .toIO .unsafeRunAsyncAndForget() - SendSoundEffect.sendEverySound(Sound.ENTITY_ENDERDRAGON_DEATH, 1.0f, 1.2f) + SendSoundEffect.sendEverySound(Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 1.2f) }) } else Applicative[F].unit } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcountbar/application/ExpBarSynchronizationRepositoryTemplate.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcountbar/application/ExpBarSynchronizationRepositoryTemplate.scala index 4d5e1b8ed9..2da81fedcb 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcountbar/application/ExpBarSynchronizationRepositoryTemplate.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakcountbar/application/ExpBarSynchronizationRepositoryTemplate.scala @@ -73,7 +73,7 @@ object ExpBarSynchronizationRepositoryTemplate { } yield (bossBar, fiberPromise) } - def finalization[G[_]: Sync, F[_]: ConcurrentEffect: ContextCoercion[G, *[_]], Player] + def finalization[G[_]: Sync, F[_]: ConcurrentEffect, Player] : RepositoryFinalization[G, Player, RepositoryValueType[F, Player]] = RepositoryFinalization.withoutAnyPersistence { case (_, (_, fiberPromise)) => diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltargetconfig/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltargetconfig/System.scala index 08ded6514f..5e2e56eee5 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltargetconfig/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltargetconfig/System.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.breakskilltargetconfig import cats.data.Kleisli -import cats.effect.{Sync, SyncEffect} +import cats.effect.SyncEffect import com.github.unchama.datarepository.bukkit.player.BukkitRepositoryControls import com.github.unchama.generic.ContextCoercion import com.github.unchama.seichiassist.meta.subsystem.Subsystem @@ -21,7 +21,7 @@ object System { import cats.implicits._ - def wired[F[_]: Sync, G[_]: SyncEffect: ContextCoercion[*[_], F]]: G[System[F, Player]] = { + def wired[F[_], G[_]: SyncEffect: ContextCoercion[*[_], F]]: G[System[F, Player]] = { implicit val breakSkillTargetConfigPersistence: BreakSkillTargetConfigPersistence[G] = new JdbcBreakSkillTargetConfigPersistence[G] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/System.scala index b85f72cca1..2c3995209c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/System.scala @@ -1,7 +1,6 @@ package com.github.unchama.seichiassist.subsystems.buildcount import cats.effect.{Clock, ConcurrentEffect, SyncEffect} -import com.github.unchama.concurrent.NonServerThreadContextShift import com.github.unchama.datarepository.KeyedDataRepository import com.github.unchama.datarepository.bukkit.player.BukkitRepositoryControls import com.github.unchama.datarepository.template.RepositoryDefinition @@ -9,7 +8,7 @@ import com.github.unchama.fs2.workaround.fs3.Fs3Topic import com.github.unchama.generic.ContextCoercion import com.github.unchama.generic.effect.concurrent.ReadOnlyRef import com.github.unchama.generic.ratelimiting.RateLimiter -import com.github.unchama.minecraft.actions.OnMinecraftServerThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.meta.subsystem.Subsystem import com.github.unchama.seichiassist.subsystems.buildcount.application.actions.{ ClassifyPlayerWorld, @@ -53,10 +52,11 @@ object System { def wired[F[ _ - ]: OnMinecraftServerThread: ConcurrentEffect: NonServerThreadContextShift: ErrorLogger: DiscordNotificationAPI, G[ + ]: OnMinecraftServerThread: ConcurrentEffect: ErrorLogger: DiscordNotificationAPI, G[ _ ]: SyncEffect: ContextCoercion[*[_], F]: Clock]( - implicit configuration: Configuration + implicit configuration: Configuration, + getConnectedPlayers: GetConnectedPlayers[F, Player] ): F[System[F, G]] = { implicit val expMultiplier: BuildExpMultiplier = configuration.multipliers implicit val persistence: JdbcBuildAmountDataPersistence[G] = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/actions/IncrementBuildExpWhenBuiltByHand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/actions/IncrementBuildExpWhenBuiltByHand.scala index 2170bbaeed..aedb816544 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/actions/IncrementBuildExpWhenBuiltByHand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/actions/IncrementBuildExpWhenBuiltByHand.scala @@ -5,7 +5,6 @@ import cats.effect.concurrent.Ref import cats.effect.{Effect, Sync} import com.github.unchama.datarepository.KeyedDataRepository import com.github.unchama.fs2.workaround.fs3.Fs3Topic -import com.github.unchama.generic.ContextCoercion import com.github.unchama.generic.effect.EffectExtra import com.github.unchama.generic.ratelimiting.RateLimiter import com.github.unchama.seichiassist.subsystems.buildcount.application.BuildExpMultiplier @@ -31,10 +30,7 @@ object IncrementBuildExpWhenBuiltByHand { implicit ev: IncrementBuildExpWhenBuiltByHand[F, Player] ): IncrementBuildExpWhenBuiltByHand[F, Player] = ev - def using[F[_]: ClassifyPlayerWorld[*[_], Player], G[_]: Effect: ContextCoercion[ - F, - *[_] - ], Player]( + def using[F[_]: ClassifyPlayerWorld[*[_], Player], G[_]: Effect, Player]( rateLimiterRepository: KeyedDataRepository[Player, RateLimiter[F, BuildExpAmount]], dataRepository: KeyedDataRepository[Player, Ref[F, BuildAmountData]], dataTopic: Fs3Topic[G, (Player, BuildAmountData)] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/application/RateLimiterRepositoryDefinitions.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/application/RateLimiterRepositoryDefinitions.scala index a6c5b3311c..2418f1873a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/application/RateLimiterRepositoryDefinitions.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/application/application/RateLimiterRepositoryDefinitions.scala @@ -59,8 +59,7 @@ object RateLimiterRepositoryDefinitions { } def finalization[F[_]: Sync: JavaTime, Player: HasUuid]( - implicit config: Configuration, - persistence: BuildAmountRateLimitPersistence[F] + implicit persistence: BuildAmountRateLimitPersistence[F] ): RepositoryFinalization[F, Player, RateLimiter[F, BuildExpAmount]] = RepositoryFinalization.withoutAnyFinalization { case (p, rateLimiter) => diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/infrastructure/JdbcBuildAmountRateLimitPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/infrastructure/JdbcBuildAmountRateLimitPersistence.scala index 3f7f1d8046..b4b1a9fa75 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/infrastructure/JdbcBuildAmountRateLimitPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/infrastructure/JdbcBuildAmountRateLimitPersistence.scala @@ -1,7 +1,6 @@ package com.github.unchama.seichiassist.subsystems.buildcount.infrastructure import cats.effect.Sync -import com.github.unchama.seichiassist.subsystems.buildcount.application.Configuration import com.github.unchama.seichiassist.subsystems.buildcount.domain.BuildAmountRateLimiterSnapshot import com.github.unchama.seichiassist.subsystems.buildcount.domain.explevel.BuildExpAmount import com.github.unchama.seichiassist.subsystems.buildcount.domain.playerdata.BuildAmountRateLimitPersistence @@ -10,8 +9,7 @@ import scalikejdbc._ import java.util.UUID class JdbcBuildAmountRateLimitPersistence[SyncContext[_]]( - implicit SyncContext: Sync[SyncContext], - config: Configuration + implicit SyncContext: Sync[SyncContext] ) extends BuildAmountRateLimitPersistence[SyncContext] { override def read(key: UUID): SyncContext[Option[BuildAmountRateLimiterSnapshot]] = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/System.scala index 02532af23e..86741a7835 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/System.scala @@ -2,7 +2,7 @@ package com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notific import cats.effect.Concurrent import com.github.unchama.generic.effect.stream.StreamExtra -import com.github.unchama.minecraft.actions.OnMinecraftServerThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.buildcount.BuildCountAPI import com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notification.application.actions.{ NotifyBuildAmountThreshold, @@ -22,7 +22,7 @@ object System { _ ]: Concurrent: ErrorLogger: OnMinecraftServerThread: DiscordNotificationAPI, G[_], A]( buildCountReadAPI: BuildCountAPI[F, G, Player] - ): F[A] = { + )(implicit getConnectedPlayers: GetConnectedPlayers[F, Player]): F[A] = { val notifyLevelUp: NotifyLevelUp[F, Player] = BukkitNotifyLevelUp[F] val notifyBuildAmountThreshold: NotifyBuildAmountThreshold[F, Player] = BukkitNotifyBuildAmountThreshold[F] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyBuildAmountThreshold.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyBuildAmountThreshold.scala index a2c53c7a15..325279cef1 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyBuildAmountThreshold.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyBuildAmountThreshold.scala @@ -1,23 +1,24 @@ package com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notification.bukkit.actions -import cats.effect.{IO, Sync} +import cats.effect.Sync import com.github.unchama.generic.Diff -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.buildcount.domain.playerdata.BuildAmountData import com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notification.application.actions.NotifyBuildAmountThreshold import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI -import com.github.unchama.seichiassist.util.{PlayerSendable, SendMessageEffect, SendSoundEffect} +import com.github.unchama.seichiassist.util.{SendMessageEffect, SendSoundEffect} import org.bukkit.ChatColor.{BOLD, GOLD} import org.bukkit.Sound import org.bukkit.entity.Player object BukkitNotifyBuildAmountThreshold { - import PlayerSendable.forString import cats.implicits._ // TODO: BukkitNotifyLevelUpなのにdiffの展開やいつメッセージを出すかなどを扱うべきでない。 - def apply[F[_]: Sync: DiscordNotificationAPI]: NotifyBuildAmountThreshold[F, Player] = { + def apply[F[_]: Sync: DiscordNotificationAPI: OnMinecraftServerThread: GetConnectedPlayers[*[ + _ + ], Player]]: NotifyBuildAmountThreshold[F, Player] = { new NotifyBuildAmountThreshold[F, Player] { override def ofBuildAmountTo(player: Player)(diff: Diff[BuildAmountData]): F[Unit] = { val Diff(oldBuildAmount, newBuildAmount) = diff @@ -46,11 +47,10 @@ object BukkitNotifyBuildAmountThreshold { val notificationMessage = s"${player.getName}の総建築量が${newBuildAmountDisplay}に到達しました!" - Sync[F].delay { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference( - s"$GOLD$BOLD$notificationMessage" - )(forString[IO]) - SendSoundEffect.sendEverySound(Sound.ENTITY_ENDERDRAGON_DEATH, 1.0f, 1.2f) + SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceM[String, F]( + s"$GOLD$BOLD$notificationMessage" + ) >> Sync[F].delay { + SendSoundEffect.sendEverySound(Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 1.2f) } >> DiscordNotificationAPI[F].sendPlainText(notificationMessage) } else Sync[F].unit } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala index 69d165e8ee..7695570b28 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/buildcount/subsystems/notification/bukkit/actions/BukkitNotifyLevelUp.scala @@ -1,30 +1,29 @@ package com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notification.bukkit.actions -import cats.effect.{IO, Sync} +import cats.effect.Sync import com.github.unchama.generic.Diff -import com.github.unchama.minecraft.actions.OnMinecraftServerThread -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.buildcount.domain.explevel.{ BuildAssistExpTable, BuildLevel } import com.github.unchama.seichiassist.subsystems.buildcount.subsystems.notification.application.actions.NotifyLevelUp import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI -import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreference +import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceM import com.github.unchama.seichiassist.util.SendSoundEffect.sendEverySound -import com.github.unchama.seichiassist.util.{LaunchFireWorksEffect, PlayerSendable} +import com.github.unchama.seichiassist.util.LaunchFireWorksEffect import org.bukkit.ChatColor.GOLD import org.bukkit.Sound import org.bukkit.entity.Player object BukkitNotifyLevelUp { - import PlayerSendable.forString import cats.implicits._ // TODO: BukkitNotifyLevelUpなのにdiffの展開やいつメッセージを出すかなどを扱うべきでない。 - def apply[F[_]: Sync: OnMinecraftServerThread: DiscordNotificationAPI] - : NotifyLevelUp[F, Player] = { + def apply[F[_]: Sync: OnMinecraftServerThread: DiscordNotificationAPI: GetConnectedPlayers[*[ + _ + ], Player]]: NotifyLevelUp[F, Player] = { new NotifyLevelUp[F, Player] { override def ofBuildLevelTo(player: Player)(diff: Diff[BuildLevel]): F[Unit] = { val Diff(oldLevel, newLevel) = diff @@ -32,11 +31,12 @@ object BukkitNotifyLevelUp { val messageLevelMaxGlobal = s"$GOLD${player.getName}の建築レベルが最大Lvに到達したよ(`・ω・´)" val messageLevelMaxDiscord = s"${player.getName}の建築レベルが最大Lvに到達したよ(`・ω・´)" val messageLevelMaxPlayer = s"${GOLD}最大Lvに到達したよ(`・ω・´)" - Sync[F].delay { - sendMessageToEveryoneIgnoringPreference(messageLevelMaxGlobal)(forString[IO]) - player.sendMessage(messageLevelMaxPlayer) - sendEverySound(Sound.ENTITY_ENDERDRAGON_DEATH, 1.0f, 1.2f) - } >> LaunchFireWorksEffect.launchFireWorks[F]( + + sendMessageToEveryoneIgnoringPreferenceM[String, F](messageLevelMaxGlobal) >> Sync[F] + .delay { + player.sendMessage(messageLevelMaxPlayer) + sendEverySound(Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 1.2f) + } >> LaunchFireWorksEffect.launchFireWorks[F]( player.getLocation ) >> DiscordNotificationAPI[F].sendPlainText(messageLevelMaxDiscord) } else if (oldLevel < newLevel) { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/chatratelimiter/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/chatratelimiter/System.scala index f56d0bce5e..7ce30513dc 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/chatratelimiter/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/chatratelimiter/System.scala @@ -9,15 +9,13 @@ import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI import com.github.unchama.seichiassist.subsystems.chatratelimiter.application.ChatRateLimitRepositoryDefinition import com.github.unchama.seichiassist.subsystems.chatratelimiter.bukkit.listeners.RateLimitCheckListener import com.github.unchama.seichiassist.subsystems.chatratelimiter.domain.ObtainChatPermission -import io.chrisdavenport.log4cats.ErrorLogger import org.bukkit.entity.Player import org.bukkit.event.Listener object System { - def wired[F[_]: ConcurrentEffect: ErrorLogger, G[_]: SyncEffect: ContextCoercion[ - *[_], - F - ]: Timer](implicit breakCountAPI: BreakCountReadAPI[F, G, Player]): F[Subsystem[F]] = { + def wired[F[_]: ConcurrentEffect, G[_]: SyncEffect: ContextCoercion[*[_], F]: Timer]( + implicit breakCountAPI: BreakCountReadAPI[F, G, Player] + ): F[Subsystem[F]] = { val repository = ChatRateLimitRepositoryDefinition.inSyncContext[G, Player] for { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/System.scala index f4e84a3810..1e078261c2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/System.scala @@ -6,20 +6,18 @@ import com.github.unchama.seichiassist.subsystems.discordnotification.infrastruc DefaultDiscordNotificationSender, WebhookDiscordNotificationSender } -import io.chrisdavenport.log4cats.Logger trait System[F[_]] extends Subsystem[F] { implicit val globalNotification: DiscordNotificationAPI[F] } object System { - def wired[F[_]: Sync: ContextShift: Logger: LiftIO]( - configuration: SystemConfiguration - ): System[F] = new System[F] { - implicit override val globalNotification: DiscordNotificationAPI[F] = { - WebhookDiscordNotificationSender - .tryCreate(configuration.webhookUrl) - .getOrElse(new DefaultDiscordNotificationSender) + def wired[F[_]: Sync: ContextShift: LiftIO](configuration: SystemConfiguration): System[F] = + new System[F] { + implicit override val globalNotification: DiscordNotificationAPI[F] = { + WebhookDiscordNotificationSender + .tryCreate(configuration.webhookUrl) + .getOrElse(new DefaultDiscordNotificationSender) + } } - } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/DefaultDiscordNotificationSender.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/DefaultDiscordNotificationSender.scala index 7950ecd446..5036a6d4e3 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/DefaultDiscordNotificationSender.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/DefaultDiscordNotificationSender.scala @@ -3,13 +3,11 @@ package com.github.unchama.seichiassist.subsystems.discordnotification.infrastru import cats.effect.LiftIO import com.github.unchama.seichiassist.SeichiAssist import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI -import io.chrisdavenport.log4cats.Logger /** * この実装は[[sendPlainText]]が呼ばれるたびに警告をロガーに流す以外は何もしない。 */ -final class DefaultDiscordNotificationSender[F[_]: Logger: LiftIO] - extends DiscordNotificationAPI[F] { +final class DefaultDiscordNotificationSender[F[_]: LiftIO] extends DiscordNotificationAPI[F] { override def sendPlainText(message: String): F[Unit] = { SeichiAssist .instance diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/WebhookDiscordNotificationSender.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/WebhookDiscordNotificationSender.scala index cbe745cf0e..237981483a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/WebhookDiscordNotificationSender.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/discordnotification/infrastructure/WebhookDiscordNotificationSender.scala @@ -2,7 +2,6 @@ package com.github.unchama.seichiassist.subsystems.discordnotification.infrastru import cats.effect.{ContextShift, Sync} import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI -import io.chrisdavenport.log4cats.Logger import java.io.IOException import java.net.{HttpURLConnection, MalformedURLException, URL} @@ -24,14 +23,14 @@ class WebhookDiscordNotificationSender[F[_]: Sync: ContextShift] private (webhoo import io.circe.generic.auto._ import io.circe.syntax._ val markdownSafeMessage = message - .replaceAllLiterally("\\", "\\\\") - .replaceAllLiterally("_", "\\_") - .replaceAllLiterally("*", "\\*") - .replaceAllLiterally("`", "\\`") - .replaceAllLiterally("|", "\\|") - .replaceAllLiterally("@", "\\@") - .replaceAllLiterally("~", "\\~") - .replaceAllLiterally(":", "\\:") + .replace("\\", "\\\\") + .replace("_", "\\_") + .replace("*", "\\*") + .replace("`", "\\`") + .replace("|", "\\|") + .replace("@", "\\@") + .replace("~", "\\~") + .replace(":", "\\:") val json = WebhookDiscordNotificationSender.PlainMessage(markdownSafeMessage).asJson.noSpaces @@ -76,7 +75,7 @@ object WebhookDiscordNotificationSender { * @return * 初期化に成功した場合はSome、初期化中に特定の例外が送出された場合はNone。マスクされない例外が送出されたときは、再送出する。 */ - def tryCreate[F[_]: Sync: ContextShift: Logger]( + def tryCreate[F[_]: Sync: ContextShift]( webhookURL: String ): Option[WebhookDiscordNotificationSender[F]] = { try { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/bukkit/commands/DonationCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/bukkit/commands/DonationCommand.scala index db33f0340e..63101baebe 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/bukkit/commands/DonationCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/bukkit/commands/DonationCommand.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.subsystems.donate.bukkit.commands -import cats.effect.ConcurrentEffect.ops.toAllConcurrentEffectOps +import cats.data.Kleisli import cats.effect.{ConcurrentEffect, Sync} import com.github.unchama.contextualexecutor.ContextualExecutor import com.github.unchama.contextualexecutor.builder.{ContextualExecutorBuilder, Parsers} @@ -12,7 +12,7 @@ import com.github.unchama.seichiassist.subsystems.donate.domain.{ PlayerName } import com.github.unchama.targetedeffect.UnfocusedEffect -import com.github.unchama.targetedeffect.commandsender.MessageEffect +import com.github.unchama.targetedeffect.commandsender.{MessageEffect, MessageEffectF} import org.bukkit.ChatColor._ import org.bukkit.command.TabExecutor import shapeless.HNil @@ -31,7 +31,7 @@ class DonationCommand[F[_]: ConcurrentEffect]( .beginConfiguration .thenParse(Parsers.identity) .thenParse(Parsers.integer(MessageEffect(s"${RED}付与するプレミアムエフェクトポイントは整数で指定してください。"))) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => import shapeless.:: val rawName :: rawDonatePoint :: HNil = context.args.parsed @@ -40,29 +40,31 @@ class DonationCommand[F[_]: ConcurrentEffect]( val dateRegex = "[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])".r val dateOpt = context.args.yetToBeParsed.headOption - val isMatchedPattern = dateOpt.forall(date => dateRegex.matches(date)) + val isMatchedPattern = dateOpt.forall(dateRegex.matches) - val eff = for { - date <- Sync[F].delay { + (for { + date <- Kleisli.liftF(Sync[F].delay { dateOpt match { case Some(date) if isMatchedPattern => val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") LocalDate.parse(date, dateTimeFormatter) case _ => LocalDate.now() } - } - _ <- donatePersistence - .addDonatePremiumEffectPoint(playerName, Obtained(donatePoint, date)) - .whenA(isMatchedPattern) + }) + _ <- Kleisli.liftF( + donatePersistence + .addDonatePremiumEffectPoint(playerName, Obtained(donatePoint, date)) + .whenA(isMatchedPattern) + ) } yield { - if (!isMatchedPattern) - MessageEffect(s"${RED}購入日はyyyy-MM-ddの形式で指定してください。") - else - MessageEffect( + if (isMatchedPattern) { + MessageEffectF( s"$GREEN${playerName.name}に${donatePoint.value}のプレミアムエフェクトポイントを付与しました。" ) - } - eff.toIO + } else { + MessageEffectF(s"${RED}購入日はyyyy-MM-ddの形式で指定してください。") + } + }).flatten } private val commandDescriptionExecutor: ContextualExecutor = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/infrastructure/JdbcDonatePersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/infrastructure/JdbcDonatePersistence.scala index 01fa757d4e..f5a0d27e9a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/infrastructure/JdbcDonatePersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/donate/infrastructure/JdbcDonatePersistence.scala @@ -65,7 +65,7 @@ class JdbcDonatePersistence[F[_]: Sync] extends DonatePersistence[F] { .map(rs => Obtained(DonatePremiumEffectPoint(rs.int("get_points")), rs.localDate("timestamp")) ) - .list + .list() .apply() .toVector } @@ -83,7 +83,7 @@ class JdbcDonatePersistence[F[_]: Sync] extends DonatePersistence[F] { ActiveSkillPremiumEffect.withName(rs.string("effect_name")) ) ) - .list + .list() .apply() .toVector } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/System.scala index 10cb78c9c2..5d286979de 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/System.scala @@ -2,13 +2,16 @@ package com.github.unchama.seichiassist.subsystems.dragonnighttime import cats.effect.{Concurrent, Timer} import com.github.unchama.generic.ContextCoercion +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.dragonnighttime.application._ import com.github.unchama.seichiassist.subsystems.dragonnighttime.bukkit.instances._ import com.github.unchama.seichiassist.subsystems.fastdiggingeffect.FastDiggingEffectWriteApi import com.github.unchama.seichiassist.subsystems.mana.ManaApi object System { - def backgroundProcess[F[_]: Concurrent: Timer, G[_]: ContextCoercion[*[_], F], Player]( + def backgroundProcess[F[_]: Concurrent: Timer: OnMinecraftServerThread: GetConnectedPlayers[*[ + _ + ], org.bukkit.entity.Player], G[_]: ContextCoercion[*[_], F], Player]( implicit fastDiggingEffectApi: FastDiggingEffectWriteApi[F, Player], manaApi: ManaApi[F, G, Player] ): F[Nothing] = { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/bukkit/instances/SyncCanBroadcastOnBukkit.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/bukkit/instances/SyncCanBroadcastOnBukkit.scala index aa16c0e760..20c1874748 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/bukkit/instances/SyncCanBroadcastOnBukkit.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/dragonnighttime/bukkit/instances/SyncCanBroadcastOnBukkit.scala @@ -1,15 +1,20 @@ package com.github.unchama.seichiassist.subsystems.dragonnighttime.bukkit.instances import cats.effect.Sync -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.dragonnighttime.application.CanBroadcast import com.github.unchama.seichiassist.util.SendMessageEffect import org.bukkit.Bukkit +import org.bukkit.entity.Player object SyncCanBroadcastOnBukkit { - def apply[F[_]: Sync]: CanBroadcast[F] = (message: String) => - Sync[F].delay { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference(message) - Bukkit.getLogger.info(message) - } + import cats.implicits._ + + def apply[F[_]: Sync: OnMinecraftServerThread: GetConnectedPlayers[*[_], Player]] + : CanBroadcast[F] = (message: String) => { + for { + _ <- SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceM[String, F](message) + _ <- Sync[F].delay(Bukkit.getLogger.info(message)) + } yield () + } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/System.scala new file mode 100644 index 0000000000..edbe85e27b --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/System.scala @@ -0,0 +1,25 @@ +package com.github.unchama.seichiassist.subsystems.elevator + +import cats.effect.ConcurrentEffect +import com.github.unchama.generic.effect.unsafe.EffectEnvironment +import com.github.unchama.seichiassist.meta.subsystem.Subsystem +import com.github.unchama.seichiassist.subsystems.elevator.application.actions.FindTeleportLocation +import com.github.unchama.seichiassist.subsystems.elevator.bukkit.actions.BukkitFindTeleportLocation +import com.github.unchama.seichiassist.subsystems.elevator.bukkit.listeners.ElevatorEventsListener +import org.bukkit.Location +import org.bukkit.event.Listener + +object System { + + def wired[F[_]: ConcurrentEffect]( + implicit effectEnvironment: EffectEnvironment + ): Subsystem[F] = { + implicit val findTeleportLocation: FindTeleportLocation[F, Location] = + new BukkitFindTeleportLocation[F] + + new Subsystem[F] { + override val listeners: Seq[Listener] = Seq(new ElevatorEventsListener[F]) + } + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/application/actions/FindTeleportLocation.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/application/actions/FindTeleportLocation.scala new file mode 100644 index 0000000000..35743f4bea --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/application/actions/FindTeleportLocation.scala @@ -0,0 +1,25 @@ +package com.github.unchama.seichiassist.subsystems.elevator.application.actions + +trait FindTeleportLocation[F[_], Location] { + + /** + * @return `currentLocation`がテレポート元として正しいかどうかを判定する作用 + */ + def currentLocationTeleportFromAsCorrectIs(currentLocation: Location): F[Boolean] + + /** + * @return `targetLocation`がテレポート先として正しいかどうかを判定する作用 + */ + def isTeleportTargetLocation(targetLocation: Location): F[Boolean] + + /** + * @return `currentLocation`より上のテレポート対象となる[[Location]]を探す作用 + */ + def findUpperLocation(currentLocation: Location): F[Option[Location]] + + /** + * @return `currentLocation`より下のテレポート対象となる[[Location]]を探す作用 + */ + def findLowerLocation(currentLocation: Location): F[Option[Location]] + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/actions/BukkitFindTeleportLocation.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/actions/BukkitFindTeleportLocation.scala new file mode 100644 index 0000000000..e1b390f31c --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/actions/BukkitFindTeleportLocation.scala @@ -0,0 +1,61 @@ +package com.github.unchama.seichiassist.subsystems.elevator.bukkit.actions + +import cats.effect.Sync +import com.github.unchama.seichiassist.subsystems.elevator.application.actions.FindTeleportLocation +import org.bukkit.Location +import org.bukkit.Material + +class BukkitFindTeleportLocation[F[_]: Sync] extends FindTeleportLocation[F, Location] { + + override def currentLocationTeleportFromAsCorrectIs(currentLocation: Location): F[Boolean] = + Sync[F].delay { + currentLocation + .clone() + .add(0, -1, 0) + .getBlock + .getType == Material.IRON_BLOCK && currentLocation + .getBlock + .getType == Material.HEAVY_WEIGHTED_PRESSURE_PLATE + } + + override def isTeleportTargetLocation(targetLocation: Location): F[Boolean] = Sync[F].delay { + targetLocation + .clone() + .add(0, -1, 0) + .getBlock + .getType == Material.IRON_BLOCK && targetLocation + .getBlock + .getType == Material.HEAVY_WEIGHTED_PRESSURE_PLATE && targetLocation + .clone() + .add(0, 1, 0) + .getBlock + .getType == Material.AIR + } + + import cats.implicits._ + + override def findUpperLocation(currentLocation: Location): F[Option[Location]] = { + (currentLocation.getY.toInt + 1 until currentLocation.getWorld.getMaxHeight) + .toVector + .map { y => + val location = currentLocation.clone() + location.setY(y) + + location + } + .findM(isTeleportTargetLocation) + } + + override def findLowerLocation(currentLocation: Location): F[Option[Location]] = { + (currentLocation.getY.toInt - 1 until currentLocation.getWorld.getMinHeight by -1) + .toVector + .map { y => + val location = currentLocation.clone() + location.setY(y) + + location + } + .findM(isTeleportTargetLocation) + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/listeners/ElevatorEventsListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/listeners/ElevatorEventsListener.scala new file mode 100644 index 0000000000..9bce467fa3 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/elevator/bukkit/listeners/ElevatorEventsListener.scala @@ -0,0 +1,60 @@ +package com.github.unchama.seichiassist.subsystems.elevator.bukkit.listeners + +import cats.effect.{ConcurrentEffect, Sync} +import com.github.unchama.generic.ApplicativeExtra +import com.github.unchama.generic.effect.unsafe.EffectEnvironment +import com.github.unchama.seichiassist.subsystems.elevator.application.actions.FindTeleportLocation +import org.bukkit.Location +import org.bukkit.event.player.{PlayerMoveEvent, PlayerToggleSneakEvent} +import org.bukkit.event.{EventHandler, Listener} + +class ElevatorEventsListener[F[_]: ConcurrentEffect]( + implicit findTeleportLocation: FindTeleportLocation[F, Location], + effectEnvironment: EffectEnvironment +) extends Listener { + + import cats.implicits._ + + @EventHandler + def onJump(e: PlayerMoveEvent): Unit = { + val player = e.getPlayer + val currentLocation = player.getLocation + + if (player.isFlying || e.getFrom.getY >= e.getTo.getY) return + + val teleportEffect = for { + currentLocationIsCorrectTeleportLocation <- findTeleportLocation + .currentLocationTeleportFromAsCorrectIs(currentLocation) + teleportTargetLocation <- ApplicativeExtra.whenAOrElse( + currentLocationIsCorrectTeleportLocation + )(findTeleportLocation.findUpperLocation(currentLocation), None) + _ <- teleportTargetLocation.traverse { location => + Sync[F].delay(player.teleport(location)) + } + } yield () + + effectEnvironment.unsafeRunEffectAsync("エレベータの上昇処理を行う", teleportEffect) + } + + @EventHandler + def onSneak(e: PlayerToggleSneakEvent): Unit = { + val player = e.getPlayer + val currentLocation = player.getLocation + + if (!player.isSneaking) return + + val teleportEffect = for { + currentLocationIsCorrectTeleportLocation <- findTeleportLocation + .currentLocationTeleportFromAsCorrectIs(currentLocation) + teleportTargetLocation <- ApplicativeExtra.whenAOrElse( + currentLocationIsCorrectTeleportLocation + )(findTeleportLocation.findLowerLocation(currentLocation), None) + _ <- teleportTargetLocation.traverse { location => + Sync[F].delay(player.teleport(location)) + } + } yield () + + effectEnvironment.unsafeRunEffectAsync("エレベータの降下処理を行う", teleportEffect) + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/expbottlestack/bukkit/listeners/ExpBottleStackUsageController.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/expbottlestack/bukkit/listeners/ExpBottleStackUsageController.scala index 5cce9248f3..1776eee635 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/expbottlestack/bukkit/listeners/ExpBottleStackUsageController.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/expbottlestack/bukkit/listeners/ExpBottleStackUsageController.scala @@ -46,7 +46,7 @@ class ExpBottleStackUsageController[F[_]: Effect, G[_]: SyncEffect]( if ( player.isSneaking && playerInventory.getItemInMainHand != null - && playerInventory.getItemInMainHand.getType == Material.EXP_BOTTLE + && playerInventory.getItemInMainHand.getType == Material.EXPERIENCE_BOTTLE && (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK) ) { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/application/process/PlayerCountEffectSynchronization.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/application/process/PlayerCountEffectSynchronization.scala index 0f9c2d60c1..50009bd66e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/application/process/PlayerCountEffectSynchronization.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/application/process/PlayerCountEffectSynchronization.scala @@ -2,7 +2,6 @@ package com.github.unchama.seichiassist.subsystems.fastdiggingeffect.application import cats.effect.{ConcurrentEffect, Timer} import com.github.unchama.minecraft.actions.GetConnectedPlayers -import com.github.unchama.minecraft.algebra.HasUuid import com.github.unchama.seichiassist.domain.actions.GetNetworkConnectionCount import com.github.unchama.seichiassist.subsystems.fastdiggingeffect.FastDiggingEffectApi import com.github.unchama.seichiassist.subsystems.fastdiggingeffect.application.Configuration @@ -21,7 +20,7 @@ object PlayerCountEffectSynchronization { def using[F[_]: ConcurrentEffect: Timer: GetConnectedPlayers[ *[_], Player - ]: GetNetworkConnectionCount, Player: HasUuid]( + ]: GetNetworkConnectionCount, Player]( implicit configuration: Configuration, api: FastDiggingEffectApi[F, Player] ): fs2.Stream[F, Unit] = { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/bukkit/actions/GrantBukkitFastDiggingEffect.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/bukkit/actions/GrantBukkitFastDiggingEffect.scala index 174c6976b0..6ce2baee5d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/bukkit/actions/GrantBukkitFastDiggingEffect.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/fastdiggingeffect/bukkit/actions/GrantBukkitFastDiggingEffect.scala @@ -1,12 +1,12 @@ package com.github.unchama.seichiassist.subsystems.fastdiggingeffect.bukkit.actions -import cats.effect.{Sync, SyncIO} +import cats.effect.SyncIO import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.subsystems.fastdiggingeffect.domain.actions.GrantFastDiggingEffect import org.bukkit.entity.Player import org.bukkit.potion.{PotionEffect, PotionEffectType} -class GrantBukkitFastDiggingEffect[F[_]: Sync: OnMinecraftServerThread] +class GrantBukkitFastDiggingEffect[F[_]: OnMinecraftServerThread] extends GrantFastDiggingEffect[F, Player] { override def forTwoSeconds(player: Player)(amount: Int): F[Unit] = { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/System.scala index 7de4971007..47216e0e1f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/System.scala @@ -76,7 +76,7 @@ object System { override val openPocketInventory: Kleisli[F, Player, Unit] = Kleisli { player => Sync[F].delay { // 開く音を再生 - player.playSound(player.getLocation, Sound.BLOCK_ENDERCHEST_OPEN, 1f, 0.1f) + player.playSound(player.getLocation, Sound.BLOCK_ENDER_CHEST_OPEN, 1f, 0.1f) } >> ContextCoercion { pocketInventoryRepositoryHandles.repository(player)._1.readLatest }.flatMap(inventory => interactInventory.open(inventory)(player)) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/bukkit/listeners/OpenPocketInventoryOnPlacingEnderPortalFrame.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/bukkit/listeners/OpenPocketInventoryOnPlacingEnderPortalFrame.scala index 94dd36e456..137752e861 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/bukkit/listeners/OpenPocketInventoryOnPlacingEnderPortalFrame.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/fourdimensionalpocket/bukkit/listeners/OpenPocketInventoryOnPlacingEnderPortalFrame.scala @@ -22,7 +22,7 @@ class OpenPocketInventoryOnPlacingEnderPortalFrame[F[_]: Effect]( val action = event.getAction val hand = event.getHand - if (event.getMaterial != Material.ENDER_PORTAL_FRAME) { + if (event.getMaterial != Material.END_PORTAL_FRAME) { return } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/System.scala index 5371812d15..c010c31141 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/System.scala @@ -2,7 +2,7 @@ package com.github.unchama.seichiassist.subsystems.gacha import cats.data.Kleisli import cats.effect.ConcurrentEffect -import com.github.unchama.minecraft.actions.OnMinecraftServerThread +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.minecraft.bukkit.algebra.CloneableBukkitItemStack.instance import com.github.unchama.seichiassist.meta.subsystem.Subsystem import com.github.unchama.seichiassist.subsystems.gacha.application.actions.{ @@ -38,9 +38,11 @@ trait System[F[_], Player] extends Subsystem[F] { object System { - def wired[F[_]: ConcurrentEffect: OnMinecraftServerThread]( + def wired[F[_]: ConcurrentEffect: OnMinecraftServerThread: GetConnectedPlayers[ + *[_], + Player + ]: GachaTicketAPI]( implicit gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], - gachaTicketAPI: GachaTicketAPI[F], mineStackAPI: MineStackAPI[F, Player, ItemStack] ): System[F, Player] = { implicit val canBeSignedAsGachaPrize: CanBeSignedAsGachaPrize[ItemStack] = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/GachaCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/GachaCommand.scala index 5846f2ebe5..70dfcdabca 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/GachaCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/GachaCommand.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.gacha.bukkit import cats.data.Kleisli -import cats.effect.{ConcurrentEffect, Effect, Sync} +import cats.effect.ConcurrentEffect import com.github.unchama.contextualexecutor.ContextualExecutor import com.github.unchama.contextualexecutor.builder.ParserResponse.{failWith, succeedWith} import com.github.unchama.contextualexecutor.builder.{ @@ -31,7 +31,7 @@ import eu.timepit.refined.api.Refined import eu.timepit.refined.auto._ import eu.timepit.refined.numeric.{Interval, NonNegative, Positive} import org.bukkit.ChatColor._ -import org.bukkit.command.TabExecutor +import org.bukkit.command.{CommandSender, TabExecutor} import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import shapeless.HNil @@ -154,7 +154,7 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( case "all" => Kleisli .liftF(gachaTicketAPI.addToAllKnownPlayers(amount)) - .flatMap(_ => MessageEffectF(s"${GREEN}全プレイヤーへガチャ券${amount}枚加算成功")) + .flatMap(_ => MessageEffectF(s"${GREEN}全プレイヤーへガチャ券${amount.value}枚加算成功")) case value => val uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}".r @@ -187,35 +187,34 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( MessageEffect("IDは0以上の整数を指定してください。") ) ) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => import shapeless.:: val gachaPrizeId :: shapeless.HNil = context.args.parsed // optional val ownerName = context.args.yetToBeParsed.headOption - for { - gachaPrize <- gachaPrizeAPI.fetch(GachaPrizeId(gachaPrizeId)) - existsGachaPrize = gachaPrize.nonEmpty - _ <- Sync[F].delay { - gachaPrize.foreach { gachaPrize => - val itemStack = ownerName match { - case Some(name) => gachaPrize.materializeWithOwnerSignature(name) - case None => gachaPrize.itemStack + Kleisli + .liftF { + for { + gachaPrize <- gachaPrizeAPI.fetch(GachaPrizeId(gachaPrizeId)) + _ <- gachaPrize.traverse { gachaPrize => + val itemStack = ownerName match { + case Some(name) => gachaPrize.materializeWithOwnerSignature(name) + case None => gachaPrize.itemStack + } + + InventoryOperations.grantItemStacksEffect(itemStack).apply(context.sender) } - - InventoryOperations.grantItemStacksEffect(itemStack).apply(context.sender) - } + } yield gachaPrize + } + .flatMap { + case Some(_) => MessageEffectF("ガチャアイテムを付与しました。") + case None => MessageEffectF("指定されたIDのガチャ景品は存在しません。") } - } yield { - if (existsGachaPrize) - MessageEffect("ガチャアイテムを付与しました。") - else - MessageEffect("指定されたIDのガチャ景品は存在しません。") - } } val add: ContextualExecutor = - playerCommandBuilder.thenParse(probabilityParser).buildWithExecutionF { context => + playerCommandBuilder.thenParse(probabilityParser).buildWithExecutionCSEffect { context => import shapeless.:: val player = context.sender @@ -223,32 +222,35 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( val eventName = context.args.yetToBeParsed.headOption.map(GachaEventName) val mainHandItem = player.getInventory.getItemInMainHand - for { - events <- gachaPrizeAPI.createdGachaEvents - _ <- gachaPrizeAPI.addGachaPrize( - domain.GachaPrizeTableEntry( - mainHandItem, - GachaProbability(probability), - probability < 0.1, - _, - events.find(gachaEvent => eventName.contains(gachaEvent.eventName)) - ) - ) - } yield MessageEffect(List("ガチャアイテムを追加しました!")) + Kleisli + .liftF[F, CommandSender, Unit] { + for { + events <- gachaPrizeAPI.createdGachaEvents + _ <- gachaPrizeAPI.addGachaPrize( + domain.GachaPrizeTableEntry( + mainHandItem, + GachaProbability(probability), + probability < 0.1, + _, + events.find(gachaEvent => eventName.contains(gachaEvent.eventName)) + ) + ) + } yield () + } + .productR(MessageEffectF("ガチャアイテムを追加しました!")) } val list: ContextualExecutor = - ContextualExecutorBuilder.beginConfiguration.buildWithExecutionF { context => + ContextualExecutorBuilder.beginConfiguration.buildWithExecutionCSEffect { context => val eventName = context.args.yetToBeParsed.headOption.map(GachaEventName) - for { - gachaPrizes <- gachaPrizeAPI.allGachaPrizeList - } yield { - val gachaPrizeInformation = gachaPrizes - .filter { gachaPrize => - if (eventName.isEmpty) gachaPrize.nonGachaEventItem - else - gachaPrize.gachaEvent.map(_.eventName) == eventName - } + Kleisli.liftF(gachaPrizeAPI.allGachaPrizeList).flatMap { gachaPrizes => + val eventGachaPrizes = gachaPrizes.filter { gachaPrize => + if (eventName.isEmpty) gachaPrize.nonGachaEventItem + else + gachaPrize.gachaEvent.map(_.eventName) == eventName + } + + val gachaPrizeInformation = eventGachaPrizes .sortBy(_.id.id) .map { gachaPrize => val itemStack = gachaPrize.itemStack @@ -260,8 +262,8 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( } .toList - val totalProbability = gachaPrizes.map(_.probability.value).sum - MessageEffect( + val totalProbability = eventGachaPrizes.map(_.probability.value).sum + MessageEffectF( List(s"${RED}アイテム番号|アイテム名|アイテム数|出現確率") ++ gachaPrizeInformation ++ List( s"${RED}合計確率: $totalProbability(${totalProbability * 100}%)", s"${RED}合計確率は100%以内に収まるようにしてください。" @@ -279,15 +281,15 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( MessageEffect("IDは正の値を指定してください。") ) ) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => val gachaId = GachaPrizeId(context.args.parsed.head) - for { - didRemoveGachaPrize <- gachaPrizeAPI.removeByGachaPrizeId(gachaId) - } yield { - if (didRemoveGachaPrize) - MessageEffect(List("ガチャアイテムを削除しました")) - else - MessageEffect("指定されたIDのガチャ景品が存在しないため、ガチャアイテムを削除できませんでした。") + Kleisli.liftF(gachaPrizeAPI.removeByGachaPrizeId(gachaId)).flatMap { + didRemoveGachaPrize => + if (didRemoveGachaPrize) { + MessageEffectF("ガチャアイテムを削除しました") + } else { + MessageEffectF("指定されたIDのガチャ景品が存在しないため、ガチャアイテムを削除できませんでした。") + } } } @@ -302,53 +304,56 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( MessageEffect("数は1~64で指定してください。") ) ) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => import shapeless.:: val targetId :: amount :: HNil = context.args.parsed - for { - currentGachaPrize <- gachaPrizeAPI.fetch(targetId) - oldItemStack <- currentGachaPrize.traverse { prize => - gachaPrizeAPI - .upsertGachaPrize( - prize.copy(itemStack = prize.itemStack.tap(_.setAmount(amount))) - ) - .as(Some(prize.itemStack)) - } - } yield { - oldItemStack match { + + Kleisli + .liftF(for { + currentGachaPrize <- gachaPrizeAPI.fetch(targetId) + oldItemStack <- currentGachaPrize.traverse { prize => + gachaPrizeAPI + .upsertGachaPrize( + prize.copy(itemStack = prize.itemStack.tap(_.setAmount(amount))) + ) + .as(Some(prize.itemStack)) + } + } yield oldItemStack) + .flatMap { case Some(itemStack) => - MessageEffect( + MessageEffectF( s"${targetId.id}|${itemStack.get.getType.toString}/${itemStack.get.getItemMeta.getDisplayName}${RESET}のアイテム数を${amount}個に変更しました。" ) case None => - MessageEffect("指定されたIDのガチャ景品が存在しないため、アイテム数が変更できませんでした。") + MessageEffectF("指定されたIDのガチャ景品が存在しないため、アイテム数が変更できませんでした。") } - } } val setProbability: ContextualExecutor = ContextualExecutorBuilder .beginConfiguration .thenParse(gachaPrizeIdExistsParser) .thenParse(probabilityParser) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => import shapeless.:: val targetId :: newProb :: HNil = context.args.parsed - for { - currentGachaPrize <- gachaPrizeAPI.fetch(targetId) - probabilityChange <- currentGachaPrize.traverse { gachaPrize => - gachaPrizeAPI.upsertGachaPrize( - gachaPrize.copy(probability = GachaProbability(newProb)) - ) - } + + (for { + currentGachaPrize <- Kleisli.liftF(gachaPrizeAPI.fetch(targetId)) + probabilityChange <- Kleisli.liftF(currentGachaPrize.traverse { gachaPrize => + gachaPrizeAPI + .upsertGachaPrize(gachaPrize.copy(probability = GachaProbability(newProb))) + }) itemStack = currentGachaPrize.map(_.itemStack) } yield { - if (probabilityChange.nonEmpty) - MessageEffect( + if (probabilityChange.nonEmpty) { + MessageEffectF( s"${targetId.id}|${itemStack.get.getType.toString}/${itemStack.get.getItemMeta.getDisplayName}${RESET}の確率を$newProb(${newProb * 100}%)に変更しました。" ) - else - MessageEffect("指定されたIDのガチャ景品は存在しません。") - } + } else { + MessageEffectF("指定されたIDのガチャ景品は存在しません。") + } + }).flatten + } val createEvent: ContextualExecutor = @@ -357,7 +362,7 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( .thenParse(Parsers.identity) .thenParse(Parsers.identity) .thenParse(Parsers.identity) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => import shapeless.:: val e :: startDate :: endDate :: HNil = context.args.parsed val eventName = GachaEventName(e) @@ -366,38 +371,42 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( val dateRegex = "[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])".r if (!dateRegex.matches(startDate) || !dateRegex.matches(endDate)) { - Effect[F].pure(MessageEffect(s"${RED}開始日/終了日はyyyy-MM-ddの形式で指定してください。")) + MessageEffectF(s"${RED}開始日/終了日はyyyy-MM-ddの形式で指定してください。") } else if (eventName.name.length > 30) { - Effect[F].pure(MessageEffect(s"${RED}イベント名は30字以内で指定してください。")) + MessageEffectF(s"${RED}イベント名は30字以内で指定してください。") } else { for { - existsEvent <- gachaPrizeAPI.existsGachaEvent(eventName) - _ <- gachaPrizeAPI - .createGachaEvent( - GachaEvent( - eventName, - LocalDate.parse(startDate, dateTimeFormatter), - LocalDate.parse(endDate, dateTimeFormatter) + existsEvent <- Kleisli.liftF(gachaPrizeAPI.existsGachaEvent(eventName)) + _ <- Kleisli.liftF( + gachaPrizeAPI + .createGachaEvent( + GachaEvent( + eventName, + LocalDate.parse(startDate, dateTimeFormatter), + LocalDate.parse(endDate, dateTimeFormatter) + ) ) - ) - .unlessA(existsEvent) + .unlessA(existsEvent) + ) } yield { - if (existsEvent) MessageEffect(s"${RED}指定された名前のイベントが既に存在します。") - else MessageEffect(s"${AQUA}イベントを作成しました。") + if (existsEvent) MessageEffectF(s"${RED}指定された名前のイベントが既に存在します。") + else MessageEffectF(s"${AQUA}イベントを作成しました。") } - } + }.flatten + } val deleteEvent: ContextualExecutor = ContextualExecutorBuilder .beginConfiguration .thenParse(Parsers.identity) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => val eventName = GachaEventName(context.args.parsed.head) - for { - _ <- gachaPrizeAPI.deleteGachaEvent(eventName) - } yield MessageEffect(s"ガチャイベント: ${eventName.name}を削除しました。") + + Kleisli.liftF(gachaPrizeAPI.deleteGachaEvent(eventName)).flatMap { _ => + MessageEffectF(s"ガチャイベント: ${eventName.name}を削除しました。") + } } private def toTimeString(localDate: LocalDate): String = { @@ -406,14 +415,13 @@ class GachaCommand[F[_]: OnMinecraftServerThread: ConcurrentEffect]( } val eventList: ContextualExecutor = - ContextualExecutorBuilder.beginConfiguration.buildWithExecutionF { _ => - for { - events <- gachaPrizeAPI.createdGachaEvents - } yield { + ContextualExecutorBuilder.beginConfiguration.buildWithExecutionCSEffect { _ => + Kleisli.liftF(gachaPrizeAPI.createdGachaEvents).flatMap { events => val messages = "イベント名 | 開始日 | 終了日" +: events.map { event => s"${event.eventName.name} | ${toTimeString(event.startDate)} | ${toTimeString(event.endDate)}" } - MessageEffect(messages.toList) + + MessageEffectF(messages.toList) } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitDrawGacha.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitDrawGacha.scala index 4277428df4..2306118995 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitDrawGacha.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitDrawGacha.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.gacha.bukkit.actions -import cats.effect.{IO, Sync} -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread +import cats.effect.{LiftIO, Sync} +import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} import com.github.unchama.seichiassist.subsystems.gacha.application.actions.{ DrawGacha, GrantGachaPrize @@ -11,24 +11,28 @@ import com.github.unchama.seichiassist.subsystems.gachaprize.GachaPrizeAPI import com.github.unchama.seichiassist.subsystems.gachaprize.domain.GachaRarity._ import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryone import com.github.unchama.seichiassist.util._ +import net.md_5.bungee.api.chat.hover.content.Text import net.md_5.bungee.api.chat.{HoverEvent, TextComponent} import org.bukkit.ChatColor._ import org.bukkit.Sound import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack -class BukkitDrawGacha[F[_]: Sync]( +class BukkitDrawGacha[ + F[_]: LiftIO: Sync: OnMinecraftServerThread: GetConnectedPlayers[*[_], Player] +]( implicit gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], lotteryOfGachaItems: LotteryOfGachaItems[F, ItemStack], grantGachaPrize: GrantGachaPrize[F, ItemStack, Player] ) extends DrawGacha[F, Player] { - import PlayerSendable._ import cats.implicits._ import scala.jdk.CollectionConverters._ override def draw(player: Player, count: Int): F[Unit] = { + implicitly[PlayerSendable[TextComponent, F]] + for { currentGachaPrizes <- gachaPrizeAPI.listOfNow gachaPrizes <- lotteryOfGachaItems.runLottery(count, currentGachaPrizes) @@ -49,7 +53,7 @@ class BukkitDrawGacha[F[_]: Sync]( val localizedEnchantmentList = prizeItem.getItemMeta.getEnchants.asScala.toSeq.map { case (enchantment, level) => - s"$GRAY${EnchantNameToJapanese.getEnchantName(enchantment.getName, level)}" + s"$GRAY${EnchantNameToJapanese.getEnchantName(enchantment.getKey.toString, level)}" } import scala.util.chaining._ @@ -62,13 +66,11 @@ class BukkitDrawGacha[F[_]: Sync]( setHoverEvent { new HoverEvent( HoverEvent.Action.SHOW_TEXT, - Array( - new TextComponent( - s" ${prizeItem.getItemMeta.getDisplayName}\n" + - ListFormatters.getDescFormat(localizedEnchantmentList.toList) + - ListFormatters - .getDescFormat(prizeItem.getItemMeta.getLore.asScala.toList) - ) + new Text( + s" ${prizeItem.getItemMeta.getDisplayName}\n" + + ListFormatters.getDescFormat(localizedEnchantmentList.toList) + + ListFormatters + .getDescFormat(prizeItem.getItemMeta.getLore.asScala.toList) ) ) } @@ -76,16 +78,15 @@ class BukkitDrawGacha[F[_]: Sync]( Sync[F].delay { player.sendMessage(s"${RED}おめでとう!!!!!Gigantic☆大当たり!$additionalMessage") player.spigot().sendMessage(message) - sendMessageToEveryone(s"$GOLD${player.getName}がガチャでGigantic☆大当たり!")( - forString[IO] - ) - sendMessageToEveryone(message)(forTextComponent[IO]) + } >> Sync[F].delay { SendSoundEffect.sendEverySoundWithoutIgnore( - Sound.ENTITY_ENDERDRAGON_DEATH, + Sound.ENTITY_ENDER_DRAGON_DEATH, 0.5f, 2f ) - } + } >> sendMessageToEveryone[String, F]( + s"$GOLD${player.getName}がガチャでGigantic☆大当たり!" + ) case GachaRarity.Big => Sync[F].delay { player.playSound(player.getLocation, Sound.ENTITY_WITHER_SPAWN, 0.8f, 1f) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitGrantGachaPrize.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitGrantGachaPrize.scala index a020a2faa3..2d7afa8cf0 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitGrantGachaPrize.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/bukkit/actions/BukkitGrantGachaPrize.scala @@ -28,18 +28,15 @@ class BukkitGrantGachaPrize[F[_]: Sync: OnMinecraftServerThread]( Kleisli { player => for { currentAutoMineStackState <- mineStackAPI.autoMineStack(player) - results <- prizes.traverse { gachaPrize => - val itemStack = gachaPrize.itemStack - whenAOrElse(currentAutoMineStackState)( - mineStackAPI - .mineStackRepository - .tryIntoMineStack(player, itemStack, itemStack.getAmount) - .map(hasBeenStoredInMineStack => gachaPrize -> hasBeenStoredInMineStack), - gachaPrize -> false - ) - } - } yield results.collect { - case (gachaPrize, result) if !result => gachaPrize + itemStacks <- Sync[F].delay(prizes.map(_.materializeWithOwnerSignature(player.getName))) + intoFailedItemStacksAndSuccessItemStacks <- whenAOrElse(currentAutoMineStackState)( + mineStackAPI.mineStackRepository.tryIntoMineStack(player, itemStacks), + (itemStacks, Vector.empty) + ) + } yield prizes.filter { prize => + intoFailedItemStacksAndSuccessItemStacks + ._1 + .exists(_.isSimilar(prize.materializeWithOwnerSignature(player.getName))) } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/domain/LotteryOfGachaItems.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/domain/LotteryOfGachaItems.scala index da1d282802..9c3b74d30d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/domain/LotteryOfGachaItems.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/domain/LotteryOfGachaItems.scala @@ -2,8 +2,8 @@ package com.github.unchama.seichiassist.subsystems.gacha.domain import cats.effect.Sync import com.github.unchama.seichiassist.subsystems.gachaprize.domain.{ - GachaPrizeTableEntry, GachaPrizeId, + GachaPrizeTableEntry, GachaProbability, StaticGachaPrizeFactory } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/subsystems/gachaticket/infrastructure/JdbcGachaTicketFromAdminTeamRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/subsystems/gachaticket/infrastructure/JdbcGachaTicketFromAdminTeamRepository.scala index c5a181a819..225eb30ec7 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/subsystems/gachaticket/infrastructure/JdbcGachaTicketFromAdminTeamRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gacha/subsystems/gachaticket/infrastructure/JdbcGachaTicketFromAdminTeamRepository.scala @@ -42,7 +42,7 @@ class JdbcGachaTicketFromAdminTeamRepository[F[_]: Sync: NonServerThreadContextS DB.localTx { implicit session => val affectedRows = sql"UPDATE playerdata SET numofsorryforbug = numofsorryforbug + ${amount.value} WHERE name = ${playerName.name}" - .update + .update() .apply() getReceiptResult(affectedRows) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/System.scala index ca33d5777e..311a18deb2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/System.scala @@ -11,7 +11,7 @@ import com.github.unchama.generic.ContextCoercion import com.github.unchama.generic.effect.EffectExtra import com.github.unchama.generic.effect.concurrent.ReadOnlyRef import com.github.unchama.generic.effect.stream.StreamExtra -import com.github.unchama.minecraft.actions.{GetConnectedPlayers, OnMinecraftServerThread} +import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.meta.subsystem.Subsystem import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI import com.github.unchama.seichiassist.subsystems.gachapoint.application.process.AddSeichiExpAsGachaPoint @@ -34,9 +34,9 @@ object System { import cats.effect.implicits._ import cats.implicits._ - def wired[F[_]: ConcurrentEffect: Timer: GetConnectedPlayers[*[_], Player]: ErrorLogger, G[ + def wired[F[_]: ConcurrentEffect: Timer: ErrorLogger, G[_]: SyncEffect: ContextCoercion[*[ _ - ]: SyncEffect: ContextCoercion[*[_], F]]( + ], F]]( breakCountReadAPI: BreakCountReadAPI[F, G, Player] )(implicit ioOnMainThread: OnMinecraftServerThread[IO]): G[System[F, G, Player]] = { import com.github.unchama.minecraft.bukkit.algebra.BukkitPlayerHasUuid.instance diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/application/process/AddSeichiExpAsGachaPoint.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/application/process/AddSeichiExpAsGachaPoint.scala index d70733c303..f12b5e671f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/application/process/AddSeichiExpAsGachaPoint.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachapoint/application/process/AddSeichiExpAsGachaPoint.scala @@ -3,7 +3,6 @@ package com.github.unchama.seichiassist.subsystems.gachapoint.application.proces import cats.Applicative import cats.effect.concurrent.Ref import com.github.unchama.datarepository.KeyedDataRepository -import com.github.unchama.minecraft.algebra.HasUuid import com.github.unchama.seichiassist.subsystems.breakcount.domain.level.SeichiExpAmount import com.github.unchama.seichiassist.subsystems.gachapoint.domain.gachapoint.GachaPoint @@ -11,7 +10,7 @@ object AddSeichiExpAsGachaPoint { import cats.implicits._ - def stream[F[_]: Applicative, Player: HasUuid]( + def stream[F[_]: Applicative, Player]( refRepository: KeyedDataRepository[Player, Ref[F, GachaPoint]] )(seichiExpStream: fs2.Stream[F, (Player, SeichiExpAmount)]): fs2.Stream[F, Unit] = seichiExpStream.evalMap { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitGachaSkullData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitGachaSkullData.scala index 816a4acda3..88bac8e12d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitGachaSkullData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitGachaSkullData.scala @@ -1,76 +1,36 @@ package com.github.unchama.seichiassist.subsystems.gachaprize.bukkit.factories -import com.github.unchama.seichiassist.util.ItemMetaFactory +import com.github.unchama.itemstackbuilder.SkullItemStackBuilder +import com.github.unchama.seichiassist.SkullOwners import org.bukkit.ChatColor._ -import org.bukkit.Material import org.bukkit.inventory.ItemStack object BukkitGachaSkullData { - import scala.jdk.CollectionConverters._ - import scala.util.chaining._ - /** * ノーマルガチャ券 */ val gachaSkull: ItemStack = - new ItemStack(Material.SKULL_ITEM, 1).tap { skull => - import skull._ - setDurability(3) - setItemMeta { - ItemMetaFactory.SKULL.getValue.tap { meta => - import meta._ - setDisplayName(s"$YELLOW${BOLD}ガチャ券") - setLore { - List(s"$RESET${GREEN}右クリックで使えます").asJava - } - - // 参加したことのないプレーヤーはgetOfflinePlayerでデータが取れないのでこうするしか無い - setOwner("unchama") - } - } - } + new SkullItemStackBuilder(SkullOwners.unchama) + .title(s"$YELLOW${BOLD}ガチャ券") + .lore(List(s"$RESET${GREEN}右クリックで使えます")) + .build() /** * 投票報酬のガチャ券 */ val gachaForVoting: ItemStack = - new ItemStack(Material.SKULL_ITEM, 1).tap { itemStack => - import itemStack._ - setDurability(3) - setItemMeta { - ItemMetaFactory.SKULL.getValue.tap { meta => - import meta._ - setDisplayName(s"$YELLOW${BOLD}ガチャ券") - setLore { - List(s"$RESET${GREEN}右クリックで使えます", s"$RESET${LIGHT_PURPLE}投票ありがとナス♡").asJava - } - - // 参加したことのないプレーヤーはgetOfflinePlayerでデータが取れないのでこうするしか無い - setOwner("unchama") - } - } - } + new SkullItemStackBuilder(SkullOwners.unchama) + .title(s"$YELLOW${BOLD}ガチャ券") + .lore(List(s"$RESET${GREEN}右クリックで使えます", s"$RESET${LIGHT_PURPLE}投票ありがとナス♡")) + .build() /** * ガチャ景品(当たり・大当たり)とガチャ券の交換システムで手に入るガチャ券 */ - val gachaForExchanging: ItemStack = { - new ItemStack(Material.SKULL_ITEM, 1).tap { itemStack => - import itemStack._ - setDurability(3) - setItemMeta { - ItemMetaFactory.SKULL.getValue.tap { meta => - import meta._ - setDisplayName(s"$YELLOW${BOLD}ガチャ券") - setLore { - List(s"$RESET${GREEN}右クリックで使えます", s"$RESET${GRAY}ガチャ景品と交換しました。").asJava - } - - // 参加したことのないプレーヤーはgetOfflinePlayerでデータが取れないのでこうするしか無い - setOwner("unchama") - } - } - } - } + val gachaForExchanging: ItemStack = + new SkullItemStackBuilder(SkullOwners.unchama) + .title(s"$YELLOW${BOLD}ガチャ券") + .lore(List(s"$RESET${GREEN}右クリックで使えます", s"$RESET${GRAY}ガチャ景品と交換しました。")) + .build() } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitStaticGachaPrizeFactory.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitStaticGachaPrizeFactory.scala index e15fd197ad..e4c082226f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitStaticGachaPrizeFactory.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/bukkit/factories/BukkitStaticGachaPrizeFactory.scala @@ -28,10 +28,10 @@ object BukkitStaticGachaPrizeFactory extends StaticGachaPrizeFactory[ItemStack] setItemMeta(meta) } - override val expBottle: ItemStack = new ItemStack(Material.EXP_BOTTLE, 20) + override val expBottle: ItemStack = new ItemStack(Material.EXPERIENCE_BOTTLE, 20) override val mineHeadItem: ItemStack = - new ItemStack(Material.CARROT_STICK, 1, 1.toShort).tap { itemStack => + new ItemStack(Material.CARROT_ON_A_STICK, 1).tap { itemStack => import itemStack._ val meta = getItemMeta meta.setDisplayName(s"${DARK_RED}死神の鎌") diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/domain/GachaRarity.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/domain/GachaRarity.scala index c5983cb395..02871e6ec8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/domain/GachaRarity.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gachaprize/domain/GachaRarity.scala @@ -38,11 +38,15 @@ object GachaRarity { override def values: IndexedSeq[GachaRarity] = findValues def of[ItemStack](gachaPrize: GachaPrizeTableEntry[ItemStack]): GachaRarity = + fromGachaProbability(gachaPrize.probability) + + def fromGachaProbability(gachaProbability: GachaProbability): GachaRarity = { GachaRarity .values - .filter { rarity => rarity.probabilityUpperLimit.value > gachaPrize.probability.value } + .filter(rarity => rarity.probabilityUpperLimit.value > gachaProbability.value) .minByOption(_.probabilityUpperLimit.value) .getOrElse(GachaRingoOrExpBottle) + } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/bukkit/BukkitRegionOperations.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/bukkit/BukkitRegionOperations.scala index 9ab2c05318..ec789febc2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/bukkit/BukkitRegionOperations.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/bukkit/BukkitRegionOperations.scala @@ -8,6 +8,8 @@ import com.github.unchama.seichiassist.subsystems.gridregion.domain.CardinalDire import com.github.unchama.seichiassist.subsystems.gridregion.domain.HorizontalAxisAlignedSubjectiveDirection.Ahead import com.github.unchama.seichiassist.subsystems.gridregion.domain._ import com.github.unchama.util.external.{WorldEditWrapper, WorldGuardWrapper} +import com.sk89q.worldedit.math.BlockVector3 +import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion import org.bukkit.Location import org.bukkit.entity.Player @@ -72,21 +74,16 @@ class BukkitRegionOperations[F[_]: Sync]( override def tryCreatingSelectedWorldGuardRegion(player: Player): F[Unit] = for { regionCount <- regionCountRepository(player).get + wgManager = WorldGuardWrapper.getRegionManager(player.getWorld) + selection = WorldEditWrapper.getSelection(player) + regionName = s"${player.getName}_${regionCount.value}" + region = new ProtectedCuboidRegion( + regionName, + BlockVector3.at(selection.getBlockX, -64, selection.getBlockZ), + BlockVector3.at(selection.getBlockX, 320, selection.getBlockZ) + ) regionCreateResult <- Sync[F].delay { - WorldEditWrapper - .getSelection(player) - .map { selection => - val regionName = s"${player.getName}_${regionCount.value}" - - WorldGuardWrapper.tryCreateRegion( - regionName, - player, - player.getWorld, - selection.getNativeMinimumPoint.toBlockVector, - selection.getNativeMaximumPoint.toBlockVector - ) - } - .getOrElse(()) + wgManager.addRegion(region) } _ <- regionCountRepository(player).update(_.increment) } yield regionCreateResult @@ -103,27 +100,18 @@ class BukkitRegionOperations[F[_]: Sync]( result <- if (!SeichiAssist.seichiAssistConfig.isGridProtectionEnabled(world)) { Sync[F].pure(RegionCreationResult.WorldProhibitsRegionCreation) - } else if (selection.isEmpty || wgManager.isEmpty) { + } else if (regionCount.value >= WorldGuardWrapper.getWorldMaxRegion(player.getWorld)) { Sync[F].pure(RegionCreationResult.Error) } else { Sync[F].delay { - val regions = WorldGuardWrapper.getApplicableRegionCount( - world, - s"${player.getName}_${regionCount.value}", - selection.get.getNativeMinimumPoint.toBlockVector, - selection.get.getNativeMaximumPoint.toBlockVector - ) - if (regions != 0) { + wgManager.getApplicableRegions(selection) + val maxRegionCount = WorldGuardWrapper.getWorldMaxRegion(world) + val regionCountPerPlayer = WorldGuardWrapper.getNumberOfRegions(player, world) + + if (maxRegionCount >= 0 && regionCountPerPlayer >= maxRegionCount) { RegionCreationResult.Error } else { - val maxRegionCount = WorldGuardWrapper.getMaxRegionCount(player, world) - val regionCountPerPlayer = WorldGuardWrapper.getRegionCountOfPlayer(player, world) - - if (maxRegionCount >= 0 && regionCountPerPlayer >= maxRegionCount) { - RegionCreationResult.Error - } else { - RegionCreationResult.Success - } + RegionCreationResult.Success } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/domain/RegionShapeSelectionState.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/domain/RegionShapeSelectionState.scala index da0a661d4f..ef30ba2922 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/domain/RegionShapeSelectionState.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/gridregion/domain/RegionShapeSelectionState.scala @@ -3,7 +3,7 @@ package com.github.unchama.seichiassist.subsystems.gridregion.domain import cats.effect.Sync import cats.effect.concurrent.Ref -class RegionShapeSelectionState[F[_]: Sync] private ( +class RegionShapeSelectionState[F[_]] private ( private val regionUnitsReference: Ref[F, SubjectiveRegionShape] ) { def currentShape: F[SubjectiveRegionShape] = regionUnitsReference.get diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/System.scala index 206e487bbd..3512ce47c7 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/System.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.subsystems.home -import cats.effect.{ConcurrentEffect, SyncEffect} +import cats.effect.ConcurrentEffect import com.github.unchama.concurrent.NonServerThreadContextShift import com.github.unchama.generic.ContextCoercion import com.github.unchama.minecraft.actions.OnMinecraftServerThread @@ -26,7 +26,7 @@ trait System[F[_]] extends Subsystem[F] { object System { def wired[F[_]: OnMinecraftServerThread: ConcurrentEffect: NonServerThreadContextShift, G[ _ - ]: SyncEffect: ContextCoercion[*[_], F]]( + ]: ContextCoercion[*[_], F]]( implicit breakCountReadAPI: BreakCountReadAPI[F, G, Player], buildCountReadAPI: BuildCountAPI[F, G, Player] ): System[F] = { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/bukkit/command/HomeCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/bukkit/command/HomeCommand.scala index 5f963be5f9..fda7d28c29 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/bukkit/command/HomeCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/bukkit/command/HomeCommand.scala @@ -1,8 +1,9 @@ package com.github.unchama.seichiassist.subsystems.home.bukkit.command import cats.Monad +import cats.data.Kleisli import cats.effect.implicits._ -import cats.effect.{ConcurrentEffect, Effect, IO, SyncEffect} +import cats.effect.{ConcurrentEffect, IO} import com.github.unchama.chatinterceptor.CancellationReason.Overridden import com.github.unchama.chatinterceptor.ChatInterceptionScope import com.github.unchama.concurrent.NonServerThreadContextShift @@ -32,7 +33,7 @@ class HomeCommand[F[ _ ]: OnMinecraftServerThread: ConcurrentEffect: NonServerThreadContextShift: HomeAPI, G[ _ -]: SyncEffect: ContextCoercion[*[_], F]]( +]: ContextCoercion[*[_], F]]( implicit scope: ChatInterceptionScope, breakCountReadAPI: BreakCountReadAPI[F, G, Player], buildCountReadAPI: BuildCountAPI[F, G, Player] @@ -86,11 +87,9 @@ class HomeCommand[F[ private def listExecutor() = { // locationの座標は負の無限大方向へ切り捨て(Debug画面のBlock:で表示される座標と同じ丸め方) def toBlockPos(pos: Double) = pos.floor.toInt - playerCommandBuilder.buildWithExecutionF { context => + playerCommandBuilder.buildWithExecutionCSEffect { context => val player = context.sender - val eff = for { - homeMap <- HomeReadAPI[F].list(player.getUniqueId) - } yield { + Kleisli.liftF(HomeReadAPI[F].list(player.getUniqueId)).flatMap { homeMap => val title = s"${RED}登録ホームポイント一覧:" val messages = title +: homeMap.toList.sortBy(_._1.value).map { case (homeId, home) => @@ -100,9 +99,8 @@ class HomeCommand[F[ ManagedWorld.fromName(worldName).map(_.japaneseName).getOrElse(worldName) f"${YELLOW}ID ${homeId.value}%2d $displayWorldName(${toBlockPos(x)}, ${toBlockPos(y)}, ${toBlockPos(z)}): $displayHomeName" } - MessageEffect(messages) + MessageEffectF(messages) } - eff.toIO } } @@ -129,35 +127,36 @@ class HomeCommand[F[ } private def warpExecutor = - argsAndSenderConfiguredBuilder.buildWithExecutionF { context => + argsAndSenderConfiguredBuilder.buildWithExecutionCSEffect { context => val homeId = HomeId(context.args.parsed.head) val player = context.sender val eff = for { - maxAvailableHomeCount <- Home.maxAvailableHomeCountF(player) - isHomeAvailable = maxAvailableHomeCount >= homeId.value - _ <- NonServerThreadContextShift[F].shift - homeLocation <- HomeReadAPI[F].get(player.getUniqueId, homeId) + maxAvailableHomeCount <- Kleisli.liftF(Home.maxAvailableHomeCountF(player)) + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) + homeLocation <- Kleisli.liftF(HomeReadAPI[F].get(player.getUniqueId, homeId)) } yield { + val isHomeAvailable = maxAvailableHomeCount >= homeId.value + if (isHomeAvailable) - homeLocation.fold(MessageEffect(s"ホームポイント${homeId}が設定されてません"))(home => { + homeLocation.fold(MessageEffectF[F](s"ホームポイント${homeId}が設定されてません")) { home => val location = home.location LocationCodec .toBukkitLocation(location) .fold( - MessageEffect( + MessageEffectF[F]( List(s"${RED}ホームポイントへのワープに失敗しました", s"${RED}登録先のワールドが削除された可能性があります") ) )(bukkitLocation => - TeleportEffect.to[F](bukkitLocation).mapK(Effect.toIOK[F]) >> - MessageEffect(s"ホームポイント${homeId}にワープしました") + TeleportEffect.to[F](bukkitLocation) >> + MessageEffectF[F](s"ホームポイント${homeId}にワープしました") ) - }) + } else - MessageEffect(s"ホームポイント${homeId}は現在のレベルでは使用できません") + MessageEffectF[F](s"ホームポイント${homeId}は現在のレベルでは使用できません") } - eff.toIO + eff.flatten } def setHomeExecutor(): ContextualExecutor = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/domain/Home.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/domain/Home.scala index 2e4146ce0c..fb47de08d3 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/home/domain/Home.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/home/domain/Home.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.subsystems.home.domain -import cats.effect.{ConcurrentEffect, SyncEffect} +import cats.effect.ConcurrentEffect import cats.implicits._ import com.github.unchama.generic.ContextCoercion import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI @@ -30,10 +30,9 @@ object Home { /** * プレイヤーの現在レベル(整地レベル、建築レベル)で利用可能なホームポイント数を取得する作用 */ - def maxAvailableHomeCountF[F[_]: ConcurrentEffect, G[_]: SyncEffect: ContextCoercion[ - *[_], - F - ], Player](player: Player)( + def maxAvailableHomeCountF[F[_]: ConcurrentEffect, G[_]: ContextCoercion[*[_], F], Player]( + player: Player + )( implicit breakCountReadAPI: BreakCountReadAPI[F, G, Player], buildCountReadAPI: BuildCountAPI[F, G, Player] ): F[Int] = { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/System.scala index 257ef27139..01274ae312 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/System.scala @@ -1,10 +1,9 @@ package com.github.unchama.seichiassist.subsystems.itemmigration -import cats.effect.{ConcurrentEffect, ContextShift, IO, Sync, SyncEffect, SyncIO} +import cats.effect.{ConcurrentEffect, IO, Sync, SyncEffect, SyncIO} import com.github.unchama.datarepository.bukkit.player.BukkitRepositoryControls import com.github.unchama.datarepository.template.RepositoryDefinition import com.github.unchama.generic.ContextCoercion -import com.github.unchama.generic.effect.unsafe.EffectEnvironment import com.github.unchama.itemmigration.application.ItemMigrationStateRepositoryDefinitions import com.github.unchama.itemmigration.bukkit.controllers.player.PlayerItemMigrationController import com.github.unchama.itemmigration.service.ItemMigrationService @@ -32,9 +31,8 @@ object System { import cats.implicits._ - def wired[F[_]: ConcurrentEffect: ContextShift, G[_]: SyncEffect: ContextCoercion[*[_], F]]( - implicit effectEnvironment: EffectEnvironment, - logger: Logger + def wired[F[_]: ConcurrentEffect, G[_]: SyncEffect: ContextCoercion[*[_], F]]( + implicit logger: Logger ): G[System[F]] = for { migrations <- Sync[G].delay { implicit val syncIOUuidRepository: UuidRepository[SyncIO] = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/controllers/DatabaseMigrationController.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/controllers/DatabaseMigrationController.scala index db43855190..cc797a51fa 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/controllers/DatabaseMigrationController.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/controllers/DatabaseMigrationController.scala @@ -1,7 +1,6 @@ package com.github.unchama.seichiassist.subsystems.itemmigration.controllers import cats.effect.{Sync, SyncEffect, SyncIO} -import com.github.unchama.generic.effect.unsafe.EffectEnvironment import com.github.unchama.itemmigration.domain.ItemMigrations import com.github.unchama.itemmigration.service.ItemMigrationService import com.github.unchama.seichiassist.subsystems.itemmigration.infrastructure.loggers.PersistedItemsMigrationSlf4jLogger @@ -11,8 +10,7 @@ import org.slf4j.Logger import scalikejdbc.DB case class DatabaseMigrationController[F[_]: SyncEffect](migrations: ItemMigrations)( - implicit effectEnvironment: EffectEnvironment, - logger: Logger + implicit logger: Logger ) { lazy val runDatabaseMigration: F[Unit] = Sync[F].delay { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/minecraft/JdbcBackedUuidRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/minecraft/JdbcBackedUuidRepository.scala index fc00e4b536..5b37ca639d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/minecraft/JdbcBackedUuidRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/minecraft/JdbcBackedUuidRepository.scala @@ -3,7 +3,6 @@ package com.github.unchama.seichiassist.subsystems.itemmigration.infrastructure. import cats.Applicative import cats.effect.Sync import com.github.unchama.seichiassist.subsystems.itemmigration.domain.minecraft.UuidRepository -import org.slf4j.Logger import java.util.UUID @@ -44,9 +43,7 @@ object JdbcBackedUuidRepository { } } - def initializeInstanceIn[F[_]: Sync, G[_]: Applicative]( - implicit logger: Logger - ): F[UuidRepository[G]] = { + def initializeInstanceIn[F[_]: Sync, G[_]: Applicative]: F[UuidRepository[G]] = { import cats.implicits._ for { @@ -56,6 +53,6 @@ object JdbcBackedUuidRepository { } } - def initializeInstance[F[_]: Sync](implicit logger: Logger): F[UuidRepository[F]] = + def initializeInstance[F[_]: Sync](): F[UuidRepository[F]] = initializeInstanceIn[F, F] } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PersistedItemsMigrationVersionRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PersistedItemsMigrationVersionRepository.scala index 70907fb507..fc5ad8f745 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PersistedItemsMigrationVersionRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PersistedItemsMigrationVersionRepository.scala @@ -52,7 +52,7 @@ class PersistedItemsMigrationVersionRepository[F[_]](implicit dbSession: DBSessi sql""" select version_string from seichiassist.item_migration_on_database """.map { rs => rs.string("version_string") } - .list + .list() .apply() .flatMap(ItemMigrationVersionNumber.fromString) .toSet diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PlayerItemsMigrationVersionRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PlayerItemsMigrationVersionRepository.scala index 4c1e273b18..6a1cd103ba 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PlayerItemsMigrationVersionRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/PlayerItemsMigrationVersionRepository.scala @@ -33,7 +33,7 @@ class PlayerItemsMigrationVersionRepository[F[_]](serverId: String)(implicit F: select version_string from seichiassist.player_in_server_item_migration where server_id = $serverId and player_uuid = ${target.player.getUniqueId.toString} """.map { rs => rs.string("version_string") } - .list + .list() .apply() .flatMap(ItemMigrationVersionNumber.fromString) .toSet diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/WorldLevelItemsMigrationVersionRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/WorldLevelItemsMigrationVersionRepository.scala index d925e4c87a..37fcdbdd77 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/WorldLevelItemsMigrationVersionRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/infrastructure/repositories/WorldLevelItemsMigrationVersionRepository.scala @@ -32,7 +32,7 @@ class WorldLevelItemsMigrationVersionRepository[F[_]](serverId: String)(implicit sql""" select version_string from seichiassist.item_migration_in_server_world_levels where server_id = $serverId """.map { rs => rs.string("version_string") } - .list + .list() .apply() .flatMap(ItemMigrationVersionNumber.fromString) .toSet diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_0_0_MigrateMebiusToNewCodec.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_0_0_MigrateMebiusToNewCodec.scala index c58bcd791a..38b3b37b9c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_0_0_MigrateMebiusToNewCodec.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_0_0_MigrateMebiusToNewCodec.scala @@ -6,7 +6,7 @@ import com.github.unchama.itemmigration.domain.{ItemMigration, ItemMigrationVers import com.github.unchama.seichiassist.subsystems.itemmigration.domain.minecraft.UuidRepository import com.github.unchama.seichiassist.subsystems.itemmigration.migrations.V1_0_0_MigrateMebiusToNewCodec.OldBukkitMebiusItemStackCodec.OldMebiusRawProperty import com.github.unchama.seichiassist.subsystems.mebius.bukkit.codec.BukkitMebiusItemStackCodec.NBTTagConstants -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Material import org.bukkit.inventory.ItemStack @@ -24,7 +24,6 @@ object V1_0_0_MigrateMebiusToNewCodec { // noinspection DuplicatedCode object OldBukkitMebiusItemStackCodec { - import de.tr7zw.itemnbtapi.NBTItem import org.bukkit.inventory.ItemStack private val mebiusLoreHead = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_1_0_AddUnbreakableToNarutoRemake.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_1_0_AddUnbreakableToNarutoRemake.scala index f4d1bced70..fec6d6914d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_1_0_AddUnbreakableToNarutoRemake.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/itemmigration/migrations/V1_1_0_AddUnbreakableToNarutoRemake.scala @@ -36,7 +36,6 @@ object V1_1_0_AddUnbreakableToNarutoRemake { itemStack.clone().tap { clone => import clone._ - setDurability(0.toShort) setItemMeta { getItemMeta.tap { itemMeta => import itemMeta._ diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/System.scala new file mode 100644 index 0000000000..3ce22378fd --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/System.scala @@ -0,0 +1,15 @@ +package com.github.unchama.seichiassist.subsystems.joinandquitmessenger + +import com.github.unchama.seichiassist.meta.subsystem.Subsystem +import com.github.unchama.seichiassist.subsystems.joinandquitmessenger.bukkit.JoinAndQuitListeners +import org.bukkit.event.Listener + +object System { + + def wired[F[_]]: Subsystem[F] = { + new Subsystem[F] { + override val listeners: Seq[Listener] = Seq(new JoinAndQuitListeners) + } + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/bukkit/JoinAndQuitListeners.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/bukkit/JoinAndQuitListeners.scala new file mode 100644 index 0000000000..5b19ae5551 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/bukkit/JoinAndQuitListeners.scala @@ -0,0 +1,20 @@ +package com.github.unchama.seichiassist.subsystems.joinandquitmessenger.bukkit + +import com.github.unchama.seichiassist.subsystems.joinandquitmessenger.domain.Messages +import org.bukkit.ChatColor +import org.bukkit.event.{EventHandler, Listener} +import org.bukkit.event.player.{PlayerJoinEvent, PlayerQuitEvent} + +class JoinAndQuitListeners extends Listener { + + @EventHandler + def onJoin(event: PlayerJoinEvent): Unit = { + event.setJoinMessage(s"${ChatColor.GRAY}${Messages.joinMessage(event.getPlayer.getName)}") + } + + @EventHandler + def onQuit(event: PlayerQuitEvent): Unit = { + event.setQuitMessage(Messages.quitMessage(event.getPlayer.getName)) + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/domain/Messages.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/domain/Messages.scala new file mode 100644 index 0000000000..0759f2ab00 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/joinandquitmessenger/domain/Messages.scala @@ -0,0 +1,10 @@ +package com.github.unchama.seichiassist.subsystems.joinandquitmessenger.domain + +object Messages { + + def joinMessage(playerName: String): String = s"$playerName がログインしました" + + // Note: 整地鯖では退出メッセージを表示しない + def quitMessage(playerName: String): String = "" + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/lastquit/bukkit/commands/LastQuitCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/lastquit/bukkit/commands/LastQuitCommand.scala index 6abbe4235b..1cb66dc606 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/lastquit/bukkit/commands/LastQuitCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/lastquit/bukkit/commands/LastQuitCommand.scala @@ -1,14 +1,14 @@ package com.github.unchama.seichiassist.subsystems.lastquit.bukkit.commands -import cats.effect.ConcurrentEffect.ops.toAllConcurrentEffectOps -import cats.effect.{ConcurrentEffect, IO} +import cats.data.Kleisli +import cats.effect.ConcurrentEffect import com.github.unchama.contextualexecutor.builder.{ContextualExecutorBuilder, Parsers} import com.github.unchama.seichiassist.infrastructure.minecraft.{ JdbcLastSeenNameToUuid, LastSeenNameToUuidError } import com.github.unchama.seichiassist.subsystems.lastquit.LastQuitAPI -import com.github.unchama.targetedeffect.commandsender.MessageEffect +import com.github.unchama.targetedeffect.commandsender.MessageEffectF import org.bukkit.ChatColor.RED import org.bukkit.command.TabExecutor @@ -21,30 +21,30 @@ class LastQuitCommand[F[_]: ConcurrentEffect](implicit lastQuitAPI: LastQuitAPI[ val executor: TabExecutor = ContextualExecutorBuilder .beginConfiguration .thenParse(Parsers.identity) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => val playerName = context.args.parsed.head - for { - uuidEither <- new JdbcLastSeenNameToUuid[IO].of(playerName) - lastQuit <- uuidEither.traverse(uuid => lastQuitAPI.get(uuid).toIO) + (for { + uuidEither <- Kleisli.liftF(new JdbcLastSeenNameToUuid[F].of(playerName)) + lastQuit <- Kleisli.liftF(uuidEither.traverse(uuid => lastQuitAPI.get(uuid))) } yield { lastQuit match { case Left(error) => error match { case LastSeenNameToUuidError.MultipleFound => - MessageEffect(s"${RED}指定された名前のプレイヤーが複数見つかりました。") + MessageEffectF(s"${RED}指定された名前のプレイヤーが複数見つかりました。") case LastSeenNameToUuidError.NotFound => - MessageEffect(s"${RED}指定された名前のプレイヤーが見つかりませんでした。") + MessageEffectF(s"${RED}指定された名前のプレイヤーが見つかりませんでした。") } case Right(lastQuitTimeOpt) => lastQuitTimeOpt match { case Some(lastQuitTime) => val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm") - MessageEffect( + MessageEffectF( s"${playerName}の最終ログアウト日時:${lastQuitTime.dateTime.format(dateTimeFormatter)}" ) case None => - MessageEffect( + MessageEffectF( List( s"${RED}最終ログアウト日時の照会に失敗しました。", s"${RED}プレイヤー名が変更されていないか確認してください。", @@ -53,7 +53,7 @@ class LastQuitCommand[F[_]: ConcurrentEffect](implicit lastQuitAPI: LastQuitAPI[ ) } } - } + }).flatten } .asNonBlockingTabExecutor() diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/RefillToCap.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/RefillToCap.scala index d56585e8a0..5cc675b0be 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/RefillToCap.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/RefillToCap.scala @@ -2,7 +2,7 @@ package com.github.unchama.seichiassist.subsystems.mana.application.process import cats.effect.concurrent.Ref import cats.implicits._ -import cats.{Functor, Monad} +import cats.Monad import com.github.unchama.datarepository.KeyedDataRepository import com.github.unchama.generic.{ContextCoercion, Diff} import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI @@ -13,7 +13,7 @@ import com.github.unchama.seichiassist.subsystems.mana.domain.LevelCappedManaAmo */ object RefillToCap { - def using[F[_]: Functor, G[_]: Monad: ContextCoercion[*[_], F], Player]( + def using[F[_], G[_]: Monad: ContextCoercion[*[_], F], Player]( repository: KeyedDataRepository[Player, Ref[G, LevelCappedManaAmount]] )(implicit breakCountReadAPI: BreakCountReadAPI[F, G, Player]): fs2.Stream[F, Unit] = { breakCountReadAPI.seichiStarLevelUpdates.evalMap { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/UpdateManaCaps.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/UpdateManaCaps.scala index 4329e87385..1c9dd48735 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/UpdateManaCaps.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mana/application/process/UpdateManaCaps.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.mana.application.process import cats.effect.concurrent.Ref -import cats.{Functor, Monad} +import cats.Monad import com.github.unchama.datarepository.KeyedDataRepository import com.github.unchama.generic.{ContextCoercion, Diff} import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI @@ -11,7 +11,7 @@ object UpdateManaCaps { import cats.implicits._ - def using[F[_]: Functor, G[_]: Monad: ContextCoercion[*[_], F], Player]( + def using[F[_], G[_]: Monad: ContextCoercion[*[_], F], Player]( repository: KeyedDataRepository[Player, Ref[G, LevelCappedManaAmount]] )(implicit breakCountReadAPI: BreakCountReadAPI[F, G, Player]): fs2.Stream[F, Unit] = breakCountReadAPI.seichiLevelUpdates.evalMap { diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/System.scala index 16b3b21273..90ac7b627c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/System.scala @@ -16,10 +16,12 @@ import com.github.unchama.seichiassist.subsystems.managedfly.application._ import com.github.unchama.seichiassist.subsystems.managedfly.application.repository.ActiveSessionReferenceRepositoryDefinition import com.github.unchama.seichiassist.subsystems.managedfly.bukkit.BukkitPlayerFlyStatusManipulation import com.github.unchama.seichiassist.subsystems.managedfly.bukkit.controllers.BukkitFlyCommand +import com.github.unchama.seichiassist.subsystems.managedfly.bukkit.listeners.BukkitPlayerStatusChangeListener import com.github.unchama.seichiassist.subsystems.managedfly.domain.PlayerFlyStatus import com.github.unchama.seichiassist.subsystems.managedfly.infrastructure.JdbcFlyDurationPersistenceRepository import org.bukkit.command.TabExecutor import org.bukkit.entity.Player +import org.bukkit.event.Listener /** * NOTE: このサブシステム(managedfly)は本来BuildAssist側に属するが、 @@ -75,6 +77,9 @@ object System { : Seq[BukkitRepositoryControls[AsyncContext, _]] = Seq(controls.coerceFinalizationContextTo[AsyncContext]) + override val listeners: Seq[Listener] = + Seq(new BukkitPlayerStatusChangeListener[AsyncContext, SyncContext]) + override val commands: Map[String, TabExecutor] = Map("fly" -> BukkitFlyCommand.executor[AsyncContext, SyncContext]) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/application/ActiveSessionReference.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/application/ActiveSessionReference.scala index 720fc0ea2d..2037fab461 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/application/ActiveSessionReference.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/application/ActiveSessionReference.scala @@ -8,9 +8,7 @@ import com.github.unchama.seichiassist.subsystems.managedfly.domain.{NotFlying, /** * プレーヤーの飛行セッションの参照 */ -class ActiveSessionReference[AsyncContext[_]: ConcurrentEffect, SyncContext[ - _ -]: Sync: ContextCoercion[*[_], AsyncContext]]( +class ActiveSessionReference[AsyncContext[_]: ConcurrentEffect, SyncContext[_]: Sync]( private val sessionMutexRef: Mutex[AsyncContext, SyncContext, Option[ ActiveSession[AsyncContext, SyncContext] ]] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/BukkitPlayerFlyStatusManipulation.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/BukkitPlayerFlyStatusManipulation.scala index 83a5187dd1..d9911a265c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/BukkitPlayerFlyStatusManipulation.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/BukkitPlayerFlyStatusManipulation.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.managedfly.bukkit import cats.data.Kleisli -import cats.effect.{Concurrent, Sync, SyncIO, Timer} +import cats.effect.{Concurrent, Sync, SyncIO} import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.subsystems.idletime.IdleTimeAPI import com.github.unchama.seichiassist.subsystems.managedfly.application._ @@ -10,9 +10,7 @@ import com.github.unchama.seichiassist.util.exp.ExperienceManager import org.bukkit.ChatColor.{GRAY, GREEN, RED} import org.bukkit.entity.Player -class BukkitPlayerFlyStatusManipulation[AsyncContext[ - _ -]: Timer: Concurrent: OnMinecraftServerThread]( +class BukkitPlayerFlyStatusManipulation[AsyncContext[_]: Concurrent: OnMinecraftServerThread]( implicit configuration: SystemConfiguration, idleTimeAPI: IdleTimeAPI[AsyncContext, Player] ) extends PlayerFlyStatusManipulation[Kleisli[AsyncContext, Player, *]] { @@ -92,7 +90,7 @@ class BukkitPlayerFlyStatusManipulation[AsyncContext[ private val sendMessages: List[String] => Kleisli[AsyncContext, Player, Unit] = { messages => Kleisli { player => Sync[AsyncContext].delay { - player.sendMessage(messages.toArray) + player.sendMessage(messages.mkString("\n")) } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/controllers/BukkitFlyCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/controllers/BukkitFlyCommand.scala index 6e222d6196..71aa2a38b1 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/controllers/BukkitFlyCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/controllers/BukkitFlyCommand.scala @@ -1,6 +1,7 @@ package com.github.unchama.seichiassist.subsystems.managedfly.bukkit.controllers -import cats.effect.{ConcurrentEffect, IO, SyncEffect, SyncIO, Timer} +import cats.data.Kleisli +import cats.effect.{ConcurrentEffect, IO, SyncEffect, SyncIO} import com.github.unchama.contextualexecutor.ContextualExecutor import com.github.unchama.contextualexecutor.builder.Parsers import com.github.unchama.contextualexecutor.executors.BranchedExecutor @@ -16,7 +17,7 @@ import com.github.unchama.seichiassist.subsystems.managedfly.domain.{ RemainingFlyDuration } import com.github.unchama.targetedeffect.TargetedEffect -import com.github.unchama.targetedeffect.commandsender.MessageEffect +import com.github.unchama.targetedeffect.commandsender.{MessageEffect, MessageEffectF} import eu.timepit.refined.api.Refined import eu.timepit.refined.numeric.Positive import org.bukkit.ChatColor._ @@ -53,7 +54,7 @@ object BukkitFlyCommand { import cats.effect.implicits._ import cats.implicits._ - def startEndlessCommand[F[_]: ConcurrentEffect: Timer, G[_]: SyncEffect]( + private def startEndlessCommand[F[_]: ConcurrentEffect, G[_]: SyncEffect]( implicit sessionReferenceRepository: KeyedDataRepository[Player, ActiveSessionReference[F, G]], factory: ActiveSessionFactory[F, Player] @@ -66,7 +67,7 @@ object BukkitFlyCommand { } yield TargetedEffect.emptyEffect } - def addCommand[F[_]: ConcurrentEffect: Timer, G[_]: SyncEffect]( + private def addCommand[F[_]: ConcurrentEffect, G[_]: SyncEffect]( implicit sessionReferenceRepository: KeyedDataRepository[Player, ActiveSessionReference[F, G]], factory: ActiveSessionFactory[F, Player] @@ -91,24 +92,22 @@ object BukkitFlyCommand { } yield TargetedEffect.emptyEffect } - def finishCommand[F[_]: ConcurrentEffect, G[_]]( + private def finishCommand[F[_]: ConcurrentEffect, G[_]]( implicit sessionReferenceRepository: KeyedDataRepository[Player, ActiveSessionReference[F, G]] ): ContextualExecutor = - BuilderTemplates.playerCommandBuilder.buildWithExecutionF { context => - for { - sessionStopped <- - sessionReferenceRepository(context.sender).stopAnyRunningSession - } yield { - if (sessionStopped) { - MessageEffect(s"${GREEN}fly効果を停止しました。") - } else { - MessageEffect(s"${GREEN}fly効果は現在OFFです。") - } + BuilderTemplates.playerCommandBuilder.buildWithExecutionCSEffect { context => + Kleisli.liftF(sessionReferenceRepository(context.sender).stopAnyRunningSession).flatMap { + sessionStopped => + if (sessionStopped) { + MessageEffectF(s"${GREEN}fly効果を停止しました。") + } else { + MessageEffectF(s"${GREEN}fly効果は現在OFFです。") + } } } - def executor[F[_]: ConcurrentEffect: Timer, G[_]: SyncEffect]( + def executor[F[_]: ConcurrentEffect, G[_]: SyncEffect]( implicit sessionReferenceRepository: KeyedDataRepository[Player, ActiveSessionReference[F, G]], factory: ActiveSessionFactory[F, Player] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/listeners/BukkitPlayerStatusChangeListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/listeners/BukkitPlayerStatusChangeListener.scala new file mode 100644 index 0000000000..0aae33467f --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/managedfly/bukkit/listeners/BukkitPlayerStatusChangeListener.scala @@ -0,0 +1,52 @@ +package com.github.unchama.seichiassist.subsystems.managedfly.bukkit.listeners + +import cats.data.Kleisli +import cats.effect.{ConcurrentEffect, SyncEffect, SyncIO} +import com.github.unchama.datarepository.KeyedDataRepository +import com.github.unchama.seichiassist.subsystems.managedfly.application.{ + ActiveSessionReference, + PlayerFlyStatusManipulation +} +import org.bukkit.entity.Player +import org.bukkit.event.player.{PlayerChangedWorldEvent, PlayerRespawnEvent} +import org.bukkit.event.{EventHandler, Listener} + +class BukkitPlayerStatusChangeListener[F[_]: ConcurrentEffect, G[_]: SyncEffect]( + implicit + sessionReferenceRepository: KeyedDataRepository[Player, ActiveSessionReference[F, G]], + playerFlyStatusManipulation: PlayerFlyStatusManipulation[Kleisli[F, Player, *]] +) extends Listener { + + import cats.effect.implicits._ + + @EventHandler + def onWorldChange(event: PlayerChangedWorldEvent): Unit = { + val player = event.getPlayer + + val program = for { + currentStatus <- sessionReferenceRepository(player) + .getLatestFlyStatus + .runSync[SyncIO] + .toIO + _ <- playerFlyStatusManipulation.synchronizeFlyStatus(currentStatus)(player).toIO + } yield () + + program.unsafeRunAsyncAndForget() + } + + @EventHandler + def onPlayerRespawn(event: PlayerRespawnEvent): Unit = { + val player = event.getPlayer + + val program = for { + currentStatus <- sessionReferenceRepository(player) + .getLatestFlyStatus + .runSync[SyncIO] + .toIO + _ <- playerFlyStatusManipulation.synchronizeFlyStatus(currentStatus)(player).toIO + } yield () + + program.unsafeRunAsyncAndForget() + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusAppearanceMaterialCodec.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusAppearanceMaterialCodec.scala index 937eb6606a..69e71cfff5 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusAppearanceMaterialCodec.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusAppearanceMaterialCodec.scala @@ -7,7 +7,7 @@ object BukkitMebiusAppearanceMaterialCodec { private val appearanceThresholds = List( 1 -> Material.LEATHER_HELMET, - 5 -> Material.GOLD_HELMET, + 5 -> Material.GOLDEN_HELMET, 10 -> Material.CHAINMAIL_HELMET, 20 -> Material.IRON_HELMET, 25 -> Material.DIAMOND_HELMET diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusItemStackCodec.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusItemStackCodec.scala index 226a5afa8e..e0295419e8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusItemStackCodec.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/codec/BukkitMebiusItemStackCodec.scala @@ -3,7 +3,7 @@ package com.github.unchama.seichiassist.subsystems.mebius.bukkit.codec import com.github.unchama.seichiassist.subsystems.mebius.domain.property._ import com.github.unchama.seichiassist.subsystems.mebius.domain.resources.MebiusTalks import com.github.unchama.seichiassist.subsystems.seasonalevents.christmas.ChristmasItemData -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Material import org.bukkit.entity.Player @@ -119,19 +119,19 @@ object BukkitMebiusItemStackCodec { * * を満足する。 */ - def materialize(property: MebiusProperty, damageValue: Short): ItemStack = { + def materialize(property: MebiusProperty): ItemStack = { val material = property.forcedMaterial match { case MebiusForcedMaterial.None => BukkitMebiusAppearanceMaterialCodec.appearanceMaterialAt(property.level) case MebiusForcedMaterial.Leather => Material.LEATHER_HELMET // 革のヘルメット case MebiusForcedMaterial.Iron => Material.IRON_HELMET // 鉄のヘルメット case MebiusForcedMaterial.Chain => Material.CHAINMAIL_HELMET // チェーンのヘルメット - case MebiusForcedMaterial.Gold => Material.GOLD_HELMET // 金のヘルメット + case MebiusForcedMaterial.Gold => Material.GOLDEN_HELMET // 金のヘルメット } import scala.util.chaining._ - val item = new ItemStack(material, 1, damageValue) + val item = new ItemStack(material, 1) item.setItemMeta { item.getItemMeta.tap { meta => diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/command/MebiusCommandExecutorProvider.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/command/MebiusCommandExecutorProvider.scala index e15664d7fc..49195bf506 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/command/MebiusCommandExecutorProvider.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/command/MebiusCommandExecutorProvider.scala @@ -64,8 +64,7 @@ class MebiusCommandExecutorProvider( SequentialEffect( UnfocusedEffect { player.getInventory.setHelmet { - BukkitMebiusItemStackCodec - .materialize(newProperty, damageValue = helmet.getDurability) + BukkitMebiusItemStackCodec.materialize(newProperty) } }, additionalEffectsOnModification(newProperty) @@ -117,7 +116,7 @@ class MebiusCommandExecutorProvider( if (property.level.isMaximum) { val newProperty = property.toggleForcedMaterial val newItem = - BukkitMebiusItemStackCodec.materialize(newProperty, mainHand.getDurability) + BukkitMebiusItemStackCodec.materialize(newProperty) val newMaterialName = newProperty.forcedMaterial match { case MebiusForcedMaterial.None => "ダイヤモンド" diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/gateway/BukkitMebiusSpeechGateway.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/gateway/BukkitMebiusSpeechGateway.scala index 8298ce99c5..778a3562d8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/gateway/BukkitMebiusSpeechGateway.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/gateway/BukkitMebiusSpeechGateway.scala @@ -44,13 +44,13 @@ class BukkitMebiusSpeechGateway(player: Player)(implicit timer: Timer[IO]) val effect = strength match { case MebiusSpeechStrength.Medium => playSoundsInSequence( - RepeatedEffect(3)(FocusedSoundEffect(Sound.BLOCK_NOTE_HARP, 2.0f, 1.0f)), - RepeatedEffect(3)(FocusedSoundEffect(Sound.BLOCK_NOTE_HARP, 2.0f, 1.5f)) + RepeatedEffect(3)(FocusedSoundEffect(Sound.BLOCK_NOTE_BLOCK_HARP, 2.0f, 1.0f)), + RepeatedEffect(3)(FocusedSoundEffect(Sound.BLOCK_NOTE_BLOCK_HARP, 2.0f, 1.5f)) ) case MebiusSpeechStrength.Loud => playSoundsInSequence( - RepeatedEffect(5)(FocusedSoundEffect(Sound.BLOCK_NOTE_HARP, 2.0f, 1.5f)), - RepeatedEffect(5)(FocusedSoundEffect(Sound.BLOCK_NOTE_HARP, 2.0f, 2.0f)) + RepeatedEffect(5)(FocusedSoundEffect(Sound.BLOCK_NOTE_BLOCK_HARP, 2.0f, 1.5f)), + RepeatedEffect(5)(FocusedSoundEffect(Sound.BLOCK_NOTE_BLOCK_HARP, 2.0f, 2.0f)) ) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusDropTrialListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusDropTrialListener.scala index 37b7facbca..6faf7eccae 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusDropTrialListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusDropTrialListener.scala @@ -51,7 +51,7 @@ class MebiusDropTrialListener[G[_]: ChristmasEventsAPI: RandomEffect: SyncEffect ) val mebius = - BukkitMebiusItemStackCodec.materialize(droppedMebiusProperty, damageValue = 0.toShort) + BukkitMebiusItemStackCodec.materialize(droppedMebiusProperty) player.sendMessage(s"$RESET$YELLOW${BOLD}おめでとうございます。採掘中にMEBIUSを発見しました。") player.sendMessage(s"$RESET$YELLOW${BOLD}MEBIUSはプレイヤーと共に成長するヘルメットです。") diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusInteractionResponder.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusInteractionResponder.scala index 1fdff31a1e..5bb0ad78db 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusInteractionResponder.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusInteractionResponder.scala @@ -21,6 +21,7 @@ import org.bukkit.event.block.BlockBreakEvent import org.bukkit.event.entity.{EntityDamageByEntityEvent, EntityDeathEvent} import org.bukkit.event.player.PlayerItemBreakEvent import org.bukkit.event.{EventHandler, EventPriority, Listener} +import org.bukkit.inventory.meta.Damageable class MebiusInteractionResponder( implicit serviceRepository: PlayerDataRepository[MebiusSpeechService[SyncIO]], @@ -40,32 +41,37 @@ class MebiusInteractionResponder( val speechService = serviceRepository(player) - val messageProgram = if (helmet.getDurability >= helmet.getType.getMaxDurability - 10) { - MebiusMessages.onDamageBreaking.pickOne[SyncIO].flatMap { message => - // 耐久閾値を超えていたら破損警告 - speechService.tryMakingSpeech( - mebiusProperty, - MebiusSpeech( - message.interpolate(mebiusProperty.ownerNickname), - MebiusSpeechStrength.Medium + val messageProgram = + if ( + helmet.getItemMeta.asInstanceOf[Damageable].getDamage >= helmet + .getType + .getMaxDurability - 10 + ) { + MebiusMessages.onDamageBreaking.pickOne[SyncIO].flatMap { message => + // 耐久閾値を超えていたら破損警告 + speechService.tryMakingSpeech( + mebiusProperty, + MebiusSpeech( + message.interpolate(mebiusProperty.ownerNickname), + MebiusSpeechStrength.Medium + ) ) - ) - } - } else - event.getDamager match { - case monster: Monster => - // モンスターからダメージを受けた場合の対モンスターメッセージ - MebiusMessages.onDamageWarnEnemy.pickOne[SyncIO].flatMap { message => - speechService.tryMakingSpeech( - mebiusProperty, - MebiusSpeech( - message.interpolate(mebiusProperty.ownerNickname, monster.getName), - MebiusSpeechStrength.Medium + } + } else + event.getDamager match { + case monster: Monster => + // モンスターからダメージを受けた場合の対モンスターメッセージ + MebiusMessages.onDamageWarnEnemy.pickOne[SyncIO].flatMap { message => + speechService.tryMakingSpeech( + mebiusProperty, + MebiusSpeech( + message.interpolate(mebiusProperty.ownerNickname, monster.getName), + MebiusSpeechStrength.Medium + ) ) - ) - } - case _ => SyncIO.unit - } + } + case _ => SyncIO.unit + } messageProgram.unsafeRunSync() case _ => @@ -98,7 +104,7 @@ class MebiusInteractionResponder( MessageEffect( s"${BukkitMebiusItemStackCodec.displayNameOfMaterializedItem(property)}${RESET}が旅立ちました。" ), - FocusedSoundEffect(Sound.ENTITY_ENDERDRAGON_DEATH, 1.0f, 0.1f) + FocusedSoundEffect(Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 0.1f) ).run(player) } ) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusLevelUpTrialListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusLevelUpTrialListener.scala index 1505585cb9..3dd1de4d2f 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusLevelUpTrialListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusLevelUpTrialListener.scala @@ -39,7 +39,7 @@ class MebiusLevelUpTrialListener( if (newMebiusProperty != oldMebiusProperty) { player.getInventory.setHelmet { - BukkitMebiusItemStackCodec.materialize(newMebiusProperty, damageValue = 0) + BukkitMebiusItemStackCodec.materialize(newMebiusProperty) } import cats.implicits._ diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusPlayerJoinGreeter.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusPlayerJoinGreeter.scala index 83f684de10..b22544bae9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusPlayerJoinGreeter.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/mebius/bukkit/listeners/MebiusPlayerJoinGreeter.scala @@ -1,6 +1,6 @@ package com.github.unchama.seichiassist.subsystems.mebius.bukkit.listeners -import cats.effect.{Effect, IO, SyncIO, Timer} +import cats.effect.{IO, SyncIO, Timer} import com.github.unchama.datarepository.bukkit.player.PlayerDataRepository import com.github.unchama.generic.effect.unsafe.EffectEnvironment import com.github.unchama.seichiassist.subsystems.mebius.bukkit.codec.BukkitMebiusItemStackCodec @@ -16,7 +16,7 @@ import org.bukkit.event.{EventHandler, EventPriority, Listener} import java.util.concurrent.TimeUnit import scala.concurrent.duration.FiniteDuration -class MebiusPlayerJoinGreeter[F[_]: Effect]( +class MebiusPlayerJoinGreeter[F[_]]( implicit effectEnvironment: EffectEnvironment, speechServiceRepository: PlayerDataRepository[MebiusSpeechService[SyncIO]], timer: Timer[IO] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackObjectList.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackObjectList.scala index 5700a0c451..44c872a438 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackObjectList.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackObjectList.scala @@ -6,6 +6,7 @@ import cats.effect.concurrent.Ref import com.github.unchama.minecraft.bukkit.algebra.CloneableBukkitItemStack._ import com.github.unchama.minecraft.objects.MinecraftMaterial import com.github.unchama.seichiassist.subsystems.gachaprize.GachaPrizeAPI +import com.github.unchama.seichiassist.subsystems.gachaprize.domain.CanBeSignedAsGachaPrize import com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobject.MineStackObject.{ MineStackObjectByItemStack, MineStackObjectByMaterial @@ -15,6 +16,8 @@ import com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobje import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.PotionMeta +import org.bukkit.potion.{PotionData, PotionType} class BukkitMineStackObjectList[F[_]: Sync]( implicit gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], @@ -29,567 +32,1081 @@ class BukkitMineStackObjectList[F[_]: Sync]( // 採掘可能ブロック private val minestacklistmine: List[MineStackObjectGroup[ItemStack]] = leftElems( - MineStackObjectByMaterial(ORES, "coal_ore", "石炭鉱石", Material.COAL_ORE, 0), - MineStackObjectByMaterial(ORES, "coal", "石炭", Material.COAL, 0), - MineStackObjectByMaterial(ORES, "coal_block", "石炭ブロック", Material.COAL_BLOCK, 0), - MineStackObjectByMaterial(ORES, "coal_1", "木炭", Material.COAL, 1), - MineStackObjectByMaterial(ORES, "iron_ore", "鉄鉱石", Material.IRON_ORE, 0), - MineStackObjectByMaterial(ORES, "iron_ingot", "鉄インゴット", Material.IRON_INGOT, 0), - MineStackObjectByMaterial(ORES, "iron_block", "鉄ブロック", Material.IRON_BLOCK, 0), - MineStackObjectByMaterial(ORES, "quartz_ore", "ネザー水晶鉱石", Material.QUARTZ_ORE, 0), - MineStackObjectByMaterial(ORES, "quartz", "ネザー水晶", Material.QUARTZ, 0), - MineStackObjectByMaterial(ORES, "gold_ore", "金鉱石", Material.GOLD_ORE, 0), - MineStackObjectByMaterial(ORES, "gold_ingot", "金インゴット", Material.GOLD_INGOT, 0), - MineStackObjectByMaterial(ORES, "gold_block", "金ブロック", Material.GOLD_BLOCK, 0), - MineStackObjectByMaterial(ORES, "redstone_ore", "レッドストーン鉱石", Material.REDSTONE_ORE, 0), - MineStackObjectByMaterial(ORES, "lapis_ore", "ラピスラズリ鉱石", Material.LAPIS_ORE, 0), - MineStackObjectByMaterial(ORES, "lapis_lazuli", "ラピスラズリ", Material.INK_SACK, 4), - MineStackObjectByMaterial(ORES, "lapis_block", "ラピスラズリブロック", Material.LAPIS_BLOCK, 0), - MineStackObjectByMaterial(ORES, "diamond_ore", "ダイヤモンド鉱石", Material.DIAMOND_ORE, 0), - MineStackObjectByMaterial(ORES, "diamond", "ダイヤモンド", Material.DIAMOND, 0), - MineStackObjectByMaterial(ORES, "diamond_block", "ダイヤモンドブロック", Material.DIAMOND_BLOCK, 0), - MineStackObjectByMaterial(ORES, "emerald_ore", "エメラルド鉱石", Material.EMERALD_ORE, 0), - MineStackObjectByMaterial(ORES, "emerald", "エメラルド", Material.EMERALD, 0), - MineStackObjectByMaterial(ORES, "emerald_block", "エメラルドブロック", Material.EMERALD_BLOCK, 0) + MineStackObjectByMaterial(ORES, "coal_ore", "石炭鉱石", Material.COAL_ORE), + MineStackObjectByMaterial(ORES, "coal", "石炭", Material.COAL), + MineStackObjectByMaterial(ORES, "coal_block", "石炭ブロック", Material.COAL_BLOCK), + MineStackObjectByMaterial(ORES, "coal_1", "木炭", Material.CHARCOAL), + MineStackObjectByMaterial(ORES, "iron_ore", "鉄鉱石", Material.IRON_ORE), + MineStackObjectByMaterial(ORES, "iron_ingot", "鉄インゴット", Material.IRON_INGOT), + MineStackObjectByMaterial(ORES, "iron_block", "鉄ブロック", Material.IRON_BLOCK), + MineStackObjectByMaterial(ORES, "quartz_ore", "ネザークォーツ鉱石", Material.NETHER_QUARTZ_ORE), + MineStackObjectByMaterial(ORES, "quartz", "ネザークォーツ", Material.QUARTZ), + MineStackObjectByMaterial(ORES, "gold_ore", "金鉱石", Material.GOLD_ORE), + MineStackObjectByMaterial(ORES, "gold_ingot", "金インゴット", Material.GOLD_INGOT), + MineStackObjectByMaterial(ORES, "gold_block", "金ブロック", Material.GOLD_BLOCK), + MineStackObjectByMaterial(ORES, "redstone_ore", "レッドストーン鉱石", Material.REDSTONE_ORE), + MineStackObjectByMaterial(ORES, "lapis_ore", "ラピスラズリ鉱石", Material.LAPIS_ORE), + MineStackObjectByMaterial(ORES, "lapis_lazuli", "ラピスラズリ", Material.LAPIS_LAZULI), + MineStackObjectByMaterial(ORES, "lapis_block", "ラピスラズリブロック", Material.LAPIS_BLOCK), + MineStackObjectByMaterial(ORES, "diamond_ore", "ダイヤモンド鉱石", Material.DIAMOND_ORE), + MineStackObjectByMaterial(ORES, "diamond", "ダイヤモンド", Material.DIAMOND), + MineStackObjectByMaterial(ORES, "diamond_block", "ダイヤモンドブロック", Material.DIAMOND_BLOCK), + MineStackObjectByMaterial(ORES, "emerald_ore", "エメラルド鉱石", Material.EMERALD_ORE), + MineStackObjectByMaterial(ORES, "emerald", "エメラルド", Material.EMERALD), + MineStackObjectByMaterial(ORES, "emerald_block", "エメラルドブロック", Material.EMERALD_BLOCK), + MineStackObjectByMaterial(ORES, "copper_ore", "銅鉱石", Material.COPPER_ORE), + MineStackObjectByMaterial(ORES, "copper_ingot", "銅インゴット", Material.COPPER_INGOT), + MineStackObjectByMaterial(ORES, "copper_block", "銅ブロック", Material.COPPER_BLOCK), + MineStackObjectByMaterial(ORES, "deepslate_coal_ore", "深層石炭鉱石", Material.DEEPSLATE_COAL_ORE), + MineStackObjectByMaterial(ORES, "deepslate_iron_ore", "深層鉄鉱石", Material.DEEPSLATE_IRON_ORE), + MineStackObjectByMaterial(ORES, "deepslate_gold_ore", "深層金鉱石", Material.DEEPSLATE_GOLD_ORE), + MineStackObjectByMaterial(ORES, "deepslate_redstone_ore", "深層レッドストーン鉱石", Material.DEEPSLATE_REDSTONE_ORE), + MineStackObjectByMaterial(ORES, "deepslate_emerald_ore", "深層エメラルド鉱石", Material.DEEPSLATE_EMERALD_ORE), + MineStackObjectByMaterial(ORES, "deepslate_lapis_ore", "深層ラピスラズリ鉱石", Material.DEEPSLATE_LAPIS_ORE), + MineStackObjectByMaterial(ORES, "deepslate_diamond_ore", "深層ダイヤモンド鉱石", Material.DEEPSLATE_DIAMOND_ORE), + MineStackObjectByMaterial(ORES, "deepslate_copper_ore", "深層銅鉱石", Material.DEEPSLATE_COPPER_ORE), + MineStackObjectByMaterial(ORES, "nether_gold_ore", "ネザー金鉱石", Material.NETHER_GOLD_ORE), + MineStackObjectByMaterial(ORES, "ancient_debris", "古代の残骸", Material.ANCIENT_DEBRIS), + MineStackObjectByMaterial(ORES, "raw_copper_block", "銅の原石ブロック", Material.RAW_COPPER_BLOCK), + MineStackObjectByMaterial(ORES, "raw_iron_block", "鉄の原石ブロック", Material.RAW_IRON_BLOCK), + MineStackObjectByMaterial(ORES, "raw_gold_block", "金の原石ブロック", Material.RAW_GOLD_BLOCK), + MineStackObjectByMaterial(ORES, "amethyst_block", "アメジストブロック", Material.AMETHYST_BLOCK), + MineStackObjectByMaterial(ORES, "budding_amethyst", "芽生えたアメジスト", Material.BUDDING_AMETHYST), + MineStackObjectByMaterial(ORES, "netherite_block", "ネザライトブロック", Material.NETHERITE_BLOCK), + MineStackObjectByMaterial(ORES, "amethyst_shard", "アメジストの欠片", Material.AMETHYST_SHARD), + MineStackObjectByMaterial(ORES, "raw_copper", "銅の原石", Material.RAW_COPPER), + MineStackObjectByMaterial(ORES, "raw_iron", "鉄の原石", Material.RAW_IRON), + MineStackObjectByMaterial(ORES, "raw_gold", "金の原石", Material.RAW_GOLD), + MineStackObjectByMaterial(ORES, "netherite_ingot", "ネザライトインゴット", Material.NETHERITE_INGOT), + MineStackObjectByMaterial(ORES, "netherite_scrap", "ネザライトの欠片", Material.NETHERITE_SCRAP), + MineStackObjectByMaterial(ORES, "small_amethyst_bud", "小さなアメジストの芽", Material.SMALL_AMETHYST_BUD), + MineStackObjectByMaterial(ORES, "medium_amethyst_bud", "中くらいのアメジストの芽", Material.MEDIUM_AMETHYST_BUD), + MineStackObjectByMaterial(ORES, "large_amethyst_bud", "大きなアメジストの芽", Material.LARGE_AMETHYST_BUD), + MineStackObjectByMaterial(ORES, "amethyst_cluster", "アメジストの塊", Material.AMETHYST_CLUSTER), + MineStackObjectByMaterial(ORES, "iron_nugget", "鉄塊", Material.IRON_NUGGET), + MineStackObjectByMaterial(ORES, "waxed_copper_block", "錆止めされた銅ブロック", Material.WAXED_COPPER_BLOCK), + MineStackObjectByMaterial(ORES, "waxed_exposed_copper", "錆止めされた風化した銅", Material.WAXED_EXPOSED_COPPER), + MineStackObjectByMaterial(ORES, "waxed_weathered_copper", "錆止めされた錆びた銅", Material.WAXED_WEATHERED_COPPER), + MineStackObjectByMaterial(ORES, "waxed_oxidized_copper", "錆止めされた酸化した銅", Material.WAXED_OXIDIZED_COPPER), + MineStackObjectByMaterial(ORES, "waxed_cut_copper", "錆止めされた切り込み入りの銅", Material.WAXED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "waxed_exposed_cut_copper", "錆止めされた風化した切り込み入りの銅", Material.WAXED_EXPOSED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "waxed_weathered_cut_copper", "錆止めされた錆びた切り込み入りの銅", Material.WAXED_WEATHERED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "waxed_oxidized_cut_copper", "錆止めされた酸化した切り込み入りの銅", Material.WAXED_OXIDIZED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "exposed_copper", "風化した銅", Material.EXPOSED_COPPER), + MineStackObjectByMaterial(ORES, "weathered_copper", "錆びた銅", Material.WEATHERED_COPPER), + MineStackObjectByMaterial(ORES, "oxidized_copper", "酸化した銅", Material.OXIDIZED_COPPER), + MineStackObjectByMaterial(ORES, "cut_copper", "切り込み入りの銅", Material.CUT_COPPER), + MineStackObjectByMaterial(ORES, "exposed_cut_copper", "風化した切り込み入りの銅", Material.EXPOSED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "weathered_cut_copper", "錆びた切り込み入りの銅", Material.WEATHERED_CUT_COPPER), + MineStackObjectByMaterial(ORES, "oxidized_cut_copper", "酸化した切り込み入りの銅", Material.OXIDIZED_CUT_COPPER), ) + import scala.util.chaining._ + // モンスター+動物ドロップ - private val minestacklistdrop: List[Either[MineStackObject[ItemStack], MineStackObjectWithColorVariants[ItemStack]]] = leftElems( - MineStackObjectByMaterial(MOB_DROP, "ender_pearl", "エンダーパール", Material.ENDER_PEARL, 0), - MineStackObjectByMaterial(MOB_DROP, "ender_eye", "エンダーアイ", Material.EYE_OF_ENDER, 0), - MineStackObjectByMaterial(MOB_DROP, "slime_ball", "スライムボール", Material.SLIME_BALL, 0), - MineStackObjectByMaterial(MOB_DROP, "slime", "スライムブロック", Material.SLIME_BLOCK, 0), - MineStackObjectByMaterial(MOB_DROP, "rotten_flesh", "腐った肉", Material.ROTTEN_FLESH, 0), - MineStackObjectByMaterial(MOB_DROP, "bone", "骨", Material.BONE, 0), - MineStackObjectByMaterial(MOB_DROP, "sulphur", "火薬", Material.SULPHUR, 0), - MineStackObjectByMaterial(MOB_DROP, "arrow", "矢", Material.ARROW, 0), - MineStackObjectByMaterial(MOB_DROP, "tipped_arrow", "鈍化の矢", Material.TIPPED_ARROW, 0), - MineStackObjectByMaterial(MOB_DROP, "spider_eye", "蜘蛛の目", Material.SPIDER_EYE, 0), - MineStackObjectByMaterial(MOB_DROP, "string", "糸", Material.STRING, 0), - MineStackObjectByMaterial(MOB_DROP, "name_tag", "名札", Material.NAME_TAG, 0), - MineStackObjectByMaterial(MOB_DROP, "lead", "リード", Material.LEASH, 0), - MineStackObjectByMaterial(MOB_DROP, "glass_bottle", "ガラス瓶", Material.GLASS_BOTTLE, 0), - MineStackObjectByMaterial(MOB_DROP, "gold_nugget", "金塊", Material.GOLD_NUGGET, 0), - MineStackObjectByMaterial(MOB_DROP, "blaze_rod", "ブレイズロッド", Material.BLAZE_ROD, 0), - MineStackObjectByMaterial(MOB_DROP, "blaze_powder", "ブレイズパウダー", Material.BLAZE_POWDER, 0), - MineStackObjectByMaterial(MOB_DROP, "ghast_tear", "ガストの涙", Material.GHAST_TEAR, 0), - MineStackObjectByMaterial(MOB_DROP, "magma_cream", "マグマクリーム", Material.MAGMA_CREAM, 0), - MineStackObjectByMaterial(MOB_DROP, "prismarine_shard", "プリズマリンの欠片", Material.PRISMARINE_SHARD, 0), - MineStackObjectByMaterial(MOB_DROP, "prismarine_crystals", "プリズマリンクリスタル", Material.PRISMARINE_CRYSTALS, 0), - MineStackObjectByMaterial(MOB_DROP, "feather", "羽", Material.FEATHER, 0), - MineStackObjectByMaterial(MOB_DROP, "leather", "革", Material.LEATHER, 0), - MineStackObjectByMaterial(MOB_DROP, "rabbit_hide", "ウサギの皮", Material.RABBIT_HIDE, 0), - MineStackObjectByMaterial(MOB_DROP, "rabbit_foot", "ウサギの足", Material.RABBIT_FOOT, 0), - MineStackObjectByMaterial(MOB_DROP, "dragon_egg", "エンドラの卵", Material.DRAGON_EGG, 0), - MineStackObjectByMaterial(MOB_DROP, "shulker_shell", "シュルカーの殻", Material.SHULKER_SHELL, 0), - MineStackObjectByMaterial(MOB_DROP, "totem_of_undying", "不死のトーテム", Material.TOTEM, 0), - MineStackObjectByMaterial(MOB_DROP, "dragon_head", "エンダードラゴンの頭", Material.SKULL_ITEM, 5), - MineStackObjectByMaterial(MOB_DROP, "wither_skeleton_skull", "ウィザースケルトンの頭", Material.SKULL_ITEM, 1), - MineStackObjectByMaterial(MOB_DROP, "stick", "棒", Material.STICK, 0) + private val minestacklistdrop: List[MineStackObjectGroup[ItemStack]] = leftElems( + MineStackObjectByMaterial(MOB_DROP, "ender_pearl", "エンダーパール", Material.ENDER_PEARL), + MineStackObjectByMaterial(MOB_DROP, "ender_eye", "エンダーアイ", Material.ENDER_EYE), + MineStackObjectByMaterial(MOB_DROP, "slime_ball", "スライムボール", Material.SLIME_BALL), + MineStackObjectByMaterial(MOB_DROP, "slime", "スライムブロック", Material.SLIME_BLOCK), + MineStackObjectByMaterial(MOB_DROP, "rotten_flesh", "腐った肉", Material.ROTTEN_FLESH), + MineStackObjectByMaterial(MOB_DROP, "bone", "骨", Material.BONE), + MineStackObjectByMaterial(MOB_DROP, "sulphur", "火薬", Material.GUNPOWDER), + MineStackObjectByMaterial(MOB_DROP, "arrow", "矢", Material.ARROW), + MineStackObjectByMaterial(MOB_DROP, "spider_eye", "クモの目", Material.SPIDER_EYE), + MineStackObjectByItemStack(MOB_DROP, "tipped_arrow", Some("鈍化の矢"), hasNameLore = false, new ItemStack(Material.TIPPED_ARROW).tap { itemStack => + val meta = itemStack.getItemMeta.asInstanceOf[PotionMeta] + meta.setBasePotionData(new PotionData(PotionType.SLOWNESS)) + itemStack.setItemMeta(meta) + }), + MineStackObjectByMaterial(MOB_DROP, "string", "糸", Material.STRING), + MineStackObjectByMaterial(MOB_DROP, "name_tag", "名札", Material.NAME_TAG), + MineStackObjectByMaterial(MOB_DROP, "lead", "リード", Material.LEAD), + MineStackObjectByMaterial(MOB_DROP, "glass_bottle", "ガラス瓶", Material.GLASS_BOTTLE), + MineStackObjectByMaterial(MOB_DROP, "gold_nugget", "金塊", Material.GOLD_NUGGET), + MineStackObjectByMaterial(MOB_DROP, "blaze_rod", "ブレイズロッド", Material.BLAZE_ROD), + MineStackObjectByMaterial(MOB_DROP, "blaze_powder", "ブレイズパウダー", Material.BLAZE_POWDER), + MineStackObjectByMaterial(MOB_DROP, "ghast_tear", "ガストの涙", Material.GHAST_TEAR), + MineStackObjectByMaterial(MOB_DROP, "magma_cream", "マグマクリーム", Material.MAGMA_CREAM), + MineStackObjectByMaterial(MOB_DROP, "prismarine_shard", "プリズマリンの欠片", Material.PRISMARINE_SHARD), + MineStackObjectByMaterial(MOB_DROP, "prismarine_crystals", "プリズマリンクリスタル", Material.PRISMARINE_CRYSTALS), + MineStackObjectByMaterial(MOB_DROP, "feather", "羽根", Material.FEATHER), + MineStackObjectByMaterial(MOB_DROP, "leather", "革", Material.LEATHER), + MineStackObjectByMaterial(MOB_DROP, "rabbit_hide", "ウサギの皮", Material.RABBIT_HIDE), + MineStackObjectByMaterial(MOB_DROP, "rabbit_foot", "ウサギの足", Material.RABBIT_FOOT), + MineStackObjectByMaterial(MOB_DROP, "dragon_egg", "ドラゴンの卵", Material.DRAGON_EGG), + MineStackObjectByMaterial(MOB_DROP, "shulker_shell", "シュルカーの殻", Material.SHULKER_SHELL), + MineStackObjectByMaterial(MOB_DROP, "totem_of_undying", "不死のトーテム", Material.TOTEM_OF_UNDYING), + MineStackObjectByMaterial(MOB_DROP, "dragon_head", "ドラゴンの頭", Material.DRAGON_HEAD), + MineStackObjectByMaterial(MOB_DROP, "wither_skeleton_skull", "ウィザースケルトンの頭", Material.WITHER_SKELETON_SKULL), + MineStackObjectByMaterial(MOB_DROP, "stick", "棒", Material.STICK), + MineStackObjectByMaterial(MOB_DROP, "scute", "カメのウロコ", Material.SCUTE), + MineStackObjectByMaterial(MOB_DROP, "fermented_spider_eye", "発酵したクモの目", Material.FERMENTED_SPIDER_EYE), + MineStackObjectByMaterial(MOB_DROP, "golden_carrot", "金のニンジン", Material.GOLDEN_CARROT), + MineStackObjectByMaterial(MOB_DROP, "skeleton_skull", "スケルトンの頭蓋骨", Material.SKELETON_SKULL), + MineStackObjectByMaterial(MOB_DROP, "zombie_head", "ゾンビの頭", Material.ZOMBIE_HEAD), + MineStackObjectByMaterial(MOB_DROP, "creeper_head", "クリーパーの頭", Material.CREEPER_HEAD), + MineStackObjectByMaterial(MOB_DROP, "nether_star", "ネザースター", Material.NETHER_STAR), + MineStackObjectByMaterial(MOB_DROP, "dragon_breath", "ドラゴンブレス", Material.DRAGON_BREATH), + MineStackObjectByMaterial(MOB_DROP, "phantom_membrane", "ファントムの皮膜", Material.PHANTOM_MEMBRANE), + MineStackObjectByMaterial(MOB_DROP, "nautilus_shell", "オウムガイの殻", Material.NAUTILUS_SHELL), + MineStackObjectByMaterial(MOB_DROP, "heart_of_the_sea", "海洋の心", Material.HEART_OF_THE_SEA), + ) ++ rightElems( + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(MOB_DROP, "music_disc_otherside", "レコード", Material.MUSIC_DISC_OTHERSIDE), + List( + MineStackObjectByMaterial(MOB_DROP, "music_disc_pigstep", "レコード", Material.MUSIC_DISC_PIGSTEP), + MineStackObjectByMaterial(MOB_DROP,"record_13","レコード",Material.MUSIC_DISC_13), + MineStackObjectByMaterial(MOB_DROP,"record_cat","レコード",Material.MUSIC_DISC_CAT), + MineStackObjectByMaterial(MOB_DROP,"record_blocks","レコード",Material.MUSIC_DISC_BLOCKS), + MineStackObjectByMaterial(MOB_DROP,"record_chirp","レコード",Material.MUSIC_DISC_CHIRP), + MineStackObjectByMaterial(MOB_DROP,"record_far","レコード",Material.MUSIC_DISC_FAR), + MineStackObjectByMaterial(MOB_DROP,"record_mall","レコード",Material.MUSIC_DISC_MALL), + MineStackObjectByMaterial(MOB_DROP,"record_mellohi","レコード",Material.MUSIC_DISC_MELLOHI), + MineStackObjectByMaterial(MOB_DROP,"record_stal","レコード",Material.MUSIC_DISC_STAL), + MineStackObjectByMaterial(MOB_DROP,"record_strad","レコード",Material.MUSIC_DISC_STRAD), + MineStackObjectByMaterial(MOB_DROP,"record_ward","レコード",Material.MUSIC_DISC_WARD), + MineStackObjectByMaterial(MOB_DROP,"record_11","レコード",Material.MUSIC_DISC_11), + MineStackObjectByMaterial(MOB_DROP,"record_wait","レコード",Material.MUSIC_DISC_WAIT), + ) + ) ) // 採掘で入手可能な農業系ブロック private val minestacklistfarm: List[MineStackObjectGroup[ItemStack]] = leftElems( - MineStackObjectByMaterial(AGRICULTURAL, "seeds", "種", Material.SEEDS, 0), - MineStackObjectByMaterial(AGRICULTURAL, "apple", "リンゴ", Material.APPLE, 0), - MineStackObjectByMaterial(AGRICULTURAL, "long_grass1", "草", Material.LONG_GRASS, 1), - MineStackObjectByMaterial(AGRICULTURAL, "long_grass2", "シダ", Material.LONG_GRASS, 2), - MineStackObjectByMaterial(AGRICULTURAL, "dead_bush", "枯れ木", Material.DEAD_BUSH, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cactus", "サボテン", Material.CACTUS, 0), - MineStackObjectByMaterial(AGRICULTURAL, "vine", "ツタ", Material.VINE, 0), - MineStackObjectByMaterial(AGRICULTURAL, "water_lily", "スイレンの葉", Material.WATER_LILY, 0), - MineStackObjectByMaterial(AGRICULTURAL, "yellow_flower", "タンポポ", Material.YELLOW_FLOWER, 0), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose0", "ポピー", Material.RED_ROSE, 0), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose1", "ヒスイラン", Material.RED_ROSE, 1), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose2", "アリウム", Material.RED_ROSE, 2), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose3", "ヒナソウ", Material.RED_ROSE, 3), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose4", "赤色のチューリップ", Material.RED_ROSE, 4), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose5", "橙色のチューリップ", Material.RED_ROSE, 5), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose6", "白色のチューリップ", Material.RED_ROSE, 6), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose7", "桃色のチューリップ", Material.RED_ROSE, 7), - MineStackObjectByMaterial(AGRICULTURAL, "red_rose8", "フランスギク", Material.RED_ROSE, 8), - MineStackObjectByMaterial(AGRICULTURAL, "leaves", "オークの葉", Material.LEAVES, 0), - MineStackObjectByMaterial(AGRICULTURAL, "leaves1", "マツの葉", Material.LEAVES, 1), - MineStackObjectByMaterial(AGRICULTURAL, "leaves2", "シラカバの葉", Material.LEAVES, 2), - MineStackObjectByMaterial(AGRICULTURAL, "leaves3", "ジャングルの葉", Material.LEAVES, 3), - MineStackObjectByMaterial(AGRICULTURAL, "leaves_2", "アカシアの葉", Material.LEAVES_2, 0), - MineStackObjectByMaterial(AGRICULTURAL, "leaves_21", "ダークオークの葉", Material.LEAVES_2, 1), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant0", "ヒマワリ", Material.DOUBLE_PLANT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant1", "ライラック", Material.DOUBLE_PLANT, 1), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant2", "高い草", Material.DOUBLE_PLANT, 2), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant3", "大きなシダ", Material.DOUBLE_PLANT, 3), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant4", "バラの低木", Material.DOUBLE_PLANT, 4), - MineStackObjectByMaterial(AGRICULTURAL, "double_plant5", "ボタン", Material.DOUBLE_PLANT, 5), - MineStackObjectByMaterial(AGRICULTURAL, "sugar_cane", "サトウキビ", Material.SUGAR_CANE, 0), - MineStackObjectByMaterial(AGRICULTURAL, "pumpkin", "カボチャ", Material.PUMPKIN, 0), - MineStackObjectByMaterial(AGRICULTURAL, "ink_sack3", "カカオ豆", Material.INK_SACK, 3), - MineStackObjectByMaterial(AGRICULTURAL, "huge_mushroom_1", "キノコ", Material.HUGE_MUSHROOM_1, 0), - MineStackObjectByMaterial(AGRICULTURAL, "huge_mushroom_2", "キノコ", Material.HUGE_MUSHROOM_2, 0), - MineStackObjectByMaterial(AGRICULTURAL, "melon", "スイカ", Material.MELON, 0), - MineStackObjectByMaterial(AGRICULTURAL, "melon_block", "スイカ", Material.MELON_BLOCK, 0), - MineStackObjectByMaterial(AGRICULTURAL, "brown_mushroom", "キノコ", Material.BROWN_MUSHROOM, 0), - MineStackObjectByMaterial(AGRICULTURAL, "red_mushroom", "キノコ", Material.RED_MUSHROOM, 0), - MineStackObjectByMaterial(AGRICULTURAL, "sapling", "オークの苗木", Material.SAPLING, 0), - MineStackObjectByMaterial(AGRICULTURAL, "sapling1", "マツの苗木", Material.SAPLING, 1), - MineStackObjectByMaterial(AGRICULTURAL, "sapling2", "シラカバの苗木", Material.SAPLING, 2), - MineStackObjectByMaterial(AGRICULTURAL, "sapling3", "ジャングルの苗木", Material.SAPLING, 3), - MineStackObjectByMaterial(AGRICULTURAL, "sapling4", "アカシアの苗木", Material.SAPLING, 4), - MineStackObjectByMaterial(AGRICULTURAL, "sapling5", "ダークオークの苗木", Material.SAPLING, 5), - MineStackObjectByMaterial(AGRICULTURAL, "beetroot", "ビートルート", Material.BEETROOT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "beetroot_seeds", "ビートルートの種", Material.BEETROOT_SEEDS, 0), - MineStackObjectByMaterial(AGRICULTURAL, "carrot_item", "ニンジン", Material.CARROT_ITEM, 0), - MineStackObjectByMaterial(AGRICULTURAL, "potato_item", "ジャガイモ", Material.POTATO_ITEM, 0), - MineStackObjectByMaterial(AGRICULTURAL, "poisonous_potato", "青くなったジャガイモ", Material.POISONOUS_POTATO, 0), - MineStackObjectByMaterial(AGRICULTURAL, "wheat", "小麦", Material.WHEAT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "pumpkin_seeds", "カボチャの種", Material.PUMPKIN_SEEDS, 0), - MineStackObjectByMaterial(AGRICULTURAL, "melon_seeds", "スイカの種", Material.MELON_SEEDS, 0), - MineStackObjectByMaterial(AGRICULTURAL, "nether_stalk", "ネザーウォート", Material.NETHER_STALK, 0), - MineStackObjectByMaterial(AGRICULTURAL, "chorus_fruit", "コーラスフルーツ", Material.CHORUS_FRUIT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "chorus_flower", "コーラスフラワー", Material.CHORUS_FLOWER, 0), - MineStackObjectByMaterial(AGRICULTURAL, "popped_chorus_fruit", "焼いたコーラスフルーツ", Material.CHORUS_FRUIT_POPPED, 0), - MineStackObjectByMaterial(AGRICULTURAL, "egg", "卵", Material.EGG, 0), - MineStackObjectByMaterial(AGRICULTURAL, "pork", "生の豚肉", Material.PORK, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_porkchop", "焼き豚", Material.GRILLED_PORK, 0), - MineStackObjectByMaterial(AGRICULTURAL, "raw_chicken", "生の鶏肉", Material.RAW_CHICKEN, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_chicken", "焼き鳥", Material.COOKED_CHICKEN, 0), - MineStackObjectByMaterial(AGRICULTURAL, "mutton", "生の羊肉", Material.MUTTON, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_mutton", "焼いた羊肉", Material.COOKED_MUTTON, 0), - MineStackObjectByMaterial(AGRICULTURAL, "raw_beef", "生の牛肉", Material.RAW_BEEF, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_beaf", "ステーキ", Material.COOKED_BEEF, 0), - MineStackObjectByMaterial(AGRICULTURAL, "rabbit", "生の兎肉", Material.RABBIT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_rabbit", "焼き兎肉", Material.COOKED_RABBIT, 0), - MineStackObjectByMaterial(AGRICULTURAL, "raw_fish0", "生魚", Material.RAW_FISH, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_fish0", "焼き魚", Material.COOKED_FISH, 0), - MineStackObjectByMaterial(AGRICULTURAL, "raw_fish1", "生鮭", Material.RAW_FISH, 1), - MineStackObjectByMaterial(AGRICULTURAL, "cooked_fish1", "焼き鮭", Material.COOKED_FISH, 1), - MineStackObjectByMaterial(AGRICULTURAL, "raw_fish2", "クマノミ", Material.RAW_FISH, 2), - MineStackObjectByMaterial(AGRICULTURAL, "raw_fish3", "フグ", Material.RAW_FISH, 3), - MineStackObjectByMaterial(AGRICULTURAL, "bread", "パン", Material.BREAD, 0), - MineStackObjectByMaterial(AGRICULTURAL, "sugar", "砂糖", Material.SUGAR, 0), - MineStackObjectByMaterial(AGRICULTURAL, "baked_potato", "ベイクドポテト", Material.BAKED_POTATO, 0), - MineStackObjectByMaterial(AGRICULTURAL, "cake", "ケーキ", Material.CAKE, 0), - MineStackObjectByMaterial(AGRICULTURAL, "mushroom_stew", "キノコシチュー", Material.MUSHROOM_SOUP, 0), - MineStackObjectByMaterial(AGRICULTURAL, "rabbit_stew", "ウサギシチュー", Material.RABBIT_STEW, 0), - MineStackObjectByMaterial(AGRICULTURAL, "beetroot_soup", "ビートルートスープ", Material.BEETROOT_SOUP, 0), - MineStackObjectByMaterial(AGRICULTURAL, "bowl", "ボウル", Material.BOWL, 0), - MineStackObjectByMaterial(AGRICULTURAL, "milk_bucket", "牛乳", Material.MILK_BUCKET, 0) + MineStackObjectByMaterial(AGRICULTURAL, "seeds", "小麦の種", Material.WHEAT_SEEDS), + MineStackObjectByMaterial(AGRICULTURAL, "apple", "リンゴ", Material.APPLE), + MineStackObjectByMaterial(AGRICULTURAL, "long_grass2", "シダ", Material.FERN), + MineStackObjectByMaterial(AGRICULTURAL, "dead_bush", "枯れ木", Material.DEAD_BUSH), + MineStackObjectByMaterial(AGRICULTURAL, "cactus", "サボテン", Material.CACTUS), + MineStackObjectByMaterial(AGRICULTURAL, "vine", "ツタ", Material.VINE), + MineStackObjectByMaterial(AGRICULTURAL, "water_lily", "スイレンの葉", Material.LILY_PAD), + MineStackObjectByMaterial(AGRICULTURAL, "yellow_flower", "タンポポ", Material.DANDELION), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose0", "ポピー", Material.POPPY), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose1", "ヒスイラン", Material.BLUE_ORCHID), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose2", "アリウム", Material.ALLIUM), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose3", "ヒナソウ", Material.AZURE_BLUET), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose4", "赤色のチューリップ", Material.RED_TULIP), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose5", "橙色のチューリップ", Material.ORANGE_TULIP), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose6", "白色のチューリップ", Material.WHITE_TULIP), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose7", "桃色のチューリップ", Material.PINK_TULIP), + MineStackObjectByMaterial(AGRICULTURAL, "red_rose8", "フランスギク", Material.OXEYE_DAISY), + MineStackObjectByMaterial(AGRICULTURAL, "leaves", "オークの葉", Material.OAK_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "leaves1", "トウヒの葉", Material.SPRUCE_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "leaves2", "シラカバの葉", Material.BIRCH_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "leaves3", "ジャングルの葉", Material.JUNGLE_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "leaves_2", "アカシアの葉", Material.ACACIA_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "leaves_21", "ダークオークの葉", Material.DARK_OAK_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant0", "ヒマワリ", Material.SUNFLOWER), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant1", "ライラック", Material.LILAC), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant2", "背の高い草", Material.TALL_GRASS), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant3", "大きなシダ", Material.LARGE_FERN), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant4", "バラの低木", Material.ROSE_BUSH), + MineStackObjectByMaterial(AGRICULTURAL, "double_plant5", "ボタン", Material.PEONY), + MineStackObjectByMaterial(AGRICULTURAL, "sugar_cane", "サトウキビ", Material.SUGAR_CANE), + MineStackObjectByMaterial(AGRICULTURAL, "pumpkin", "カボチャ", Material.PUMPKIN), + MineStackObjectByMaterial(AGRICULTURAL, "ink_sack3", "カカオ豆", Material.COCOA_BEANS), + MineStackObjectByMaterial(AGRICULTURAL, "huge_mushroom_1", "赤色のキノコ", Material.BROWN_MUSHROOM), + MineStackObjectByMaterial(AGRICULTURAL, "huge_mushroom_2", "茶色のキノコ", Material.RED_MUSHROOM), + MineStackObjectByMaterial(AGRICULTURAL, "melon", "スイカの薄切り", Material.MELON_SLICE), + MineStackObjectByMaterial(AGRICULTURAL, "melon_block", "スイカ", Material.MELON), + MineStackObjectByMaterial(AGRICULTURAL, "sapling", "オークの苗木", Material.OAK_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "sapling1", "トウヒの苗木", Material.SPRUCE_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "sapling2", "シラカバの苗木", Material.BIRCH_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "sapling3", "ジャングルの苗木", Material.JUNGLE_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "sapling4", "アカシアの苗木", Material.ACACIA_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "sapling5", "ダークオークの苗木", Material.DARK_OAK_SAPLING), + MineStackObjectByMaterial(AGRICULTURAL, "beetroot", "ビートルート", Material.BEETROOT), + MineStackObjectByMaterial(AGRICULTURAL, "beetroot_seeds", "ビートルートの種", Material.BEETROOT_SEEDS), + MineStackObjectByMaterial(AGRICULTURAL, "carrot_item", "ニンジン", Material.CARROT), + MineStackObjectByMaterial(AGRICULTURAL, "potato_item", "ジャガイモ", Material.POTATO), + MineStackObjectByMaterial(AGRICULTURAL, "poisonous_potato", "青くなったジャガイモ", Material.POISONOUS_POTATO), + MineStackObjectByMaterial(AGRICULTURAL, "wheat", "小麦", Material.WHEAT), + MineStackObjectByMaterial(AGRICULTURAL, "pumpkin_seeds", "カボチャの種", Material.PUMPKIN_SEEDS), + MineStackObjectByMaterial(AGRICULTURAL, "melon_seeds", "スイカの種", Material.MELON_SEEDS), + MineStackObjectByMaterial(AGRICULTURAL, "nether_stalk", "ネザーウォート", Material.NETHER_WART), + MineStackObjectByMaterial(AGRICULTURAL, "chorus_fruit", "コーラスフルーツ", Material.CHORUS_FRUIT), + MineStackObjectByMaterial(AGRICULTURAL, "chorus_flower", "コーラスフラワー", Material.CHORUS_FLOWER), + MineStackObjectByMaterial(AGRICULTURAL, "popped_chorus_fruit", "焼いたコーラスフルーツ", Material.POPPED_CHORUS_FRUIT), + MineStackObjectByMaterial(AGRICULTURAL, "egg", "卵", Material.EGG), + MineStackObjectByMaterial(AGRICULTURAL, "pork", "生の豚肉", Material.PORKCHOP), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_porkchop", "焼き豚", Material.COOKED_PORKCHOP), + MineStackObjectByMaterial(AGRICULTURAL, "raw_chicken", "生の鶏肉", Material.CHICKEN), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_chicken", "焼き鳥", Material.COOKED_CHICKEN), + MineStackObjectByMaterial(AGRICULTURAL, "mutton", "生の羊肉", Material.MUTTON), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_mutton", "焼いた羊肉", Material.COOKED_MUTTON), + MineStackObjectByMaterial(AGRICULTURAL, "raw_beef", "生の牛肉", Material.BEEF), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_beaf", "ステーキ", Material.COOKED_BEEF), + MineStackObjectByMaterial(AGRICULTURAL, "rabbit", "生の兎肉", Material.RABBIT), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_rabbit", "焼き兎肉", Material.COOKED_RABBIT), + MineStackObjectByMaterial(AGRICULTURAL, "raw_fish0", "生鱈", Material.COD), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_fish0", "焼き鱈", Material.COOKED_COD), + MineStackObjectByMaterial(AGRICULTURAL, "raw_fish1", "生鮭", Material.SALMON), + MineStackObjectByMaterial(AGRICULTURAL, "cooked_fish1", "焼き鮭", Material.COOKED_SALMON), + MineStackObjectByMaterial(AGRICULTURAL, "raw_fish2", "クマノミ", Material.TROPICAL_FISH), + MineStackObjectByMaterial(AGRICULTURAL, "raw_fish3", "フグ", Material.PUFFERFISH), + MineStackObjectByMaterial(AGRICULTURAL, "bread", "パン", Material.BREAD), + MineStackObjectByMaterial(AGRICULTURAL, "sugar", "砂糖", Material.SUGAR), + MineStackObjectByMaterial(AGRICULTURAL, "baked_potato", "ベイクドポテト", Material.BAKED_POTATO), + MineStackObjectByMaterial(AGRICULTURAL, "cake", "ケーキ", Material.CAKE), + MineStackObjectByMaterial(AGRICULTURAL, "mushroom_stew", "キノコシチュー", Material.MUSHROOM_STEW), + MineStackObjectByMaterial(AGRICULTURAL, "rabbit_stew", "ウサギシチュー", Material.RABBIT_STEW), + MineStackObjectByMaterial(AGRICULTURAL, "beetroot_soup", "ビートルートスープ", Material.BEETROOT_SOUP), + MineStackObjectByMaterial(AGRICULTURAL, "bowl", "ボウル", Material.BOWL), + MineStackObjectByMaterial(AGRICULTURAL, "milk_bucket", "ミルク入りバケツ", Material.MILK_BUCKET), + MineStackObjectByMaterial(AGRICULTURAL, "kelp", "コンブ", Material.KELP), + MineStackObjectByMaterial(AGRICULTURAL, "crimson_hyphae", "真紅の菌糸", Material.CRIMSON_HYPHAE), + MineStackObjectByMaterial(AGRICULTURAL, "warped_hyphae", "歪んだ菌糸", Material.WARPED_HYPHAE), + MineStackObjectByMaterial(AGRICULTURAL, "azalea_leaves", "ツツジの葉", Material.AZALEA_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "flowering_azalea_leaves", "開花したツツジの葉", Material.FLOWERING_AZALEA_LEAVES), + MineStackObjectByMaterial(AGRICULTURAL, "carved_pumpkin", "くり抜かれたカボチャ", Material.CARVED_PUMPKIN), + MineStackObjectByMaterial(AGRICULTURAL, "dried_kelp_block", "乾燥した昆布ブロック", Material.DRIED_KELP_BLOCK), + MineStackObjectByMaterial(AGRICULTURAL, "suspicious_stew", "怪しげなシチュー", Material.SUSPICIOUS_STEW), + MineStackObjectByMaterial(AGRICULTURAL, "cookie", "クッキー", Material.COOKIE), + MineStackObjectByMaterial(AGRICULTURAL, "dried_kelp", "乾燥した昆布", Material.DRIED_KELP), + MineStackObjectByMaterial(AGRICULTURAL, "glistering_melon_slice", "きらめくスイカの薄切り", Material.GLISTERING_MELON_SLICE), + MineStackObjectByMaterial(AGRICULTURAL, "pumpkin_pie", "パンプキンパイ", Material.PUMPKIN_PIE), ) // 建築系ブロック private val minestacklistbuild: List[MineStackObjectGroup[ItemStack]] = leftElems( - MineStackObjectByMaterial(BUILDING, "log", "オークの原木", Material.LOG, 0), - MineStackObjectByMaterial(BUILDING, "wood", "オークの木材", Material.WOOD, 0), - MineStackObjectByMaterial(BUILDING, "wood_step0", "オークの木材ハーフブロック", Material.WOOD_STEP, 0), - MineStackObjectByMaterial(BUILDING, "oak_stairs", "オークの木の階段", Material.WOOD_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "fence", "オークのフェンス", Material.FENCE, 0), - MineStackObjectByMaterial(BUILDING, "log1", "マツの原木", Material.LOG, 1), - MineStackObjectByMaterial(BUILDING, "wood_1", "マツの木材", Material.WOOD, 1), - MineStackObjectByMaterial(BUILDING, "wood_step1", "マツの木材ハーフブロック", Material.WOOD_STEP, 1), - MineStackObjectByMaterial(BUILDING, "spruce_stairs", "マツの木の階段", Material.SPRUCE_WOOD_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "spruce_fence", "マツのフェンス", Material.SPRUCE_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "log2", "シラカバの原木", Material.LOG, 2), - MineStackObjectByMaterial(BUILDING, "wood_2", "シラカバの木材", Material.WOOD, 2), - MineStackObjectByMaterial(BUILDING, "wood_step2", "シラカバの木材ハーフブロック", Material.WOOD_STEP, 2), - MineStackObjectByMaterial(BUILDING, "birch_stairs", "シラカバの木の階段", Material.BIRCH_WOOD_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "birch_fence", "シラカバのフェンス", Material.BIRCH_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "log3", "ジャングルの原木", Material.LOG, 3), - MineStackObjectByMaterial(BUILDING, "wood_3", "ジャングルの木材", Material.WOOD, 3), - MineStackObjectByMaterial(BUILDING, "wood_step3", "ジャングルの木材ハーフブロック", Material.WOOD_STEP, 3), - MineStackObjectByMaterial(BUILDING, "jungle_stairs", "ジャングルの木の階段", Material.JUNGLE_WOOD_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "jungle_fence", "ジャングルのフェンス", Material.JUNGLE_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "log_2", "アカシアの原木", Material.LOG_2, 0), - MineStackObjectByMaterial(BUILDING, "wood_4", "アカシアの木材", Material.WOOD, 4), - MineStackObjectByMaterial(BUILDING, "wood_step4", "アカシアの木材ハーフブロック", Material.WOOD_STEP, 4), - MineStackObjectByMaterial(BUILDING, "acacia_stairs", "アカシアの木の階段", Material.ACACIA_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "acacia_fence", "アカシアのフェンス", Material.ACACIA_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "log_21", "ダークオークの原木", Material.LOG_2, 1), - MineStackObjectByMaterial(BUILDING, "wood_5", "ダークオークの木材", Material.WOOD, 5), - MineStackObjectByMaterial(BUILDING, "wood_step5", "ダークオークの木材ハーフブロック", Material.WOOD_STEP, 5), - MineStackObjectByMaterial(BUILDING, "dark_oak_stairs", "ダークオークの木の階段", Material.DARK_OAK_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "dark_oak_fence", "ダークオークのフェンス", Material.DARK_OAK_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "cobblestone", "丸石", Material.COBBLESTONE, 0), - MineStackObjectByMaterial(BUILDING, "step3", "丸石ハーフブロック", Material.STEP, 3), - MineStackObjectByMaterial(BUILDING, "stone_stairs", "丸石の階段", Material.COBBLESTONE_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "cobblestone_wall_0", "丸石の壁", Material.COBBLE_WALL, 0), - MineStackObjectByMaterial(BUILDING, "mossy_cobblestone", "苔石", Material.MOSSY_COBBLESTONE, 0), - MineStackObjectByMaterial(BUILDING, "cobblestone_wall_1", "苔石の壁", Material.COBBLE_WALL, 1), - MineStackObjectByMaterial(BUILDING, "stone", "石", Material.STONE, 0), - MineStackObjectByMaterial(BUILDING, "step0", "石ハーフブロック", Material.STEP, 0), - MineStackObjectByMaterial(BUILDING, "smooth_brick0", "石レンガ", Material.SMOOTH_BRICK, 0), - MineStackObjectByMaterial(BUILDING, "step5", "石レンガハーフブロック", Material.STEP, 5), - MineStackObjectByMaterial(BUILDING, "smooth_stairs", "石レンガの階段", Material.SMOOTH_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "smooth_brick3", "模様入り石レンガ", Material.SMOOTH_BRICK, 3), - MineStackObjectByMaterial(BUILDING, "smooth_brick1", "苔石レンガ", Material.SMOOTH_BRICK, 1), - MineStackObjectByMaterial(BUILDING, "smooth_brick2", "ひびの入った石レンガ", Material.SMOOTH_BRICK, 2), - MineStackObjectByMaterial(BUILDING, "sand", "砂", Material.SAND, 0), - MineStackObjectByMaterial(BUILDING, "sandstone", "砂岩", Material.SANDSTONE, 0), - MineStackObjectByMaterial(BUILDING, "step1", "砂岩ハーフブロック", Material.STEP, 1), - MineStackObjectByMaterial(BUILDING, "standstone_stairs", "砂岩の階段", Material.SANDSTONE_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "sandstone1", "模様入りの砂岩", Material.SANDSTONE, 1), - MineStackObjectByMaterial(BUILDING, "sandstone2", "なめらかな砂岩", Material.SANDSTONE, 2), - MineStackObjectByMaterial(BUILDING, "red_sand", "赤い砂", Material.SAND, 1), - MineStackObjectByMaterial(BUILDING, "red_sandstone", "赤い砂岩", Material.RED_SANDSTONE, 0), - MineStackObjectByMaterial(BUILDING, "stone_slab20", "赤い砂岩ハーフブロック", Material.STONE_SLAB2, 0), - MineStackObjectByMaterial(BUILDING, "red_sandstone_stairs", "赤い砂岩の階段", Material.RED_SANDSTONE_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "red_sandstone1", "模様入りの赤い砂岩", Material.RED_SANDSTONE, 1), - MineStackObjectByMaterial(BUILDING, "red_sandstone2", "なめらかな赤い砂岩", Material.RED_SANDSTONE, 2), - MineStackObjectByMaterial(BUILDING, "clay_ball", "粘土", Material.CLAY_BALL, 0), - MineStackObjectByMaterial(BUILDING, "clay", "粘土(ブロック)", Material.CLAY, 0), - MineStackObjectByMaterial(BUILDING, "brick_item", "レンガ", Material.CLAY_BRICK, 0), - MineStackObjectByMaterial(BUILDING, "brick", "レンガ(ブロック)", Material.BRICK, 0), - MineStackObjectByMaterial(BUILDING, "step4", "レンガハーフブロック", Material.STEP, 4), - MineStackObjectByMaterial(BUILDING, "brick_stairs", "レンガの階段", Material.BRICK_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "quartz_block", "ネザー水晶ブロック", Material.QUARTZ_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "step7", "ネザー水晶ハーフブロック", Material.STEP, 7), - MineStackObjectByMaterial(BUILDING, "quartz_stairs", "ネザー水晶の階段", Material.QUARTZ_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "quartz_block1", "模様入りネザー水晶ブロック", Material.QUARTZ_BLOCK, 1), - MineStackObjectByMaterial(BUILDING, "quartz_block2", "柱状ネザー水晶ブロック", Material.QUARTZ_BLOCK, 2), - MineStackObjectByMaterial(BUILDING, "netherrack", "ネザーラック", Material.NETHERRACK, 0), - MineStackObjectByMaterial(BUILDING, "nether_brick_item", "ネザーレンガ", Material.NETHER_BRICK_ITEM, 0), - MineStackObjectByMaterial(BUILDING, "nether_brick", "ネザーレンガ(ブロック)", Material.NETHER_BRICK, 0), - MineStackObjectByMaterial(BUILDING, "step6", "ネザーレンガハーフブロック", Material.STEP, 6), - MineStackObjectByMaterial(BUILDING, "nether_brick_stairs", "ネザーレンガの階段", Material.NETHER_BRICK_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "nether_brick_fence", "ネザーレンガのフェンス", Material.NETHER_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "red_nether_brick", "赤いネザーレンガ", Material.RED_NETHER_BRICK, 0), - MineStackObjectByMaterial(BUILDING, "nether_wart_block", "ネザ-ウォートブロック", Material.NETHER_WART_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "ender_stone", "エンドストーン", Material.ENDER_STONE, 0), - MineStackObjectByMaterial(BUILDING, "end_bricks", "エンドストーンレンガ", Material.END_BRICKS, 0), - MineStackObjectByMaterial(BUILDING, "purpur_block", "プルプァブロック", Material.PURPUR_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "purpur_pillar", "柱状プルプァブロック", Material.PURPUR_PILLAR, 0), - MineStackObjectByMaterial(BUILDING, "purpur_slab", "プルプァハーフブロック", Material.PURPUR_SLAB, 0), - MineStackObjectByMaterial(BUILDING, "purpur_stairs", "プルプァの階段", Material.PURPUR_STAIRS, 0), - MineStackObjectByMaterial(BUILDING, "prismarine0", "プリズマリン", Material.PRISMARINE, 0), - MineStackObjectByMaterial(BUILDING, "prismarine1", "プリズマリンレンガ", Material.PRISMARINE, 1), - MineStackObjectByMaterial(BUILDING, "prismarine2", "ダークプリズマリン", Material.PRISMARINE, 2), - MineStackObjectByMaterial(BUILDING, "sea_lantern", "シーランタン", Material.SEA_LANTERN, 0), - MineStackObjectByMaterial(BUILDING, "granite", "花崗岩", Material.STONE, 1), - MineStackObjectByMaterial(BUILDING, "polished_granite", "磨かれた花崗岩", Material.STONE, 2), - MineStackObjectByMaterial(BUILDING, "diorite", "閃緑岩", Material.STONE, 3), - MineStackObjectByMaterial(BUILDING, "polished_diorite", "磨かれた閃緑岩", Material.STONE, 4), - MineStackObjectByMaterial(BUILDING, "andesite", "安山岩", Material.STONE, 5), - MineStackObjectByMaterial(BUILDING, "polished_andesite", "磨かれた安山岩", Material.STONE, 6), - MineStackObjectByMaterial(BUILDING, "dirt", "土", Material.DIRT, 0), - MineStackObjectByMaterial(BUILDING, "grass", "草ブロック", Material.GRASS, 0), - MineStackObjectByMaterial(BUILDING, "gravel", "砂利", Material.GRAVEL, 0), - MineStackObjectByMaterial(BUILDING, "flint", "火打石", Material.FLINT, 0), - MineStackObjectByMaterial(BUILDING, "flint_and_steel", "火打石と打ち金", Material.FLINT_AND_STEEL, 0), - MineStackObjectByMaterial(BUILDING, "dirt1", "粗い土", Material.DIRT, 1), - MineStackObjectByMaterial(BUILDING, "dirt2", "ポドゾル", Material.DIRT, 2), - MineStackObjectByMaterial(BUILDING, "snow_block", "雪", Material.SNOW_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "snow_layer", "雪タイル", Material.SNOW, 0), - MineStackObjectByMaterial(BUILDING, "snow_ball", "雪玉", Material.SNOW_BALL, 0), - MineStackObjectByMaterial(BUILDING, "ice", "氷", Material.ICE, 0), - MineStackObjectByMaterial(BUILDING, "packed_ice", "氷塊", Material.PACKED_ICE, 0), - MineStackObjectByMaterial(BUILDING, "mycel", "菌糸", Material.MYCEL, 0), - MineStackObjectByMaterial(BUILDING, "bone_block", "骨ブロック", Material.BONE_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "sponge", "スポンジ", Material.SPONGE, 0), - MineStackObjectByMaterial(BUILDING, "wet_sponge", "濡れたスポンジ", Material.SPONGE, 1), - MineStackObjectByMaterial(BUILDING, "soul_sand", "ソウルサンド", Material.SOUL_SAND, 0), - MineStackObjectByMaterial(BUILDING, "magma", "マグマブロック", Material.MAGMA, 0), - MineStackObjectByMaterial(BUILDING, "obsidian", "黒曜石", Material.OBSIDIAN, 0), - MineStackObjectByMaterial(BUILDING, "glowstone_dust", "グロウストーンダスト", Material.GLOWSTONE_DUST, 0), - MineStackObjectByMaterial(BUILDING, "glowstone", "グロウストーン", Material.GLOWSTONE, 0), - MineStackObjectByMaterial(BUILDING, "torch", "松明", Material.TORCH, 0), - MineStackObjectByMaterial(BUILDING, "jack_o_lantern", "ジャック・オ・ランタン", Material.JACK_O_LANTERN, 0), - MineStackObjectByMaterial(BUILDING, "end_rod", "エンドロッド", Material.END_ROD, 0), - MineStackObjectByMaterial(BUILDING, "bucket", "バケツ", Material.BUCKET, 0), - MineStackObjectByMaterial(BUILDING, "water_bucket", "水入りバケツ", Material.WATER_BUCKET, 0), - MineStackObjectByMaterial(BUILDING, "lava_bucket", "溶岩入りバケツ", Material.LAVA_BUCKET, 0), - MineStackObjectByMaterial(BUILDING, "web", "クモの巣", Material.WEB, 0), - MineStackObjectByMaterial(BUILDING, "rails", "レール", Material.RAILS, 0), - MineStackObjectByMaterial(BUILDING, "furnace", "かまど", Material.FURNACE, 0), - MineStackObjectByMaterial(BUILDING, "chest", "チェスト", Material.CHEST, 0), - MineStackObjectByMaterial(BUILDING, "book", "本", Material.BOOK, 0), - MineStackObjectByMaterial(BUILDING, "bookshelf", "本棚", Material.BOOKSHELF, 0), - MineStackObjectByMaterial(BUILDING, "iron_bars", "鉄格子", Material.IRON_FENCE, 0), - MineStackObjectByMaterial(BUILDING, "anvil", "金床", Material.ANVIL, 0), - MineStackObjectByMaterial(BUILDING, "cauldron", "大釜", Material.CAULDRON_ITEM, 0), - MineStackObjectByMaterial(BUILDING, "brewing_stand", "醸造台", Material.BREWING_STAND_ITEM, 0), - MineStackObjectByMaterial(BUILDING, "flower_pot", "植木鉢", Material.FLOWER_POT_ITEM, 0), - MineStackObjectByMaterial(BUILDING, "hay_block", "干し草の俵", Material.HAY_BLOCK, 0), - MineStackObjectByMaterial(BUILDING, "ladder", "はしご", Material.LADDER, 0), - MineStackObjectByMaterial(BUILDING, "sign", "看板", Material.SIGN, 0), - MineStackObjectByMaterial(BUILDING, "item_frame", "額縁", Material.ITEM_FRAME, 0), - MineStackObjectByMaterial(BUILDING, "painting", "絵画", Material.PAINTING, 0), - MineStackObjectByMaterial(BUILDING, "beacon", "ビーコン", Material.BEACON, 0), - MineStackObjectByMaterial(BUILDING, "armor_stand", "アーマースタンド", Material.ARMOR_STAND, 0), - MineStackObjectByMaterial(BUILDING, "end_crystal", "エンドクリスタル", Material.END_CRYSTAL, 0), - MineStackObjectByMaterial(BUILDING, "enchanting_table", "エンチャントテーブル", Material.ENCHANTMENT_TABLE, 0), - MineStackObjectByMaterial(BUILDING, "jukebox", "ジュークボックス", Material.JUKEBOX, 0), - MineStackObjectByMaterial(BUILDING, "hard_clay", "テラコッタ", Material.HARD_CLAY, 0), - MineStackObjectByMaterial(BUILDING, "workbench", "作業台", Material.WORKBENCH, 0) + MineStackObjectByMaterial(BUILDING, "cobblestone", "丸石", Material.COBBLESTONE), + MineStackObjectByMaterial(BUILDING, "cobblestone_wall_0", "丸石の堀", Material.COBBLESTONE_WALL), + MineStackObjectByMaterial(BUILDING, "mossy_cobblestone", "苔むした丸石", Material.MOSSY_COBBLESTONE), + MineStackObjectByMaterial(BUILDING, "cobblestone_wall_1", "苔むした丸石の堀", Material.MOSSY_COBBLESTONE_WALL), + MineStackObjectByMaterial(BUILDING, "stone", "石", Material.STONE), + MineStackObjectByMaterial(BUILDING, "smooth_brick0", "石レンガ", Material.STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "smooth_brick3", "模様入り石レンガ", Material.CHISELED_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "smooth_brick1", "苔むした石レンガ", Material.MOSSY_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "smooth_brick2", "ひびの入った石レンガ", Material.CRACKED_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "sand", "砂", Material.SAND), + MineStackObjectByMaterial(BUILDING, "sandstone", "砂岩", Material.SANDSTONE), + MineStackObjectByMaterial(BUILDING, "sandstone1", "模様入りの砂岩", Material.CHISELED_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "sandstone2", "なめらかな砂岩", Material.SMOOTH_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "red_sand", "赤い砂", Material.RED_SAND), + MineStackObjectByMaterial(BUILDING, "red_sandstone", "赤い砂岩", Material.RED_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "red_sandstone1", "模様入りの赤い砂岩", Material.CHISELED_RED_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "red_sandstone2", "なめらかな赤い砂岩", Material.SMOOTH_RED_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "clay_ball", "粘土玉", Material.CLAY_BALL), + MineStackObjectByMaterial(BUILDING, "clay", "粘土", Material.CLAY), + MineStackObjectByMaterial(BUILDING, "brick_item", "レンガ", Material.BRICK), + MineStackObjectByMaterial(BUILDING, "brick", "レンガ(ブロック)", Material.BRICKS), + MineStackObjectByMaterial(BUILDING, "quartz_block", "クォーツブロック", Material.QUARTZ_BLOCK), + MineStackObjectByMaterial(BUILDING, "quartz_block1", "模様入りのクォーツブロック", Material.CHISELED_QUARTZ_BLOCK), + MineStackObjectByMaterial(BUILDING, "quartz_block2", "クォーツの柱", Material.QUARTZ_PILLAR), + MineStackObjectByMaterial(BUILDING, "netherrack", "ネザーラック", Material.NETHERRACK), + MineStackObjectByMaterial(BUILDING, "nether_brick_item", "ネザーレンガ", Material.NETHER_BRICK), + MineStackObjectByMaterial(BUILDING, "nether_brick", "ネザーレンガ(ブロック)", Material.NETHER_BRICKS), + MineStackObjectByMaterial(BUILDING, "red_nether_brick", "赤いネザーレンガ", Material.RED_NETHER_BRICKS), + MineStackObjectByMaterial(BUILDING, "nether_wart_block", "ネザ-ウォートブロック", Material.NETHER_WART_BLOCK), + MineStackObjectByMaterial(BUILDING, "ender_stone", "エンドストーン", Material.END_STONE), + MineStackObjectByMaterial(BUILDING, "end_bricks", "エンドストーンレンガ", Material.END_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "purpur_block", "プルプァブロック", Material.PURPUR_BLOCK), + MineStackObjectByMaterial(BUILDING, "purpur_pillar", "プルプァの柱", Material.PURPUR_PILLAR), + MineStackObjectByMaterial(BUILDING, "prismarine0", "プリズマリン", Material.PRISMARINE), + MineStackObjectByMaterial(BUILDING, "prismarine1", "プリズマリンレンガ", Material.PRISMARINE_BRICKS), + MineStackObjectByMaterial(BUILDING, "prismarine2", "ダークプリズマリン", Material.DARK_PRISMARINE), + MineStackObjectByMaterial(BUILDING, "sea_lantern", "シーランタン", Material.SEA_LANTERN), + MineStackObjectByMaterial(BUILDING, "granite", "花崗岩", Material.GRANITE), + MineStackObjectByMaterial(BUILDING, "polished_granite", "磨かれた花崗岩", Material.POLISHED_GRANITE), + MineStackObjectByMaterial(BUILDING, "diorite", "閃緑岩", Material.DIORITE), + MineStackObjectByMaterial(BUILDING, "polished_diorite", "磨かれた閃緑岩", Material.POLISHED_DIORITE), + MineStackObjectByMaterial(BUILDING, "andesite", "安山岩", Material.ANDESITE), + MineStackObjectByMaterial(BUILDING, "polished_andesite", "磨かれた安山岩", Material.POLISHED_ANDESITE), + MineStackObjectByMaterial(BUILDING, "dirt", "土", Material.DIRT), + MineStackObjectByMaterial(BUILDING, "grass", "草ブロック", Material.GRASS_BLOCK), + MineStackObjectByMaterial(BUILDING, "gravel", "砂利", Material.GRAVEL), + MineStackObjectByMaterial(BUILDING, "flint", "火打石", Material.FLINT), + MineStackObjectByMaterial(BUILDING, "flint_and_steel", "火打石と打ち金", Material.FLINT_AND_STEEL), + MineStackObjectByMaterial(BUILDING, "dirt1", "粗い土", Material.COARSE_DIRT), + MineStackObjectByMaterial(BUILDING, "dirt2", "ポドゾル", Material.PODZOL), + MineStackObjectByMaterial(BUILDING, "snow_block", "雪", Material.SNOW_BLOCK), + MineStackObjectByMaterial(BUILDING, "snow_layer", "雪タイル", Material.SNOW), + MineStackObjectByMaterial(BUILDING, "snow_ball", "雪玉", Material.SNOWBALL), + MineStackObjectByMaterial(BUILDING, "ice", "氷", Material.ICE), + MineStackObjectByMaterial(BUILDING, "packed_ice", "氷塊", Material.PACKED_ICE), + MineStackObjectByMaterial(BUILDING, "mycel", "菌糸", Material.MYCELIUM), + MineStackObjectByMaterial(BUILDING, "bone_block", "骨ブロック", Material.BONE_BLOCK), + MineStackObjectByMaterial(BUILDING, "sponge", "スポンジ", Material.SPONGE), + MineStackObjectByMaterial(BUILDING, "wet_sponge", "濡れたスポンジ", Material.WET_SPONGE), + MineStackObjectByMaterial(BUILDING, "soul_sand", "ソウルサンド", Material.SOUL_SAND), + MineStackObjectByMaterial(BUILDING, "magma", "マグマブロック", Material.MAGMA_BLOCK), + MineStackObjectByMaterial(BUILDING, "obsidian", "黒曜石", Material.OBSIDIAN), + MineStackObjectByMaterial(BUILDING, "glowstone_dust", "グロウストーンダスト", Material.GLOWSTONE_DUST), + MineStackObjectByMaterial(BUILDING, "glowstone", "グロウストーン", Material.GLOWSTONE), + MineStackObjectByMaterial(BUILDING, "torch", "松明", Material.TORCH), + MineStackObjectByMaterial(BUILDING, "jack_o_lantern", "ジャック・オ・ランタン", Material.JACK_O_LANTERN), + MineStackObjectByMaterial(BUILDING, "end_rod", "エンドロッド", Material.END_ROD), + MineStackObjectByMaterial(BUILDING, "bucket", "バケツ", Material.BUCKET), + MineStackObjectByMaterial(BUILDING, "water_bucket", "水入りバケツ", Material.WATER_BUCKET), + MineStackObjectByMaterial(BUILDING, "lava_bucket", "溶岩入りバケツ", Material.LAVA_BUCKET), + MineStackObjectByMaterial(BUILDING, "web", "クモの巣", Material.COBWEB), + MineStackObjectByMaterial(BUILDING, "rails", "レール", Material.RAIL), + MineStackObjectByMaterial(BUILDING, "furnace", "かまど", Material.FURNACE), + MineStackObjectByMaterial(BUILDING, "chest", "チェスト", Material.CHEST), + MineStackObjectByMaterial(BUILDING, "book", "本", Material.BOOK), + MineStackObjectByMaterial(BUILDING, "bookshelf", "本棚", Material.BOOKSHELF), + MineStackObjectByMaterial(BUILDING, "iron_bars", "鉄格子", Material.IRON_BARS), + MineStackObjectByMaterial(BUILDING, "anvil", "金床", Material.ANVIL), + MineStackObjectByMaterial(BUILDING, "cauldron", "大釜", Material.CAULDRON), + MineStackObjectByMaterial(BUILDING, "brewing_stand", "醸造台", Material.BREWING_STAND), + MineStackObjectByMaterial(BUILDING, "flower_pot", "植木鉢", Material.FLOWER_POT), + MineStackObjectByMaterial(BUILDING, "hay_block", "干草の俵", Material.HAY_BLOCK), + MineStackObjectByMaterial(BUILDING, "ladder", "はしご", Material.LADDER), + MineStackObjectByMaterial(BUILDING, "item_frame", "額縁", Material.ITEM_FRAME), + MineStackObjectByMaterial(BUILDING, "painting", "絵画", Material.PAINTING), + MineStackObjectByMaterial(BUILDING, "beacon", "ビーコン", Material.BEACON), + MineStackObjectByMaterial(BUILDING, "armor_stand", "防具立て", Material.ARMOR_STAND), + MineStackObjectByMaterial(BUILDING, "end_crystal", "エンドクリスタル", Material.END_CRYSTAL), + MineStackObjectByMaterial(BUILDING, "enchanting_table", "エンチャントテーブル", Material.ENCHANTING_TABLE), + MineStackObjectByMaterial(BUILDING, "jukebox", "ジュークボックス", Material.JUKEBOX), + MineStackObjectByMaterial(BUILDING, "workbench", "作業台", Material.CRAFTING_TABLE), + MineStackObjectByMaterial(BUILDING, "deepslate", "深層岩", Material.DEEPSLATE), + MineStackObjectByMaterial(BUILDING, "cobbled_deepslate", "深層岩の丸石", Material.COBBLED_DEEPSLATE), + MineStackObjectByMaterial(BUILDING, "polished_deepslate", "磨かれた深層岩", Material.POLISHED_DEEPSLATE), + MineStackObjectByMaterial(BUILDING, "calcite", "方解石", Material.CALCITE), + MineStackObjectByMaterial(BUILDING, "tuff", "凝灰岩", Material.TUFF), + MineStackObjectByMaterial(BUILDING, "dripstone_block", "鍾乳石ブロック", Material.DRIPSTONE_BLOCK), + MineStackObjectByMaterial(BUILDING, "grass_block", "草", Material.GRASS), + MineStackObjectByMaterial(BUILDING, "rooted_dirt", "根付いた土", Material.ROOTED_DIRT), + MineStackObjectByMaterial(BUILDING, "crimson_nylium", "真紅のナイリウム", Material.CRIMSON_NYLIUM), + MineStackObjectByMaterial(BUILDING, "warped_nylium", "歪んだナイリウム", Material.WARPED_NYLIUM), + MineStackObjectByMaterial(BUILDING, "crimson_stem", "真紅の幹", Material.CRIMSON_STEM), + MineStackObjectByMaterial(BUILDING, "warped_stem", "歪んだ幹", Material.WARPED_STEM), + MineStackObjectByMaterial(BUILDING, "warped_wart_block", "歪んだウォートブロック", Material.WARPED_WART_BLOCK), + MineStackObjectByMaterial(BUILDING, "stripped_crimson_stem", "表皮を剥いだ真紅の幹", Material.STRIPPED_CRIMSON_STEM), + MineStackObjectByMaterial(BUILDING, "stripped_warped_stem", "表皮を剥いだ歪んだ幹", Material.STRIPPED_WARPED_STEM), + MineStackObjectByMaterial(BUILDING, "stripped_crimson_hyphae", "表皮を剥いだ真紅の菌糸", Material.STRIPPED_CRIMSON_HYPHAE), + MineStackObjectByMaterial(BUILDING, "stripped_warped_hyphae", "表皮を剥いだ歪んだ菌糸", Material.STRIPPED_WARPED_HYPHAE), + MineStackObjectByMaterial(BUILDING, "tinted_glass", "遮光ガラス", Material.TINTED_GLASS), + MineStackObjectByMaterial(BUILDING, "cut_sandstone", "研がれた砂岩", Material.CUT_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "azalea", "ツツジ", Material.AZALEA), + MineStackObjectByMaterial(BUILDING, "flowering_azalea", "開花したツツジ", Material.FLOWERING_AZALEA), + MineStackObjectByMaterial(BUILDING, "seagrass", "海草", Material.SEAGRASS), + MineStackObjectByMaterial(BUILDING, "sea_pickle", "シーピクルス", Material.SEA_PICKLE), + MineStackObjectByMaterial(BUILDING, "cornflower", "ヤグルマギク", Material.CORNFLOWER), + MineStackObjectByMaterial(BUILDING, "lily_of_the_valley", "スズラン", Material.LILY_OF_THE_VALLEY), + MineStackObjectByMaterial(BUILDING, "wither_rose", "ウィザーローズ", Material.WITHER_ROSE), + MineStackObjectByMaterial(BUILDING, "spore_blossom", "胞子の花", Material.SPORE_BLOSSOM), + MineStackObjectByMaterial(BUILDING, "crimson_fungus", "真紅のキノコ", Material.CRIMSON_FUNGUS), + MineStackObjectByMaterial(BUILDING, "warped_fungus", "歪んだキノコ", Material.WARPED_FUNGUS), + MineStackObjectByMaterial(BUILDING, "crimson_roots", "真紅の根", Material.CRIMSON_ROOTS), + MineStackObjectByMaterial(BUILDING, "warped_roots", "歪んだ根", Material.WARPED_ROOTS), + MineStackObjectByMaterial(BUILDING, "nether_sprouts", "ネザースプラウト", Material.NETHER_SPROUTS), + MineStackObjectByMaterial(BUILDING, "weeping_vines", "しだれツタ", Material.WEEPING_VINES), + MineStackObjectByMaterial(BUILDING, "twisting_vines", "ねじれツタ", Material.TWISTING_VINES), + MineStackObjectByMaterial(BUILDING, "moss_carpet", "苔のカーペット", Material.MOSS_CARPET), + MineStackObjectByMaterial(BUILDING, "moss_block", "苔ブロック", Material.MOSS_BLOCK), + MineStackObjectByMaterial(BUILDING, "hanging_roots", "垂れ根", Material.HANGING_ROOTS), + MineStackObjectByMaterial(BUILDING, "big_dripleaf", "大きなドリップリーフ", Material.BIG_DRIPLEAF), + MineStackObjectByMaterial(BUILDING, "small_dripleaf", "小さなドリップリーフ", Material.SMALL_DRIPLEAF), + MineStackObjectByMaterial(BUILDING, "bamboo", "竹", Material.BAMBOO), + MineStackObjectByMaterial(BUILDING, "smooth_quartz", "滑らかなクォーツブロック", Material.SMOOTH_QUARTZ), + MineStackObjectByMaterial(BUILDING, "smooth_stone", "滑らかな石", Material.SMOOTH_STONE), + MineStackObjectByMaterial(BUILDING, "chorus_plant", "コーラスプラント", Material.CHORUS_PLANT), + MineStackObjectByMaterial(BUILDING, "soul_soil", "ソウルソイル", Material.SOUL_SOIL), + MineStackObjectByMaterial(BUILDING, "basalt", "玄武岩", Material.BASALT), + MineStackObjectByMaterial(BUILDING, "polished_basalt", "磨かれた玄武岩", Material.POLISHED_BASALT), + MineStackObjectByMaterial(BUILDING, "smooth_basalt", "滑らかな玄武岩", Material.SMOOTH_BASALT), + MineStackObjectByMaterial(BUILDING, "soul_torch", "魂の松明", Material.SOUL_TORCH), + MineStackObjectByMaterial(BUILDING, "infested_stone", "虫食い石", Material.INFESTED_STONE), + MineStackObjectByMaterial(BUILDING, "infested_cobblestone", "虫食い丸石", Material.INFESTED_COBBLESTONE), + MineStackObjectByMaterial(BUILDING, "infested_stone_bricks", "虫食い石レンガ", Material.INFESTED_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "infested_mossy_stone_bricks", "苔むした虫食い石レンガ", Material.INFESTED_MOSSY_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "infested_cracked_stone_bricks", "ひび割れた虫食い石レンガ", Material.INFESTED_CRACKED_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "infested_chiseled_stone_bricks", "模様入りの虫食い石レンガ", Material.INFESTED_CHISELED_STONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "infested_deepslate", "虫食い深層岩", Material.INFESTED_DEEPSLATE), + MineStackObjectByMaterial(BUILDING, "deepslate_bricks", "深層岩レンガ", Material.DEEPSLATE_BRICKS), + MineStackObjectByMaterial(BUILDING, "cracked_deepslate_bricks", "ひび割れた深層岩レンガ", Material.CRACKED_DEEPSLATE_BRICKS), + MineStackObjectByMaterial(BUILDING, "deepslate_tiles", "深層岩タイル", Material.DEEPSLATE_TILES), + MineStackObjectByMaterial(BUILDING, "cracked_deepslate_tiles", "ひび割れた深層岩タイル", Material.CRACKED_DEEPSLATE_TILES), + MineStackObjectByMaterial(BUILDING, "chiseled_deepslate", "模様入りの深層岩", Material.CHISELED_DEEPSLATE), + MineStackObjectByMaterial(BUILDING, "brown_mushroom_block", "茶色のキノコブロック", Material.BROWN_MUSHROOM_BLOCK), + MineStackObjectByMaterial(BUILDING, "red_mushroom_block", "赤色のキノコブロック", Material.RED_MUSHROOM_BLOCK), + MineStackObjectByMaterial(BUILDING, "mushroom_stem", "キノコの柄", Material.MUSHROOM_STEM), + MineStackObjectByMaterial(BUILDING, "chain", "鎖", Material.CHAIN), + MineStackObjectByMaterial(BUILDING, "glow_lichen", "ヒカリゴケ", Material.GLOW_LICHEN), + MineStackObjectByMaterial(BUILDING, "cracked_nether_bricks", "ひび割れたネザーレンガ", Material.CRACKED_NETHER_BRICKS), + MineStackObjectByMaterial(BUILDING, "chiseled_nether_bricks", "模様入りのネザーレンガ", Material.CHISELED_NETHER_BRICKS), + MineStackObjectByMaterial(BUILDING, "quartz_bricks", "クォーツレンガ", Material.QUARTZ_BRICKS), + MineStackObjectByMaterial(BUILDING, "cut_red_sandstone", "研がれた赤い砂岩", Material.CUT_RED_SANDSTONE), + MineStackObjectByMaterial(BUILDING, "turtle_egg", "カメの卵", Material.TURTLE_EGG), + MineStackObjectByMaterial(BUILDING, "blue_ice", "青氷", Material.BLUE_ICE), + MineStackObjectByMaterial(BUILDING, "conduit", "コンジット", Material.CONDUIT), + MineStackObjectByMaterial(BUILDING, "scaffolding", "足場", Material.SCAFFOLDING), + MineStackObjectByMaterial(BUILDING, "honey_block", "ハチミツブロック", Material.HONEY_BLOCK), + MineStackObjectByMaterial(BUILDING, "loom", "機織り機", Material.LOOM), + MineStackObjectByMaterial(BUILDING, "composter", "コンポスター", Material.COMPOSTER), + MineStackObjectByMaterial(BUILDING, "barrel", "樽", Material.BARREL), + MineStackObjectByMaterial(BUILDING, "smoker", "燻製器", Material.SMOKER), + MineStackObjectByMaterial(BUILDING, "blast_furnace", "溶鉱炉", Material.BLAST_FURNACE), + MineStackObjectByMaterial(BUILDING, "cartography_table", "製図台", Material.CARTOGRAPHY_TABLE), + MineStackObjectByMaterial(BUILDING, "fletching_table", "矢細工台", Material.FLETCHING_TABLE), + MineStackObjectByMaterial(BUILDING, "grindstone", "砥石", Material.GRINDSTONE), + MineStackObjectByMaterial(BUILDING, "smithing_table", "鍛冶台", Material.SMITHING_TABLE), + MineStackObjectByMaterial(BUILDING, "stonecutter", "石切台", Material.STONECUTTER), + MineStackObjectByMaterial(BUILDING, "bell", "鐘", Material.BELL), + MineStackObjectByMaterial(BUILDING, "lantern", "ランタン", Material.LANTERN), + MineStackObjectByMaterial(BUILDING, "soul_lantern", "魂のランタン", Material.SOUL_LANTERN), + MineStackObjectByMaterial(BUILDING, "sweet_berries", "スイートベリー", Material.SWEET_BERRIES), + MineStackObjectByMaterial(BUILDING, "glow_berries", "グロウベリー", Material.GLOW_BERRIES), + MineStackObjectByMaterial(BUILDING, "campfire", "焚き火", Material.CAMPFIRE), + MineStackObjectByMaterial(BUILDING, "soul_campfire", "魂の焚き火", Material.SOUL_CAMPFIRE), + MineStackObjectByMaterial(BUILDING, "shroomlight", "シュルームライト", Material.SHROOMLIGHT), + MineStackObjectByMaterial(BUILDING, "honeycomb", "ハニカム", Material.HONEYCOMB), + MineStackObjectByMaterial(BUILDING, "beehive", "養蜂箱", Material.BEEHIVE), + MineStackObjectByMaterial(BUILDING, "honey_bottle", "ハチミツ入りの瓶", Material.HONEY_BOTTLE), + MineStackObjectByMaterial(BUILDING, "honeycomb_block", "ハニカムブロック", Material.HONEYCOMB_BLOCK), + MineStackObjectByMaterial(BUILDING, "lodestone", "ロードストーン", Material.LODESTONE), + MineStackObjectByMaterial(BUILDING, "crying_obsidian", "泣く黒曜石", Material.CRYING_OBSIDIAN), + MineStackObjectByMaterial(BUILDING, "blackstone", "ブラックストーン", Material.BLACKSTONE), + MineStackObjectByMaterial(BUILDING, "gilded_blackstone", "きらめくブラックストーン", Material.GILDED_BLACKSTONE), + MineStackObjectByMaterial(BUILDING, "polished_blackstone", "磨かれたブラックストーン", Material.POLISHED_BLACKSTONE), + MineStackObjectByMaterial(BUILDING, "chiseled_polished_blackstone", "模様入りの磨かれたブラックストーン", Material.CHISELED_POLISHED_BLACKSTONE), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_bricks", "磨かれたブラックストーンレンガ", Material.POLISHED_BLACKSTONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "cracked_polished_blackstone_bricks", "ひび割れたブラックストーンレンガ", Material.CRACKED_POLISHED_BLACKSTONE_BRICKS), + MineStackObjectByMaterial(BUILDING, "respawn_anchor", "リスポーンアンカー", Material.RESPAWN_ANCHOR), + MineStackObjectByMaterial(BUILDING, "pointed_dripstone", "鍾乳石", Material.POINTED_DRIPSTONE), + MineStackObjectByMaterial(BUILDING, "warped_fungus_on_a_stick", "歪んだキノコ付きの棒", Material.WARPED_FUNGUS_ON_A_STICK), + MineStackObjectByMaterial(BUILDING, "powder_snow_bucket", "粉雪入りバケツ", Material.POWDER_SNOW_BUCKET), + MineStackObjectByMaterial(BUILDING, "glow_ink_sac", "輝くイカスミ", Material.GLOW_INK_SAC), + MineStackObjectByMaterial(BUILDING, "filled_map", "地図", Material.FILLED_MAP), + MineStackObjectByMaterial(BUILDING, "fire_charge", "ファイヤーチャージ", Material.FIRE_CHARGE), + MineStackObjectByMaterial(BUILDING, "writable_book", "本と羽根ペン", Material.WRITABLE_BOOK), + MineStackObjectByMaterial(BUILDING, "written_book", "記入済みの本", Material.WRITTEN_BOOK), + MineStackObjectByMaterial(BUILDING, "glow_item_frame", "輝く額縁", Material.GLOW_ITEM_FRAME), + MineStackObjectByMaterial(BUILDING, "firework_star", "花火の星", Material.FIREWORK_STAR), + MineStackObjectByMaterial(BUILDING, "leather_horse_armor", "革の馬鎧", Material.LEATHER_HORSE_ARMOR), ) ++ rightElems( - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "bed", "白色のベッド", Material.BED, 0), - List( - MineStackObjectByMaterial(BUILDING, "bed_1", "橙色のベッド", Material.BED, 1), - MineStackObjectByMaterial(BUILDING, "bed_2", "赤紫色のベッド", Material.BED, 2), - MineStackObjectByMaterial(BUILDING, "bed_3", "空色のベッド", Material.BED, 3), - MineStackObjectByMaterial(BUILDING, "bed_4", "黄色のベッド", Material.BED, 4), - MineStackObjectByMaterial(BUILDING, "bed_5", "黄緑色のベッド", Material.BED, 5), - MineStackObjectByMaterial(BUILDING, "bed_6", "桃色のベッド", Material.BED, 6), - MineStackObjectByMaterial(BUILDING, "bed_7", "灰色のベッド", Material.BED, 7), - MineStackObjectByMaterial(BUILDING, "bed_8", "薄灰色のベッド", Material.BED, 8), - MineStackObjectByMaterial(BUILDING, "bed_9", "青緑色のベッド", Material.BED, 9), - MineStackObjectByMaterial(BUILDING, "bed_10", "紫色のベッド", Material.BED, 10), - MineStackObjectByMaterial(BUILDING, "bed_11", "青色のベッド", Material.BED, 11), - MineStackObjectByMaterial(BUILDING, "bed_12", "茶色のベッド", Material.BED, 12), - MineStackObjectByMaterial(BUILDING, "bed_13", "緑色のベッド", Material.BED, 13), - MineStackObjectByMaterial(BUILDING, "bed_14", "赤色のベッド", Material.BED, 14), - MineStackObjectByMaterial(BUILDING, "bed_15", "黒色のベッド", Material.BED, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "log", "オークの原木", Material.OAK_LOG), + List( + MineStackObjectByMaterial(BUILDING, "log1", "トウヒの原木", Material.SPRUCE_LOG), + MineStackObjectByMaterial(BUILDING, "log2", "シラカバの原木", Material.BIRCH_LOG), + MineStackObjectByMaterial(BUILDING, "log3", "ジャングルの原木", Material.JUNGLE_LOG), + MineStackObjectByMaterial(BUILDING, "log_2", "アカシアの原木", Material.ACACIA_LOG), + MineStackObjectByMaterial(BUILDING, "log_21", "ダークオークの原木", Material.DARK_OAK_LOG), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "stripped_oak_log", "樹皮を剥いだオークの原木", Material.STRIPPED_OAK_LOG), + List( + MineStackObjectByMaterial(BUILDING, "stripped_spruce_log", "樹皮を剥いだトウヒの原木", Material.STRIPPED_SPRUCE_LOG), + MineStackObjectByMaterial(BUILDING, "stripped_birch_log", "樹皮を剥いだシラカバの原木", Material.STRIPPED_BIRCH_LOG), + MineStackObjectByMaterial(BUILDING, "stripped_jungle_log", "樹皮を剥いだジャングルの原木", Material.STRIPPED_JUNGLE_LOG), + MineStackObjectByMaterial(BUILDING, "stripped_acacia_log", "樹皮を剥いだアカシアの原木", Material.STRIPPED_ACACIA_LOG), + MineStackObjectByMaterial(BUILDING, "stripped_dark_oak_log", "樹皮を剥いだダークオークの原木", Material.STRIPPED_DARK_OAK_LOG), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "stripped_oak_wood", "樹皮を剥いだオークの木", Material.STRIPPED_OAK_WOOD), + List( + MineStackObjectByMaterial(BUILDING, "stripped_spruce_wood", "樹皮を剥いだトウヒの木", Material.STRIPPED_SPRUCE_WOOD), + MineStackObjectByMaterial(BUILDING, "stripped_birch_wood", "樹皮を剥いだシラカバの木", Material.STRIPPED_BIRCH_WOOD), + MineStackObjectByMaterial(BUILDING, "stripped_jungle_wood", "樹皮を剥いだジャングルの木", Material.STRIPPED_JUNGLE_WOOD), + MineStackObjectByMaterial(BUILDING, "stripped_acacia_wood", "樹皮を剥いだアカシアの木", Material.STRIPPED_ACACIA_WOOD), + MineStackObjectByMaterial(BUILDING, "stripped_dark_oak_wood", "樹皮を剥いだダークオークの木", Material.STRIPPED_DARK_OAK_WOOD), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "wood", "オークの木材", Material.OAK_WOOD), + List( + MineStackObjectByMaterial(BUILDING, "wood_1", "トウヒの木材", Material.SPRUCE_WOOD), + MineStackObjectByMaterial(BUILDING, "wood_2", "シラカバの木材", Material.BIRCH_WOOD), + MineStackObjectByMaterial(BUILDING, "wood_3", "ジャングルの木材", Material.JUNGLE_WOOD), + MineStackObjectByMaterial(BUILDING, "wood_4", "アカシアの木材", Material.ACACIA_WOOD), + MineStackObjectByMaterial(BUILDING, "wood_5", "ダークオークの木材", Material.DARK_OAK_WOOD), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "oak_planks", "オークの板材", Material.OAK_PLANKS), + List( + MineStackObjectByMaterial(BUILDING, "spruce_planks", "トウヒの板材", Material.SPRUCE_PLANKS), + MineStackObjectByMaterial(BUILDING, "birch_planks", "シラカバの板材", Material.BIRCH_PLANKS), + MineStackObjectByMaterial(BUILDING, "jungle_planks", "ジャングルの板材", Material.JUNGLE_PLANKS), + MineStackObjectByMaterial(BUILDING, "acacia_planks", "アカシアの板材", Material.ACACIA_PLANKS), + MineStackObjectByMaterial(BUILDING, "dark_oak_planks", "ダークオークの板材", Material.DARK_OAK_PLANKS), + MineStackObjectByMaterial(BUILDING, "crimson_planks", "真紅の板材", Material.CRIMSON_PLANKS), + MineStackObjectByMaterial(BUILDING, "warped_planks", "歪んだ板材", Material.WARPED_PLANKS), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "wood_step0", "オークのハーフブロック", Material.OAK_SLAB), + List( + MineStackObjectByMaterial(BUILDING, "wood_step1", "トウヒのハーフブロック", Material.SPRUCE_SLAB), + MineStackObjectByMaterial(BUILDING, "wood_step2", "シラカバのハーフブロック", Material.BIRCH_SLAB), + MineStackObjectByMaterial(BUILDING, "wood_step3", "ジャングルのハーフブロック", Material.JUNGLE_SLAB), + MineStackObjectByMaterial(BUILDING, "wood_step4", "アカシアのハーフブロック", Material.ACACIA_SLAB), + MineStackObjectByMaterial(BUILDING, "wood_step5", "ダークオークのハーフブロック", Material.DARK_OAK_SLAB), + MineStackObjectByMaterial(BUILDING, "step3", "丸石のハーフブロック", Material.COBBLESTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "step0", "石のハーフブロック", Material.STONE_SLAB), + MineStackObjectByMaterial(BUILDING, "step5", "石レンガのハーフブロック", Material.STONE_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "step1", "砂岩のハーフブロック", Material.SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "stone_slab20", "赤い砂岩のハーフブロック", Material.RED_SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "step4", "レンガのハーフブロック", Material.BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "step7", "クォーツのハーフブロック", Material.QUARTZ_SLAB), + MineStackObjectByMaterial(BUILDING, "step6", "ネザーレンガのハーフブロック", Material.NETHER_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "purpur_slab", "プルプァのハーフブロック", Material.PURPUR_SLAB), + MineStackObjectByMaterial(BUILDING, "cut_copper_slab", "切り込み入りの銅のハーフブロック", Material.CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "exposed_cut_copper_slab", "風化した切り込み入りの銅のハーフブロック", Material.EXPOSED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "weathered_cut_copper_slab", "錆びた切り込み入りの銅のハーフブロック", Material.WEATHERED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "oxidized_cut_copper_slab", "酸化した切り込み入りの銅のハーフブロック", Material.OXIDIZED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "waxed_cut_copper_slab", "錆止めされた切り込み入りの銅のハーフブロック", Material.WAXED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "waxed_exposed_cut_copper_slab", "錆止めされた風化した切り込み入りの銅のハーフブロック", Material.WAXED_EXPOSED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "waxed_weathered_cut_copper_slab", "錆止めされた錆びた切り込み入りの銅のハーフブロック", Material.WAXED_WEATHERED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "waxed_oxidized_cut_copper_slab", "錆止めされた酸化した切り込み入りの銅のハーフブロック", Material.WAXED_OXIDIZED_CUT_COPPER_SLAB), + MineStackObjectByMaterial(BUILDING, "crimson_slab", "真紅のハーフブロック", Material.CRIMSON_SLAB), + MineStackObjectByMaterial(BUILDING, "warped_slab", "歪んだハーフブロック", Material.WARPED_SLAB), + MineStackObjectByMaterial(BUILDING, "smooth_stone_slab", "滑らかな石のハーフブロック", Material.SMOOTH_STONE_SLAB), + MineStackObjectByMaterial(BUILDING, "cut_sandstone_slab", "研がれた砂岩のハーフブロック", Material.CUT_SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "petrified_oak_slab", "石化したオークのハーフブロック", Material.PETRIFIED_OAK_SLAB), + MineStackObjectByMaterial(BUILDING, "cut_red_sandstone_slab", "研がれた赤い砂岩のハーフブロック", Material.CUT_RED_SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "prismarine_slab", "プリズマリンのハーフブロック", Material.PRISMARINE_SLAB), + MineStackObjectByMaterial(BUILDING, "prismarine_brick_slab", "プリズマリンレンガのハーフブロック", Material.PRISMARINE_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "dark_prismarine_slab", "ダークプリズマリンのハーフブロック", Material.DARK_PRISMARINE_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_granite_slab", "磨かれた花崗岩のハーフブロック", Material.POLISHED_GRANITE_SLAB), + MineStackObjectByMaterial(BUILDING, "smooth_red_sandstone_slab", "滑らかな赤い砂岩のハーフブロック", Material.SMOOTH_RED_SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "mossy_stone_brick_slab", "苔むした石レンガのハーフブロック", Material.MOSSY_STONE_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_diorite_slab", "磨かれた閃緑岩のハーフブロック", Material.POLISHED_DIORITE_SLAB), + MineStackObjectByMaterial(BUILDING, "mossy_cobblestone_slab", "苔むした丸石のハーフブロック", Material.MOSSY_COBBLESTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "end_stone_brick_slab", "エンドストーンレンガのハーフブロック", Material.END_STONE_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "smooth_sandstone_slab", "滑らかな砂岩のハーフブロック", Material.SMOOTH_SANDSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "smooth_quartz_slab", "滑らかなクォーツのハーフブロック", Material.SMOOTH_QUARTZ_SLAB), + MineStackObjectByMaterial(BUILDING, "granite_slab", "花崗岩のハーフブロック", Material.GRANITE_SLAB), + MineStackObjectByMaterial(BUILDING, "andesite_slab", "安山岩のハーフブロック", Material.ANDESITE_SLAB), + MineStackObjectByMaterial(BUILDING, "red_nether_brick_slab", "赤いネザーレンガのハーフブロック", Material.RED_NETHER_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_andesite_slab", "磨かれた安山岩のハーフブロック", Material.POLISHED_ANDESITE_SLAB), + MineStackObjectByMaterial(BUILDING, "diorite_slab", "閃緑岩のハーフブロック", Material.DIORITE_SLAB), + MineStackObjectByMaterial(BUILDING, "cobbled_deepslate_slab", "深層岩の丸石のハーフブロック", Material.COBBLED_DEEPSLATE_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_deepslate_slab", "磨かれた深層岩のハーフブロック", Material.POLISHED_DEEPSLATE_SLAB), + MineStackObjectByMaterial(BUILDING, "deepslate_brick_slab", "深層岩レンガのハーフブロック", Material.DEEPSLATE_BRICK_SLAB), + MineStackObjectByMaterial(BUILDING, "deepslate_tile_slab", "深層岩タイルのハーフブロック", Material.DEEPSLATE_TILE_SLAB), + MineStackObjectByMaterial(BUILDING, "blackstone_slab", "ブラックストーンのハーフブロック", Material.BLACKSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_slab", "磨かれたブラックストーンのハーフブロック", Material.POLISHED_BLACKSTONE_SLAB), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_brick_slab", "磨かれたブラックストーンレンガのハーフブロック", Material.POLISHED_BLACKSTONE_BRICK_SLAB), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "oak_stairs", "オークの階段", Material.OAK_STAIRS), + List( + MineStackObjectByMaterial(BUILDING, "spruce_stairs", "トウヒの階段", Material.SPRUCE_STAIRS), + MineStackObjectByMaterial(BUILDING, "birch_stairs", "シラカバの階段", Material.BIRCH_STAIRS), + MineStackObjectByMaterial(BUILDING, "jungle_stairs", "ジャングルの階段", Material.JUNGLE_STAIRS), + MineStackObjectByMaterial(BUILDING, "acacia_stairs", "アカシアの階段", Material.ACACIA_STAIRS), + MineStackObjectByMaterial(BUILDING, "dark_oak_stairs", "ダークオークの階段", Material.DARK_OAK_STAIRS), + MineStackObjectByMaterial(BUILDING, "stone_stairs", "丸石の階段", Material.COBBLESTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "smooth_stairs", "石レンガの階段", Material.STONE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "standstone_stairs", "砂岩の階段", Material.SANDSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "red_sandstone_stairs", "赤い砂岩の階段", Material.RED_SANDSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "brick_stairs", "レンガの階段", Material.BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "quartz_stairs", "クォーツの階段", Material.QUARTZ_STAIRS), + MineStackObjectByMaterial(BUILDING, "nether_brick_stairs", "ネザーレンガの階段", Material.NETHER_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "purpur_stairs", "プルプァの階段", Material.PURPUR_STAIRS), + MineStackObjectByMaterial(BUILDING, "cut_copper_stairs", "切り込み入りの銅の階段", Material.CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "exposed_cut_copper_stairs", "風化した切り込み入りの銅の階段", Material.EXPOSED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "weathered_cut_copper_stairs", "錆びた切り込み入りの銅の階段", Material.WEATHERED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "oxidized_cut_copper_stairs", "酸化した切り込み入りの銅の階段", Material.OXIDIZED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "waxed_cut_copper_stairs", "錆止めされた切り込み入りの銅の階段", Material.WAXED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "waxed_exposed_cut_copper_stairs", "錆止めされた風化した切り込み入りの銅の階段", Material.WAXED_EXPOSED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "waxed_weathered_cut_copper_stairs", "錆止めされた錆びた切り込み入りの銅の階段", Material.WAXED_WEATHERED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "waxed_oxidized_cut_copper_stairs", "錆止めされた酸化した切り込み入りの銅の階段", Material.WAXED_OXIDIZED_CUT_COPPER_STAIRS), + MineStackObjectByMaterial(BUILDING, "crimson_stairs", "真紅の階段", Material.CRIMSON_STAIRS), + MineStackObjectByMaterial(BUILDING, "prismarine_stairs", "プリズマリンの階段", Material.PRISMARINE_STAIRS), + MineStackObjectByMaterial(BUILDING, "prismarine_brick_stairs", "プリズマリンレンガの階段", Material.PRISMARINE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "dark_prismarine_stairs", "ダークプリズマリンの階段", Material.DARK_PRISMARINE_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_granite_stairs", "磨かれた花崗岩の階段", Material.POLISHED_GRANITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "smooth_red_sandstone_stairs", "滑らかな赤い砂岩の階段", Material.SMOOTH_RED_SANDSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "mossy_stone_brick_stairs", "苔むした石レンガの階段", Material.MOSSY_STONE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_diorite_stairs", "磨かれた閃緑岩の階段", Material.POLISHED_DIORITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "mossy_cobblestone_stairs", "苔むした丸石の階段", Material.MOSSY_COBBLESTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "end_stone_brick_stairs", "エンドストーンレンガの階段", Material.END_STONE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "stone_stairs", "石の階段", Material.STONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "smooth_sandstone_stairs", "滑らかな砂岩の階段", Material.SMOOTH_SANDSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "smooth_quartz_stairs", "滑らかなクォーツの階段", Material.SMOOTH_QUARTZ_STAIRS), + MineStackObjectByMaterial(BUILDING, "granite_stairs", "花崗岩の階段", Material.GRANITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "andesite_stairs", "安山岩の階段", Material.ANDESITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "red_nether_brick_stairs", "赤いネザーレンガの階段", Material.RED_NETHER_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_andesite_stairs", "磨かれた安山岩の階段", Material.POLISHED_ANDESITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "diorite_stairs", "閃緑岩の階段", Material.DIORITE_STAIRS), + MineStackObjectByMaterial(BUILDING, "cobbled_deepslate_stairs", "深層岩の丸石の階段", Material.COBBLED_DEEPSLATE_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_deepslate_stairs", "磨かれた深層岩の階段", Material.POLISHED_DEEPSLATE_STAIRS), + MineStackObjectByMaterial(BUILDING, "deepslate_brick_stairs", "深層岩レンガの階段", Material.DEEPSLATE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "deepslate_tile_stairs", "深層岩タイルの階段", Material.DEEPSLATE_TILE_STAIRS), + MineStackObjectByMaterial(BUILDING, "blackstone_stairs", "ブラックストーンの階段", Material.BLACKSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_stairs", "磨かれたブラックストーンの階段", Material.POLISHED_BLACKSTONE_STAIRS), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_brick_stairs", "磨かれたブラックストーンレンガの階段", Material.POLISHED_BLACKSTONE_BRICK_STAIRS), + MineStackObjectByMaterial(BUILDING, "warped_stairs", "歪んだ階段", Material.WARPED_STAIRS), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "brick_wall", "レンガの塀", Material.BRICK_WALL), + List( + MineStackObjectByMaterial(BUILDING, "prismarine_wall", "プリズマリンの塀", Material.PRISMARINE_WALL), + MineStackObjectByMaterial(BUILDING, "red_sandstone_wall", "赤い砂岩の塀", Material.RED_SANDSTONE_WALL), + MineStackObjectByMaterial(BUILDING, "mossy_stone_brick_wall", "苔むした石レンガの塀", Material.MOSSY_STONE_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "granite_wall", "花崗岩の塀", Material.GRANITE_WALL), + MineStackObjectByMaterial(BUILDING, "stone_brick_wall", "石レンガの塀", Material.STONE_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "nether_brick_wall", "ネザーレンガの塀", Material.NETHER_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "andesite_wall", "安山岩の塀", Material.ANDESITE_WALL), + MineStackObjectByMaterial(BUILDING, "red_nether_brick_wall", "赤いネザーレンガの塀", Material.RED_NETHER_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "sandstone_wall", "砂岩の塀", Material.SANDSTONE_WALL), + MineStackObjectByMaterial(BUILDING, "end_stone_brick_wall", "エンドストーンレンガの塀", Material.END_STONE_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "diorite_wall", "閃緑岩の塀", Material.DIORITE_WALL), + MineStackObjectByMaterial(BUILDING, "blackstone_wall", "ブラックストーンの塀", Material.BLACKSTONE_WALL), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_wall", "磨かれたブラックストーンの塀", Material.POLISHED_BLACKSTONE_WALL), + MineStackObjectByMaterial(BUILDING, "polished_blackstone_brick_wall", "磨かれたブラックストーンレンガの塀", Material.POLISHED_BLACKSTONE_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "cobbled_deepslate_wall", "深層岩の丸石の塀", Material.COBBLED_DEEPSLATE_WALL), + MineStackObjectByMaterial(BUILDING, "polished_deepslate_wall", "磨かれた深層岩の塀", Material.POLISHED_DEEPSLATE_WALL), + MineStackObjectByMaterial(BUILDING, "deepslate_brick_wall", "深層岩レンガの塀", Material.DEEPSLATE_BRICK_WALL), + MineStackObjectByMaterial(BUILDING, "deepslate_tile_wall", "深層岩タイルの塀", Material.DEEPSLATE_TILE_WALL), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "fence", "オークのフェンス", Material.OAK_FENCE), + List( + MineStackObjectByMaterial(BUILDING, "spruce_fence", "トウヒのフェンス", Material.SPRUCE_FENCE), + MineStackObjectByMaterial(BUILDING, "birch_fence", "シラカバのフェンス", Material.BIRCH_FENCE), + MineStackObjectByMaterial(BUILDING, "jungle_fence", "ジャングルのフェンス", Material.JUNGLE_FENCE), + MineStackObjectByMaterial(BUILDING, "acacia_fence", "アカシアのフェンス", Material.ACACIA_FENCE), + MineStackObjectByMaterial(BUILDING, "dark_oak_fence", "ダークオークのフェンス", Material.DARK_OAK_FENCE), + MineStackObjectByMaterial(BUILDING, "nether_brick_fence", "ネザーレンガのフェンス", Material.NETHER_BRICK_FENCE), + MineStackObjectByMaterial(BUILDING, "crimson_fence", "真紅のフェンス", Material.CRIMSON_FENCE), + MineStackObjectByMaterial(BUILDING, "warped_fence", "歪んだフェンス", Material.WARPED_FENCE), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "dead_tube_coral_fan", "死んだクダウチワサンゴ", Material.DEAD_TUBE_CORAL_FAN), + List( + MineStackObjectByMaterial(BUILDING, "dead_brain_coral_fan", "死んだノウウチワサンゴ", Material.DEAD_BRAIN_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "dead_bubble_coral_fan", "死んだミズタマウチワサンゴ", Material.DEAD_BUBBLE_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "dead_fire_coral_fan", "死んだミレポラウチワサンゴ", Material.DEAD_FIRE_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "dead_horn_coral_fan", "死んだシカツノウチワサンゴ", Material.DEAD_HORN_CORAL_FAN), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "tube_coral_block", "クダサンゴブロック", Material.TUBE_CORAL_BLOCK), + List( + MineStackObjectByMaterial(BUILDING, "brain_coral_block", "ノウサンゴブロック", Material.BRAIN_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "bubble_coral_block", "ミズタマサンゴブロック", Material.BUBBLE_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "fire_coral_block", "ミレポラサンゴブロック", Material.FIRE_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "horn_coral_block", "シカツノサンゴブロック", Material.HORN_CORAL_BLOCK), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "dead_tube_coral_block", "死んだクダサンゴブロック", Material.DEAD_TUBE_CORAL_BLOCK), + List( + MineStackObjectByMaterial(BUILDING, "dead_brain_coral_block", "死んだノウサンゴブロック", Material.DEAD_BRAIN_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "dead_bubble_coral_block", "死んだミズタマサンゴブロック", Material.DEAD_BUBBLE_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "dead_fire_coral_block", "死んだミレポラサンゴブロック", Material.DEAD_FIRE_CORAL_BLOCK), + MineStackObjectByMaterial(BUILDING, "dead_horn_coral_block", "死んだシカツノサンゴブロック", Material.DEAD_HORN_CORAL_BLOCK), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "tube_coral", "クダサンゴ", Material.TUBE_CORAL), + List( + MineStackObjectByMaterial(BUILDING, "brain_coral", "ノウサンゴ", Material.BRAIN_CORAL), + MineStackObjectByMaterial(BUILDING, "bubble_coral", "ミズタマサンゴ", Material.BUBBLE_CORAL), + MineStackObjectByMaterial(BUILDING, "fire_coral", "ミレポラサンゴ", Material.FIRE_CORAL), + MineStackObjectByMaterial(BUILDING, "horn_coral", "シカツノサンゴ", Material.HORN_CORAL), + MineStackObjectByMaterial(BUILDING, "dead_brain_coral", "死んだノウサンゴ", Material.DEAD_BRAIN_CORAL), + MineStackObjectByMaterial(BUILDING, "dead_bubble_coral", "死んだミズタマサンゴ", Material.DEAD_BUBBLE_CORAL), + MineStackObjectByMaterial(BUILDING, "dead_fire_coral", "死んだミレポラサンゴ", Material.DEAD_FIRE_CORAL), + MineStackObjectByMaterial(BUILDING, "dead_horn_coral", "死んだシカツノサンゴ", Material.DEAD_HORN_CORAL), + MineStackObjectByMaterial(BUILDING, "dead_tube_coral", "死んだクダサンゴ", Material.DEAD_TUBE_CORAL), + MineStackObjectByMaterial(BUILDING, "tube_coral_fan", "クダウチワサンゴ", Material.TUBE_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "brain_coral_fan", "ノウウチワサンゴ", Material.BRAIN_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "bubble_coral_fan", "ミズタマウチワサンゴ", Material.BUBBLE_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "fire_coral_fan", "ミレポラウチワサンゴ", Material.FIRE_CORAL_FAN), + MineStackObjectByMaterial(BUILDING, "horn_coral_fan", "シカツノウチワサンゴ", Material.HORN_CORAL_FAN), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "flower_banner_pattern", "旗の模様", Material.FLOWER_BANNER_PATTERN), + List( + MineStackObjectByMaterial(BUILDING, "creeper_banner_pattern", "旗の模様", Material.CREEPER_BANNER_PATTERN), + MineStackObjectByMaterial(BUILDING, "skull_banner_pattern", "旗の模様", Material.SKULL_BANNER_PATTERN), + MineStackObjectByMaterial(BUILDING, "mojang_banner_pattern", "旗の模様", Material.MOJANG_BANNER_PATTERN), + MineStackObjectByMaterial(BUILDING, "globe_banner_pattern", "旗の模様", Material.GLOBE_BANNER_PATTERN), + MineStackObjectByMaterial(BUILDING, "piglin_banner_pattern", "旗の模様", Material.PIGLIN_BANNER_PATTERN), ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "stained_clay", "白色のテラコッタ", Material.STAINED_CLAY, 0), - List( - MineStackObjectByMaterial(BUILDING, "stained_clay1", "橙色のテラコッタ", Material.STAINED_CLAY, 1), - MineStackObjectByMaterial(BUILDING, "stained_clay2", "赤紫色のテラコッタ", Material.STAINED_CLAY, 2), - MineStackObjectByMaterial(BUILDING, "stained_clay3", "空色のテラコッタ", Material.STAINED_CLAY, 3), - MineStackObjectByMaterial(BUILDING, "stained_clay4", "黄色のテラコッタ", Material.STAINED_CLAY, 4), - MineStackObjectByMaterial(BUILDING, "stained_clay5", "黄緑色のテラコッタ", Material.STAINED_CLAY, 5), - MineStackObjectByMaterial(BUILDING, "stained_clay6", "桃色のテラコッタ", Material.STAINED_CLAY, 6), - MineStackObjectByMaterial(BUILDING, "stained_clay7", "灰色のテラコッタ", Material.STAINED_CLAY, 7), - MineStackObjectByMaterial(BUILDING, "stained_clay8", "薄灰色のテラコッタ", Material.STAINED_CLAY, 8), - MineStackObjectByMaterial(BUILDING, "stained_clay9", "青緑色のテラコッタ", Material.STAINED_CLAY, 9), - MineStackObjectByMaterial(BUILDING, "stained_clay10", "紫色のテラコッタ", Material.STAINED_CLAY, 10), - MineStackObjectByMaterial(BUILDING, "stained_clay11", "青色のテラコッタ", Material.STAINED_CLAY, 11), - MineStackObjectByMaterial(BUILDING, "stained_clay12", "茶色のテラコッタ", Material.STAINED_CLAY, 12), - MineStackObjectByMaterial(BUILDING, "stained_clay13", "緑色のテラコッタ", Material.STAINED_CLAY, 13), - MineStackObjectByMaterial(BUILDING, "stained_clay14", "赤色のテラコッタ", Material.STAINED_CLAY, 14), - MineStackObjectByMaterial(BUILDING, "stained_clay15", "黒色のテラコッタ", Material.STAINED_CLAY, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "white_banner", "白色の旗", Material.WHITE_BANNER), + List( + MineStackObjectByMaterial(BUILDING, "orange_banner", "橙色の旗", Material.ORANGE_BANNER), + MineStackObjectByMaterial(BUILDING, "magenta_banner", "赤紫色の旗", Material.MAGENTA_BANNER), + MineStackObjectByMaterial(BUILDING, "light_blue_banner", "空色の旗", Material.LIGHT_BLUE_BANNER), + MineStackObjectByMaterial(BUILDING, "yellow_banner", "黄色の旗", Material.YELLOW_BANNER), + MineStackObjectByMaterial(BUILDING, "lime_banner", "黄緑色の旗", Material.LIME_BANNER), + MineStackObjectByMaterial(BUILDING, "pink_banner", "桃色の旗", Material.PINK_BANNER), + MineStackObjectByMaterial(BUILDING, "gray_banner", "灰色の旗", Material.GRAY_BANNER), + MineStackObjectByMaterial(BUILDING, "light_gray_banner", "薄灰色の旗", Material.LIGHT_GRAY_BANNER), + MineStackObjectByMaterial(BUILDING, "cyan_banner", "青緑色の旗", Material.CYAN_BANNER), + MineStackObjectByMaterial(BUILDING, "purple_banner", "紫色の旗", Material.PURPLE_BANNER), + MineStackObjectByMaterial(BUILDING, "blue_banner", "青色の旗", Material.BLUE_BANNER), + MineStackObjectByMaterial(BUILDING, "brown_banner", "茶色の旗", Material.BROWN_BANNER), + MineStackObjectByMaterial(BUILDING, "green_banner", "緑色の旗", Material.GREEN_BANNER), + MineStackObjectByMaterial(BUILDING, "red_banner", "赤色の旗", Material.RED_BANNER), + MineStackObjectByMaterial(BUILDING, "black_banner", "黒色の旗", Material.BLACK_BANNER), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "sign", "看板", Material.OAK_SIGN), + List( + MineStackObjectByMaterial(BUILDING, "spruce_sign", "トウヒの看板", Material.SPRUCE_SIGN), + MineStackObjectByMaterial(BUILDING, "birch_sign", "シラカバの看板", Material.BIRCH_SIGN), + MineStackObjectByMaterial(BUILDING, "jungle_sign", "ジャングルの看板", Material.JUNGLE_SIGN), + MineStackObjectByMaterial(BUILDING, "acacia_sign", "アカシアの看板", Material.ACACIA_SIGN), + MineStackObjectByMaterial(BUILDING, "dark_oak_sign", "ダークオークの看板", Material.DARK_OAK_SIGN), + MineStackObjectByMaterial(BUILDING, "crimson_sign", "真紅の看板", Material.CRIMSON_SIGN), + MineStackObjectByMaterial(BUILDING, "warped_sign", "歪んだ看板", Material.WARPED_SIGN), ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "concrete", "白色のコンクリート", Material.CONCRETE, 0), - List( - MineStackObjectByMaterial(BUILDING, "concrete1", "橙色のコンクリート", Material.CONCRETE, 1), - MineStackObjectByMaterial(BUILDING, "concrete2", "赤紫色のコンクリート", Material.CONCRETE, 2), - MineStackObjectByMaterial(BUILDING, "concrete3", "空色のコンクリート", Material.CONCRETE, 3), - MineStackObjectByMaterial(BUILDING, "concrete4", "黄色のコンクリート", Material.CONCRETE, 4), - MineStackObjectByMaterial(BUILDING, "concrete5", "黄緑色のコンクリート", Material.CONCRETE, 5), - MineStackObjectByMaterial(BUILDING, "concrete6", "桃色のコンクリート", Material.CONCRETE, 6), - MineStackObjectByMaterial(BUILDING, "concrete7", "灰色のコンクリート", Material.CONCRETE, 7), - MineStackObjectByMaterial(BUILDING, "concrete8", "薄灰色のコンクリート", Material.CONCRETE, 8), - MineStackObjectByMaterial(BUILDING, "concrete9", "青緑色のコンクリート", Material.CONCRETE, 9), - MineStackObjectByMaterial(BUILDING, "concrete10", "紫色のコンクリート", Material.CONCRETE, 10), - MineStackObjectByMaterial(BUILDING, "concrete11", "青色のコンクリート", Material.CONCRETE, 11), - MineStackObjectByMaterial(BUILDING, "concrete12", "茶色のコンクリート", Material.CONCRETE, 12), - MineStackObjectByMaterial(BUILDING, "concrete13", "緑色のコンクリート", Material.CONCRETE, 13), - MineStackObjectByMaterial(BUILDING, "concrete14", "赤色のコンクリート", Material.CONCRETE, 14), - MineStackObjectByMaterial(BUILDING, "concrete15", "黒色のコンクリート", Material.CONCRETE, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "candle", "ろうそく", Material.CANDLE), + List( + MineStackObjectByMaterial(BUILDING, "white_candle", "白色のろうそく", Material.WHITE_CANDLE), + MineStackObjectByMaterial(BUILDING, "orange_candle", "橙色のろうそく", Material.ORANGE_CANDLE), + MineStackObjectByMaterial(BUILDING, "magenta_candle", "赤紫色のろうそく", Material.MAGENTA_CANDLE), + MineStackObjectByMaterial(BUILDING, "light_blue_candle", "空色のろうそく", Material.LIGHT_BLUE_CANDLE), + MineStackObjectByMaterial(BUILDING, "yellow_candle", "黄色のろうそく", Material.YELLOW_CANDLE), + MineStackObjectByMaterial(BUILDING, "lime_candle", "黄緑色のろうそく", Material.LIME_CANDLE), + MineStackObjectByMaterial(BUILDING, "pink_candle", "桃色のろうそく", Material.PINK_CANDLE), + MineStackObjectByMaterial(BUILDING, "gray_candle", "灰色のろうそく", Material.GRAY_CANDLE), + MineStackObjectByMaterial(BUILDING, "light_gray_candle", "薄灰色のろうそく", Material.LIGHT_GRAY_CANDLE), + MineStackObjectByMaterial(BUILDING, "cyan_candle", "青緑色のろうそく", Material.CYAN_CANDLE), + MineStackObjectByMaterial(BUILDING, "purple_candle", "紫色のろうそく", Material.PURPLE_CANDLE), + MineStackObjectByMaterial(BUILDING, "blue_candle", "青色のろうそく", Material.BLUE_CANDLE), + MineStackObjectByMaterial(BUILDING, "brown_candle", "茶色のろうそく", Material.BROWN_CANDLE), + MineStackObjectByMaterial(BUILDING, "green_candle", "緑色のろうそく", Material.GREEN_CANDLE), + MineStackObjectByMaterial(BUILDING, "red_candle", "赤色のろうそく", Material.RED_CANDLE), + MineStackObjectByMaterial(BUILDING, "black_candle", "黒色のろうそく", Material.BLACK_CANDLE), ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "concrete_powder", "白色のコンクリートパウダー", Material.CONCRETE_POWDER, 0), - List( - MineStackObjectByMaterial(BUILDING, "concrete_powder1", "橙色のコンクリートパウダー", Material.CONCRETE_POWDER, 1), - MineStackObjectByMaterial(BUILDING, "concrete_powder2", "赤紫色のコンクリートパウダー", Material.CONCRETE_POWDER, 2), - MineStackObjectByMaterial(BUILDING, "concrete_powder3", "空色のコンクリートパウダー", Material.CONCRETE_POWDER, 3), - MineStackObjectByMaterial(BUILDING, "concrete_powder4", "黄色のコンクリートパウダー", Material.CONCRETE_POWDER, 4), - MineStackObjectByMaterial(BUILDING, "concrete_powder5", "黄緑色のコンクリートパウダー", Material.CONCRETE_POWDER, 5), - MineStackObjectByMaterial(BUILDING, "concrete_powder6", "桃色のコンクリートパウダー", Material.CONCRETE_POWDER, 6), - MineStackObjectByMaterial(BUILDING, "concrete_powder7", "灰色のコンクリートパウダー", Material.CONCRETE_POWDER, 7), - MineStackObjectByMaterial(BUILDING, "concrete_powder8", "薄灰色のコンクリートパウダー", Material.CONCRETE_POWDER, 8), - MineStackObjectByMaterial(BUILDING, "concrete_powder9", "青緑色のコンクリートパウダー", Material.CONCRETE_POWDER, 9), - MineStackObjectByMaterial(BUILDING, "concrete_powder10", "紫色のコンクリートパウダー", Material.CONCRETE_POWDER, 10), - MineStackObjectByMaterial(BUILDING, "concrete_powder11", "青色のコンクリートパウダー", Material.CONCRETE_POWDER, 11), - MineStackObjectByMaterial(BUILDING, "concrete_powder12", "茶色のコンクリートパウダー", Material.CONCRETE_POWDER, 12), - MineStackObjectByMaterial(BUILDING, "concrete_powder13", "緑色のコンクリートパウダー", Material.CONCRETE_POWDER, 13), - MineStackObjectByMaterial(BUILDING, "concrete_powder14", "赤色のコンクリートパウダー", Material.CONCRETE_POWDER, 14), - MineStackObjectByMaterial(BUILDING, "concrete_powder15", "黒色のコンクリートパウダー", Material.CONCRETE_POWDER, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "bed", "白色のベッド", Material.WHITE_BED), + List( + MineStackObjectByMaterial(BUILDING, "bed_1", "橙色のベッド", Material.ORANGE_BED), + MineStackObjectByMaterial(BUILDING, "bed_2", "赤紫色のベッド", Material.MAGENTA_BED), + MineStackObjectByMaterial(BUILDING, "bed_3", "空色のベッド", Material.LIGHT_BLUE_BED), + MineStackObjectByMaterial(BUILDING, "bed_4", "黄色のベッド", Material.YELLOW_BED), + MineStackObjectByMaterial(BUILDING, "bed_5", "黄緑色のベッド", Material.LIME_BED), + MineStackObjectByMaterial(BUILDING, "bed_6", "桃色のベッド", Material.PINK_BED), + MineStackObjectByMaterial(BUILDING, "bed_7", "灰色のベッド", Material.GRAY_BED), + MineStackObjectByMaterial(BUILDING, "bed_8", "薄灰色のベッド", Material.LIGHT_GRAY_BED), + MineStackObjectByMaterial(BUILDING, "bed_9", "青緑色のベッド", Material.CYAN_BED), + MineStackObjectByMaterial(BUILDING, "bed_10", "紫色のベッド", Material.PURPLE_BED), + MineStackObjectByMaterial(BUILDING, "bed_11", "青色のベッド", Material.BLUE_BED), + MineStackObjectByMaterial(BUILDING, "bed_12", "茶色のベッド", Material.BROWN_BED), + MineStackObjectByMaterial(BUILDING, "bed_13", "緑色のベッド", Material.GREEN_BED), + MineStackObjectByMaterial(BUILDING, "bed_14", "赤色のベッド", Material.RED_BED), + MineStackObjectByMaterial(BUILDING, "bed_15", "黒色のベッド", Material.BLACK_BED) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "white_glazed_terracotta", "白色の彩釉テラコッタ", Material.WHITE_GLAZED_TERRACOTTA, 0), - List( - MineStackObjectByMaterial(BUILDING, "orange_glazed_terracotta", "橙色の彩釉テラコッタ", Material.ORANGE_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "magenta_glazed_terracotta", "赤紫色の彩釉テラコッタ", Material.MAGENTA_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "light_blue_glazed_terracotta", "空色の彩釉テラコッタ", Material.LIGHT_BLUE_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "yellow_glazed_terracotta", "黄色の彩釉テラコッタ", Material.YELLOW_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "lime_glazed_terracotta", "黄緑色の彩釉テラコッタ", Material.LIME_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "pink_glazed_terracotta", "桃色の彩釉テラコッタ", Material.PINK_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "gray_glazed_terracotta", "灰色の彩釉テラコッタ", Material.GRAY_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "silver_glazed_terracotta", "薄灰色の彩釉テラコッタ", Material.SILVER_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "cyan_glazed_terracotta", "青緑色の彩釉テラコッタ", Material.CYAN_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "purple_glazed_terracotta", "紫色の彩釉テラコッタ", Material.PURPLE_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "blue_glazed_terracotta", "青色の彩釉テラコッタ", Material.BLUE_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "brown_glazed_terracotta", "茶色の彩釉テラコッタ", Material.BROWN_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "green_glazed_terracotta", "緑色の彩釉テラコッタ", Material.GREEN_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "red_glazed_terracotta", "赤色の彩釉テラコッタ", Material.RED_GLAZED_TERRACOTTA, 0), - MineStackObjectByMaterial(BUILDING, "black_glazed_terracotta", "黒色の彩釉テラコッタ", Material.BLACK_GLAZED_TERRACOTTA, 0) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "hard_clay", "テラコッタ", Material.TERRACOTTA), + List( + MineStackObjectByMaterial(BUILDING, "stained_clay", "白色のテラコッタ", Material.WHITE_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay1", "橙色のテラコッタ", Material.ORANGE_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay2", "赤紫色のテラコッタ", Material.MAGENTA_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay3", "空色のテラコッタ", Material.LIGHT_BLUE_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay4", "黄色のテラコッタ", Material.YELLOW_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay5", "黄緑色のテラコッタ", Material.LIME_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay6", "桃色のテラコッタ", Material.PINK_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay7", "灰色のテラコッタ", Material.GRAY_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay8", "薄灰色のテラコッタ", Material.LIGHT_GRAY_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay9", "青緑色のテラコッタ", Material.CYAN_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay10", "紫色のテラコッタ", Material.PURPLE_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay11", "青色のテラコッタ", Material.BLUE_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay12", "茶色のテラコッタ", Material.BROWN_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay13", "緑色のテラコッタ", Material.GREEN_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay14", "赤色のテラコッタ", Material.RED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING, "stained_clay15", "黒色のテラコッタ", Material.BLACK_TERRACOTTA) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "wool_0", "白色の羊毛", Material.WOOL, 0), - List( - MineStackObjectByMaterial(BUILDING, "wool_1", "橙色の羊毛", Material.WOOL, 1), - MineStackObjectByMaterial(BUILDING, "wool_2", "赤紫色の羊毛", Material.WOOL, 2), - MineStackObjectByMaterial(BUILDING, "wool_3", "空色の羊毛", Material.WOOL, 3), - MineStackObjectByMaterial(BUILDING, "wool_4", "黄色の羊毛", Material.WOOL, 4), - MineStackObjectByMaterial(BUILDING, "wool_5", "黄緑色の羊毛", Material.WOOL, 5), - MineStackObjectByMaterial(BUILDING, "wool_6", "桃色の羊毛", Material.WOOL, 6), - MineStackObjectByMaterial(BUILDING, "wool_7", "灰色の羊毛", Material.WOOL, 7), - MineStackObjectByMaterial(BUILDING, "wool_8", "薄灰色の羊毛", Material.WOOL, 8), - MineStackObjectByMaterial(BUILDING, "wool_9", "青緑色の羊毛", Material.WOOL, 9), - MineStackObjectByMaterial(BUILDING, "wool_10", "紫色の羊毛", Material.WOOL, 10), - MineStackObjectByMaterial(BUILDING, "wool_11", "青色の羊毛", Material.WOOL, 11), - MineStackObjectByMaterial(BUILDING, "wool_12", "茶色の羊毛", Material.WOOL, 12), - MineStackObjectByMaterial(BUILDING, "wool_13", "緑色の羊毛", Material.WOOL, 13), - MineStackObjectByMaterial(BUILDING, "wool_14", "赤色の羊毛", Material.WOOL, 14), - MineStackObjectByMaterial(BUILDING, "wool_15", "黒色の羊毛", Material.WOOL, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "concrete", "白色のコンクリート", Material.WHITE_CONCRETE), + List( + MineStackObjectByMaterial(BUILDING, "concrete1", "橙色のコンクリート", Material.ORANGE_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete2", "赤紫色のコンクリート", Material.MAGENTA_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete3", "空色のコンクリート", Material.LIGHT_BLUE_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete4", "黄色のコンクリート", Material.YELLOW_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete5", "黄緑色のコンクリート", Material.LIME_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete6", "桃色のコンクリート", Material.PINK_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete7", "灰色のコンクリート", Material.GRAY_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete8", "薄灰色のコンクリート", Material.LIGHT_GRAY_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete9", "青緑色のコンクリート", Material.CYAN_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete10", "紫色のコンクリート", Material.PURPLE_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete11", "青色のコンクリート", Material.BLUE_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete12", "茶色のコンクリート", Material.BROWN_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete13", "緑色のコンクリート", Material.GREEN_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete14", "赤色のコンクリート", Material.RED_CONCRETE), + MineStackObjectByMaterial(BUILDING, "concrete15", "黒色のコンクリート", Material.BLACK_CONCRETE) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "carpet_0", "白色のカーペット", Material.CARPET, 0), - List( - MineStackObjectByMaterial(BUILDING, "carpet_1", "橙色のカーペット", Material.CARPET, 1), - MineStackObjectByMaterial(BUILDING, "carpet_2", "赤紫色のカーペット", Material.CARPET, 2), - MineStackObjectByMaterial(BUILDING, "carpet_3", "空色のカーペット", Material.CARPET, 3), - MineStackObjectByMaterial(BUILDING, "carpet_4", "黄色のカーペット", Material.CARPET, 4), - MineStackObjectByMaterial(BUILDING, "carpet_5", "黄緑色のカーペット", Material.CARPET, 5), - MineStackObjectByMaterial(BUILDING, "carpet_6", "桃色のカーペット", Material.CARPET, 6), - MineStackObjectByMaterial(BUILDING, "carpet_7", "灰色のカーペット", Material.CARPET, 7), - MineStackObjectByMaterial(BUILDING, "carpet_8", "薄灰色のカーペット", Material.CARPET, 8), - MineStackObjectByMaterial(BUILDING, "carpet_9", "青緑色のカーペット", Material.CARPET, 9), - MineStackObjectByMaterial(BUILDING, "carpet_10", "紫色のカーペット", Material.CARPET, 10), - MineStackObjectByMaterial(BUILDING, "carpet_11", "青色のカーペット", Material.CARPET, 11), - MineStackObjectByMaterial(BUILDING, "carpet_12", "茶色のカーペット", Material.CARPET, 12), - MineStackObjectByMaterial(BUILDING, "carpet_13", "緑色のカーペット", Material.CARPET, 13), - MineStackObjectByMaterial(BUILDING, "carpet_14", "赤色のカーペット", Material.CARPET, 14), - MineStackObjectByMaterial(BUILDING, "carpet_15", "黒色のカーペット", Material.CARPET, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "concrete_powder", "白色のコンクリートパウダー", Material.WHITE_CONCRETE_POWDER), + List( + MineStackObjectByMaterial(BUILDING, "concrete_powder1", "橙色のコンクリートパウダー", Material.ORANGE_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING, "concrete_powder2", "赤紫色のコンクリートパウダー", Material.MAGENTA_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING, "concrete_powder3", "空色のコンクリートパウダー", Material.LIGHT_BLUE_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING, "concrete_powder4", "黄色のコンクリートパウダー", Material.YELLOW_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING, "concrete_powder5", "黄緑色のコンクリートパウダー", Material.LIME_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder6","桃色のコンクリートパウダー",Material.PINK_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder7","灰色のコンクリートパウダー",Material.GRAY_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder8","薄灰色のコンクリートパウダー",Material.LIGHT_GRAY_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder9","青緑色のコンクリートパウダー",Material.CYAN_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder10","紫色のコンクリートパウダー",Material.PURPLE_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder11","青色のコンクリートパウダー",Material.BLUE_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder12","茶色のコンクリートパウダー",Material.BROWN_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder13","緑色のコンクリートパウダー",Material.GREEN_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder14","赤色のコンクリートパウダー",Material.RED_CONCRETE_POWDER), + MineStackObjectByMaterial(BUILDING,"concrete_powder15","黒色のコンクリートパウダー",Material.BLACK_CONCRETE_POWDER) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "glass", "ガラス", Material.GLASS, 0), - List( - MineStackObjectByMaterial(BUILDING, "stained_glass_0", "白色の色付きガラス", Material.STAINED_GLASS, 0), - MineStackObjectByMaterial(BUILDING, "stained_glass_1", "橙色の色付きガラス", Material.STAINED_GLASS, 1), - MineStackObjectByMaterial(BUILDING, "stained_glass_2", "赤紫色の色付きガラス", Material.STAINED_GLASS, 2), - MineStackObjectByMaterial(BUILDING, "stained_glass_3", "空色の色付きガラス", Material.STAINED_GLASS, 3), - MineStackObjectByMaterial(BUILDING, "stained_glass_4", "黄色の色付きガラス", Material.STAINED_GLASS, 4), - MineStackObjectByMaterial(BUILDING, "stained_glass_5", "黄緑色の色付きガラス", Material.STAINED_GLASS, 5), - MineStackObjectByMaterial(BUILDING, "stained_glass_6", "桃色の色付きガラス", Material.STAINED_GLASS, 6), - MineStackObjectByMaterial(BUILDING, "stained_glass_7", "灰色の色付きガラス", Material.STAINED_GLASS, 7), - MineStackObjectByMaterial(BUILDING, "stained_glass_8", "薄灰色の色付きガラス", Material.STAINED_GLASS, 8), - MineStackObjectByMaterial(BUILDING, "stained_glass_9", "青緑色の色付きガラス", Material.STAINED_GLASS, 9), - MineStackObjectByMaterial(BUILDING, "stained_glass_10", "紫色の色付きガラス", Material.STAINED_GLASS, 10), - MineStackObjectByMaterial(BUILDING, "stained_glass_11", "青色の色付きガラス", Material.STAINED_GLASS, 11), - MineStackObjectByMaterial(BUILDING, "stained_glass_12", "茶色の色付きガラス", Material.STAINED_GLASS, 12), - MineStackObjectByMaterial(BUILDING, "stained_glass_13", "緑色の色付きガラス", Material.STAINED_GLASS, 13), - MineStackObjectByMaterial(BUILDING, "stained_glass_14", "赤色の色付きガラス", Material.STAINED_GLASS, 14), - MineStackObjectByMaterial(BUILDING, "stained_glass_15", "黒色の色付きガラス", Material.STAINED_GLASS, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING,"white_glazed_terracotta","白色の彩釉テラコッタ",Material.WHITE_GLAZED_TERRACOTTA), + List( + MineStackObjectByMaterial(BUILDING,"orange_glazed_terracotta","橙色の彩釉テラコッタ",Material.ORANGE_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"magenta_glazed_terracotta","赤紫色の彩釉テラコッタ",Material.MAGENTA_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"light_blue_glazed_terracotta","空色の彩釉テラコッタ",Material.LIGHT_BLUE_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"yellow_glazed_terracotta","黄色の彩釉テラコッタ",Material.YELLOW_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"lime_glazed_terracotta","黄緑色の彩釉テラコッタ",Material.LIME_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"pink_glazed_terracotta","桃色の彩釉テラコッタ",Material.PINK_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"gray_glazed_terracotta","灰色の彩釉テラコッタ",Material.GRAY_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"silver_glazed_terracotta","薄灰色の彩釉テラコッタ",Material.LIGHT_GRAY_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"cyan_glazed_terracotta","青緑色の彩釉テラコッタ",Material.CYAN_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"purple_glazed_terracotta","紫色の彩釉テラコッタ",Material.PURPLE_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"blue_glazed_terracotta","青色の彩釉テラコッタ",Material.BLUE_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"brown_glazed_terracotta","茶色の彩釉テラコッタ",Material.BROWN_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"green_glazed_terracotta","緑色の彩釉テラコッタ",Material.GREEN_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"red_glazed_terracotta","赤色の彩釉テラコッタ",Material.RED_GLAZED_TERRACOTTA), + MineStackObjectByMaterial(BUILDING,"black_glazed_terracotta","黒色の彩釉テラコッタ",Material.BLACK_GLAZED_TERRACOTTA) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "glass_panel", "板ガラス", Material.THIN_GLASS, 0), - List( - MineStackObjectByMaterial(BUILDING, "glass_panel_0", "白色の色付きガラス板", Material.STAINED_GLASS_PANE, 0), - MineStackObjectByMaterial(BUILDING, "glass_panel_1", "橙色の色付きガラス板", Material.STAINED_GLASS_PANE, 1), - MineStackObjectByMaterial(BUILDING, "glass_panel_2", "赤紫色の色付きガラス板", Material.STAINED_GLASS_PANE, 2), - MineStackObjectByMaterial(BUILDING, "glass_panel_3", "空色の色付きガラス板", Material.STAINED_GLASS_PANE, 3), - MineStackObjectByMaterial(BUILDING, "glass_panel_4", "黄色の色付きガラス板", Material.STAINED_GLASS_PANE, 4), - MineStackObjectByMaterial(BUILDING, "glass_panel_5", "黄緑色の色付きガラス板", Material.STAINED_GLASS_PANE, 5), - MineStackObjectByMaterial(BUILDING, "glass_panel_6", "桃色の色付きガラス板", Material.STAINED_GLASS_PANE, 6), - MineStackObjectByMaterial(BUILDING, "glass_panel_7", "灰色の色付きガラス板", Material.STAINED_GLASS_PANE, 7), - MineStackObjectByMaterial(BUILDING, "glass_panel_8", "薄灰色の色付きガラス板", Material.STAINED_GLASS_PANE, 8), - MineStackObjectByMaterial(BUILDING, "glass_panel_9", "青緑色の色付きガラス板", Material.STAINED_GLASS_PANE, 9), - MineStackObjectByMaterial(BUILDING, "glass_panel_10", "紫色の色付きガラス板", Material.STAINED_GLASS_PANE, 10), - MineStackObjectByMaterial(BUILDING, "glass_panel_11", "青色の色付きガラス板", Material.STAINED_GLASS_PANE, 11), - MineStackObjectByMaterial(BUILDING, "glass_panel_12", "茶色の色付きガラス板", Material.STAINED_GLASS_PANE, 12), - MineStackObjectByMaterial(BUILDING, "glass_panel_13", "緑色の色付きガラス板", Material.STAINED_GLASS_PANE, 13), - MineStackObjectByMaterial(BUILDING, "glass_panel_14", "赤色の色付きガラス板", Material.STAINED_GLASS_PANE, 14), - MineStackObjectByMaterial(BUILDING, "glass_panel_15", "黒色の色付きガラス板", Material.STAINED_GLASS_PANE, 15) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "wool_0", "白色の羊毛", Material.WHITE_WOOL), + List( + MineStackObjectByMaterial(BUILDING, "wool_1", "橙色の羊毛", Material.ORANGE_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_2", "赤紫色の羊毛", Material.MAGENTA_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_3", "空色の羊毛", Material.LIGHT_BLUE_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_4", "黄色の羊毛", Material.YELLOW_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_5", "黄緑色の羊毛", Material.LIME_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_6", "桃色の羊毛", Material.PINK_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_7", "灰色の羊毛", Material.GRAY_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_8", "薄灰色の羊毛", Material.LIGHT_GRAY_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_9", "青緑色の羊毛", Material.CYAN_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_10", "紫色の羊毛", Material.PURPLE_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_11", "青色の羊毛", Material.BLUE_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_12", "茶色の羊毛", Material.BROWN_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_13", "緑色の羊毛", Material.GREEN_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_14", "赤色の羊毛", Material.RED_WOOL), + MineStackObjectByMaterial(BUILDING, "wool_15", "黒色の羊毛", Material.BLACK_WOOL) ) ), - MineStackObjectWithColorVariants( - MineStackObjectByMaterial(BUILDING, "dye_1", "赤色の染料", Material.INK_SACK, 1), - List( - MineStackObjectByMaterial(BUILDING, "dye_2", "緑色の染料", Material.INK_SACK, 2), - MineStackObjectByMaterial(BUILDING, "dye_5", "紫色の染料", Material.INK_SACK, 5), - MineStackObjectByMaterial(BUILDING, "dye_6", "青緑色の染料", Material.INK_SACK, 6), - MineStackObjectByMaterial(BUILDING, "dye_7", "薄灰色の染料", Material.INK_SACK, 7), - MineStackObjectByMaterial(BUILDING, "dye_8", "灰色の染料", Material.INK_SACK, 8), - MineStackObjectByMaterial(BUILDING, "dye_9", "桃色の染料", Material.INK_SACK, 9), - MineStackObjectByMaterial(BUILDING, "dye_10", "黄緑色の染料", Material.INK_SACK, 10), - MineStackObjectByMaterial(BUILDING, "dye_11", "黄色の染料", Material.INK_SACK, 11), - MineStackObjectByMaterial(BUILDING, "dye_12", "空色の染料", Material.INK_SACK, 12), - MineStackObjectByMaterial(BUILDING, "dye_13", "赤紫色の染料", Material.INK_SACK, 13), - MineStackObjectByMaterial(BUILDING, "dye_14", "橙色の染料", Material.INK_SACK, 14), - MineStackObjectByMaterial(BUILDING, "dye_15", "骨粉", Material.INK_SACK, 15), - MineStackObjectByMaterial(BUILDING, "ink_sack0", "イカスミ", Material.INK_SACK, 0) + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "carpet_0", "白色のカーペット", Material.WHITE_CARPET), + List( + MineStackObjectByMaterial(BUILDING, "carpet_1", "橙色のカーペット", Material.ORANGE_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_2", "赤紫色のカーペット", Material.MAGENTA_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_3", "空色のカーペット", Material.LIGHT_BLUE_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_4", "黄色のカーペット", Material.YELLOW_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_5", "黄緑色のカーペット", Material.LIME_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_6", "桃色のカーペット", Material.PINK_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_7", "灰色のカーペット", Material.GRAY_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_8", "薄灰色のカーペット", Material.LIGHT_GRAY_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_9", "青緑色のカーペット", Material.CYAN_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_10", "紫色のカーペット", Material.PURPLE_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_11", "青色のカーペット", Material.BLUE_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_12", "茶色のカーペット", Material.BROWN_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_13", "緑色のカーペット", Material.GREEN_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_14", "赤色のカーペット", Material.RED_CARPET), + MineStackObjectByMaterial(BUILDING, "carpet_15", "黒色のカーペット", Material.BLACK_CARPET) + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "glass", "ガラス",Material.GLASS), + List( + MineStackObjectByMaterial(BUILDING, "stained_glass_0", "白色の色付きガラス", Material.WHITE_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_1", "橙色の色付きガラス", Material.ORANGE_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_2", "赤紫色の色付きガラス", Material.MAGENTA_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_3", "空色の色付きガラス", Material.LIGHT_BLUE_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_4", "黄色の色付きガラス", Material.YELLOW_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_5", "黄緑色の色付きガラス", Material.LIME_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_6", "桃色の色付きガラス", Material.PINK_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_7", "灰色の色付きガラス", Material.GRAY_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_8", "薄灰色の色付きガラス", Material.LIGHT_GRAY_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_9", "青緑色の色付きガラス", Material.CYAN_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_10", "紫色の色付きガラス", Material.PURPLE_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_11", "青色の色付きガラス", Material.BLUE_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_12", "茶色の色付きガラス", Material.BROWN_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_13", "緑色の色付きガラス", Material.GREEN_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_14", "赤色の色付きガラス", Material.RED_STAINED_GLASS), + MineStackObjectByMaterial(BUILDING, "stained_glass_15", "黒色の色付きガラス", Material.BLACK_STAINED_GLASS) + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "glass_panel", "ガラス板", Material.GLASS_PANE), + List( + MineStackObjectByMaterial(BUILDING,"glass_panel_0","白色の色付きガラス板",Material.WHITE_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_1","橙色の色付きガラス板",Material.ORANGE_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_2","赤紫色の色付きガラス板",Material.MAGENTA_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_3","空色の色付きガラス板",Material.LIGHT_BLUE_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_4","黄色の色付きガラス板",Material.YELLOW_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_5","黄緑色の色付きガラス板",Material.LIME_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_6","桃色の色付きガラス板",Material.PINK_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_7","灰色の色付きガラス板",Material.GRAY_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_8","薄灰色の色付きガラス板",Material.LIGHT_GRAY_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_9","青緑色の色付きガラス板",Material.CYAN_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_10","紫色の色付きガラス板",Material.PURPLE_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_11","青色の色付きガラス板",Material.BLUE_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_12","茶色の色付きガラス板",Material.BROWN_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_13","緑色の色付きガラス板",Material.GREEN_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_14","赤色の色付きガラス板",Material.RED_STAINED_GLASS_PANE), + MineStackObjectByMaterial(BUILDING,"glass_panel_15","黒色の色付きガラス板",Material.BLACK_STAINED_GLASS_PANE) + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(BUILDING, "dye_1", "赤色の染料", Material.RED_DYE), + List( + MineStackObjectByMaterial(BUILDING, "dye_2", "緑色の染料", Material.GREEN_DYE), + MineStackObjectByMaterial(BUILDING, "dye_5", "紫色の染料", Material.PURPLE_DYE), + MineStackObjectByMaterial(BUILDING, "dye_6", "青緑色の染料", Material.CYAN_DYE), + MineStackObjectByMaterial(BUILDING, "dye_7", "薄灰色の染料", Material.LIGHT_GRAY_DYE), + MineStackObjectByMaterial(BUILDING, "dye_8", "灰色の染料", Material.GRAY_DYE), + MineStackObjectByMaterial(BUILDING, "dye_9", "桃色の染料", Material.PINK_DYE), + MineStackObjectByMaterial(BUILDING, "dye_10", "黄緑色の染料", Material.LIME_DYE), + MineStackObjectByMaterial(BUILDING, "dye_11", "黄色の染料", Material.YELLOW_DYE), + MineStackObjectByMaterial(BUILDING, "dye_12", "空色の染料", Material.LIGHT_BLUE_DYE), + MineStackObjectByMaterial(BUILDING, "dye_13", "赤紫色の染料", Material.MAGENTA_DYE), + MineStackObjectByMaterial(BUILDING, "dye_14", "橙色の染料", Material.ORANGE_DYE), + MineStackObjectByMaterial(BUILDING, "dye_15", "骨粉", Material.BONE_MEAL), + MineStackObjectByMaterial(BUILDING, "ink_sack0", "イカスミ", Material.INK_SAC), + MineStackObjectByMaterial(BUILDING, "white_dye", "白色の染料", Material.WHITE_DYE), + MineStackObjectByMaterial(BUILDING, "blue_dye", "青色の染料", Material.BLUE_DYE), + MineStackObjectByMaterial(BUILDING, "brown_dye", "茶色の染料", Material.BROWN_DYE), + MineStackObjectByMaterial(BUILDING, "black_dye", "黒色の染料", Material.BLACK_DYE), ) ) ) // レッドストーン系ブロック private val minestacklistrs: List[MineStackObjectGroup[ItemStack]] = leftElems( - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "redstone", "レッドストーン", Material.REDSTONE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "stone_button", "石のボタン", Material.STONE_BUTTON, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "wood_button", "木のボタン", Material.WOOD_BUTTON, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "stone_plate", "石の感圧版", Material.STONE_PLATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "wood_plate", "木の感圧版", Material.WOOD_PLATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "fence_gate", "オークのフェンスゲート", Material.FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_fence_gate", "マツのフェンスゲート", Material.SPRUCE_FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_fence_gate", "シラカバのフェンスゲート", Material.BIRCH_FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_fence_gate", "ジャングルのフェンスゲート", Material.JUNGLE_FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_fence_gate", "ダークオークのフェンスゲート", Material.DARK_OAK_FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_fence_gate", "アカシアのフェンスゲート", Material.ACACIA_FENCE_GATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "redstone_block", "レッドストーンブロック", Material.REDSTONE_BLOCK, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "lever", "レバー", Material.LEVER, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "redstone_torch_on", "レッドストーントーチ", Material.REDSTONE_TORCH_ON, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "trap_door", "木のトラップドア", Material.TRAP_DOOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "iron_trapdoor", "鉄のトラップドア", Material.IRON_TRAPDOOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "gold_plate", "重量感圧版 (軽) ", Material.GOLD_PLATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "iron_plate", "重量感圧版 (重) ", Material.IRON_PLATE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "wood_door", "オークのドア", Material.WOOD_DOOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_door_item", "マツのドア", Material.SPRUCE_DOOR_ITEM, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_door_item", "シラカバのドア", Material.BIRCH_DOOR_ITEM, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_door_item", "ジャングルのドア", Material.JUNGLE_DOOR_ITEM, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_door_item", "アカシアのドア", Material.ACACIA_DOOR_ITEM, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_door_item", "ダークオークのドア", Material.DARK_OAK_DOOR_ITEM, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "note_block", "音符ブロック", Material.NOTE_BLOCK, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "redstone_lamp_off", "レッドストーンランプ", Material.REDSTONE_LAMP_OFF, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "tripwire_hook", "トリップワイヤーフック", Material.TRIPWIRE_HOOK, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dropper", "ドロッパー", Material.DROPPER, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "piston_sticky_base", "粘着ピストン", Material.PISTON_STICKY_BASE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "piston_base", "ピストン", Material.PISTON_BASE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "tnt", "TNT", Material.TNT, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "trapped_chest", "トラップチェスト", Material.TRAPPED_CHEST, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "daylight_detector", "日照センサー", Material.DAYLIGHT_DETECTOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "iron_door", "鉄のドア", Material.IRON_DOOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "diode", "レッドストーンリピーター", Material.DIODE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dispenser", "ディスペンサー", Material.DISPENSER, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "hopper", "ホッパー", Material.HOPPER, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "redstone_comparator", "レッドストーンコンパレーター", Material.REDSTONE_COMPARATOR, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "powered_rail", "パワードレール", Material.POWERED_RAIL, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "detector_rail", "ディテクターレール", Material.DETECTOR_RAIL, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "activator_rail", "アクティベーターレール", Material.ACTIVATOR_RAIL, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "boat", "オークのボート", Material.BOAT, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_boat", "マツのボート", Material.BOAT_SPRUCE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_boat", "シラカバのボート", Material.BOAT_BIRCH, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_boat", "ジャングルのボート", Material.BOAT_JUNGLE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_boat", "アカシアのボート", Material.BOAT_ACACIA, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_boat", "ダークオークのボート", Material.BOAT_DARK_OAK, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "saddle", "サドル", Material.SADDLE, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "minecart", "トロッコ", Material.MINECART, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "chest_minecart", "チェスト付きトロッコ", Material.STORAGE_MINECART, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "furnace_minecart", "かまど付きトロッコ", Material.POWERED_MINECART, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "hopper_minecart", "ホッパー付きトロッコ", Material.HOPPER_MINECART, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "iron_horse_armor", "鉄の馬鎧", Material.IRON_BARDING, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "golden_horse_armor", "金の馬鎧", Material.GOLD_BARDING, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "diamond_horse_armor", "ダイヤの馬鎧", Material.DIAMOND_BARDING, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_13", "レコード", Material.GOLD_RECORD, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_cat", "レコード", Material.GREEN_RECORD, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_blocks", "レコード", Material.RECORD_3, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_chirp", "レコード", Material.RECORD_4, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_far", "レコード", Material.RECORD_5, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_mall", "レコード", Material.RECORD_6, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_mellohi", "レコード", Material.RECORD_7, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_stal", "レコード", Material.RECORD_8, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_strad", "レコード", Material.RECORD_9, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_ward", "レコード", Material.RECORD_10, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_11", "レコード", Material.RECORD_11, 0), - MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "record_wait", "レコード", Material.RECORD_12, 0) + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"redstone","レッドストーンダスト",Material.REDSTONE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"redstone_block","レッドストーンブロック",Material.REDSTONE_BLOCK), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "lever", "レバー", Material.LEVER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"redstone_torch_on","レッドストーントーチ",Material.REDSTONE_TORCH), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"note_block","音符ブロック",Material.NOTE_BLOCK), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"redstone_lamp_off","レッドストーンランプ",Material.REDSTONE_LAMP), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"tripwire_hook","トリップワイヤーフック",Material.TRIPWIRE_HOOK), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dropper", "ドロッパー", Material.DROPPER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"piston_sticky_base","粘着ピストン",Material.STICKY_PISTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"piston_base","ピストン",Material.PISTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "tnt", "TNT", Material.TNT), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"trapped_chest","トラップチェスト",Material.TRAPPED_CHEST), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"daylight_detector","日照センサー",Material.DAYLIGHT_DETECTOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"diode","レッドストーンリピーター",Material.REPEATER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"dispenser","ディスペンサー",Material.DISPENSER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "hopper", "ホッパー", Material.HOPPER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"redstone_comparator","レッドストーンコンパレーター",Material.COMPARATOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"powered_rail","パワードレール",Material.POWERED_RAIL), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"detector_rail","ディテクターレール",Material.DETECTOR_RAIL), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"activator_rail","アクティベーターレール",Material.ACTIVATOR_RAIL), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "saddle", "鞍", Material.SADDLE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "minecart", "トロッコ", Material.MINECART), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"chest_minecart","チェスト付きトロッコ",Material.CHEST_MINECART), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"furnace_minecart","かまど付きトロッコ",Material.FURNACE_MINECART), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"hopper_minecart","ホッパー付きトロッコ",Material.HOPPER_MINECART), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"iron_horse_armor","鉄の馬鎧",Material.IRON_HORSE_ARMOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"golden_horse_armor","金の馬鎧",Material.GOLDEN_HORSE_ARMOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"diamond_horse_armor","ダイヤの馬鎧",Material.DIAMOND_HORSE_ARMOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "observer", "オブザーバー", Material.OBSERVER), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "lectern", "書見台", Material.LECTERN), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "target", "的", Material.TARGET), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "lightning_rod", "避雷針", Material.LIGHTNING_ROD), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "sculk_sensor", "スカルクセンサー", Material.SCULK_SENSOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "clock", "時計", Material.CLOCK), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spyglass", "望遠鏡", Material.SPYGLASS), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "firework_rocket", "ロケット花火", Material.FIREWORK_ROCKET), + ) ++ rightElems( + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"wood_button","木のボタン",Material.OAK_BUTTON), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"stone_button","石のボタン",Material.STONE_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_button", "トウヒのボタン", Material.SPRUCE_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_button", "シラカバのボタン", Material.BIRCH_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_button", "ジャングルのボタン", Material.JUNGLE_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_button", "アカシアのボタン", Material.ACACIA_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_button", "ダークオークのボタン", Material.DARK_OAK_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "polished_blackstone_button", "磨かれたブラックストーンのボタン", Material.POLISHED_BLACKSTONE_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "crimson_button", "真紅のボタン", Material.CRIMSON_BUTTON), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "warped_button", "歪んだボタン", Material.WARPED_BUTTON), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"wood_door","オークのドア",Material.OAK_DOOR), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"spruce_door_item","トウヒのドア",Material.SPRUCE_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"birch_door_item","シラカバのドア",Material.BIRCH_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"jungle_door_item","ジャングルのドア",Material.JUNGLE_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"acacia_door_item","アカシアのドア",Material.ACACIA_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"dark_oak_door_item","ダークオークのドア",Material.DARK_OAK_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"iron_door","鉄のドア",Material.IRON_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "crimson_door", "真紅のドア", Material.CRIMSON_DOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "warped_door", "歪んだドア", Material.WARPED_DOOR), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"trap_door","木のトラップドア",Material.OAK_TRAPDOOR), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"iron_trapdoor","鉄のトラップドア",Material.IRON_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_trapdoor", "トウヒのトラップドア", Material.SPRUCE_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_trapdoor", "シラカバのトラップドア", Material.BIRCH_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_trapdoor", "ジャングルのトラップドア", Material.JUNGLE_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_trapdoor", "アカシアのトラップドア", Material.ACACIA_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_trapdoor", "ダークオークのトラップドア", Material.DARK_OAK_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "crimson_trapdoor", "真紅のトラップドア", Material.CRIMSON_TRAPDOOR), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "warped_trapdoor", "歪んだトラップドア", Material.WARPED_TRAPDOOR), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"fence_gate","オークのフェンスゲート",Material.OAK_FENCE_GATE), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"spruce_fence_gate","トウヒのフェンスゲート",Material.SPRUCE_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"birch_fence_gate","シラカバのフェンスゲート",Material.BIRCH_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"jungle_fence_gate","ジャングルのフェンスゲート",Material.JUNGLE_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"dark_oak_fence_gate","ダークオークのフェンスゲート",Material.DARK_OAK_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"acacia_fence_gate","アカシアのフェンスゲート",Material.ACACIA_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "crimson_fence_gate", "真紅のフェンスゲート", Material.CRIMSON_FENCE_GATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "warped_fence_gate", "歪んだフェンスゲート", Material.WARPED_FENCE_GATE), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"wood_plate","木の感圧版",Material.OAK_PRESSURE_PLATE), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"stone_plate","石の感圧版",Material.STONE_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "polished_blackstone_pressure_plate", "磨かれたブラックストーンの感圧板", Material.POLISHED_BLACKSTONE_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "spruce_pressure_plate", "トウヒの感圧板", Material.SPRUCE_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "birch_pressure_plate", "シラカバの感圧板", Material.BIRCH_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "jungle_pressure_plate", "ジャングルの感圧板", Material.JUNGLE_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "acacia_pressure_plate", "アカシアの感圧板", Material.ACACIA_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "dark_oak_pressure_plate", "ダークオークの感圧板", Material.DARK_OAK_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "crimson_pressure_plate", "真紅の感圧板", Material.CRIMSON_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "warped_pressure_plate", "歪んだ感圧板", Material.WARPED_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"gold_plate","重量感圧版 (軽) ",Material.LIGHT_WEIGHTED_PRESSURE_PLATE), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"iron_plate","重量感圧版 (重) ",Material.HEAVY_WEIGHTED_PRESSURE_PLATE), + ) + ), + MineStackObjectWithKindVariants( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION, "boat", "オークのボート", Material.OAK_BOAT), + List( + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"spruce_boat","トウヒのボート",Material.SPRUCE_BOAT), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"birch_boat","シラカバのボート",Material.BIRCH_BOAT), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"jungle_boat","ジャングルのボート",Material.JUNGLE_BOAT), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"acacia_boat","アカシアのボート",Material.ACACIA_BOAT), + MineStackObjectByMaterial(REDSTONE_AND_TRANSPORTATION,"dark_oak_boat","ダークオークのボート",Material.DARK_OAK_BOAT), + ) + ) ) /** @@ -597,7 +1114,7 @@ class BukkitMineStackObjectList[F[_]: Sync]( */ private val minestackBuiltinGachaPrizes: List[MineStackObjectGroup[ItemStack]] = leftElems( MineStackObjectByItemStack(GACHA_PRIZES, "gachaimo", None, hasNameLore = true, gachaPrizeAPI.staticGachaPrizeFactory.gachaRingo), - MineStackObjectByItemStack(GACHA_PRIZES, "exp_bottle", Some("エンチャントの瓶"), hasNameLore = false, new ItemStack(Material.EXP_BOTTLE, 1)) + MineStackObjectByItemStack(GACHA_PRIZES, "exp_bottle", Some("エンチャントの瓶"), hasNameLore = false, new ItemStack(Material.EXPERIENCE_BOTTLE)) ) // @formatter:on @@ -640,7 +1157,7 @@ class BukkitMineStackObjectList[F[_]: Sync]( override def allMineStackObjects: F[Vector[MineStackObject[ItemStack]]] = allMineStackGroups.map(_.flatMap { case Left(mineStackObject: MineStackObject[ItemStack]) => List(mineStackObject) - case Right(group) => List(group.representative) ++ group.coloredVariants + case Right(group) => List(group.representative) ++ group.kindVariants }.toVector) override def getAllObjectGroupsInCategory( @@ -656,37 +1173,36 @@ class BukkitMineStackObjectList[F[_]: Sync]( allMineStackGroups.map(_.filter { group => categoryOf(group) == category }) } - override def findBySignedItemStack( - itemStack: ItemStack, + override def findBySignedItemStacks( + itemStacks: Vector[ItemStack], player: Player - ): F[Option[MineStackObject[ItemStack]]] = for { - gachaPrizes <- gachaPrizeAPI.gachaPrizesWhenGachaEventsIsNotHolding - canBeSignedAsGachaPrize = gachaPrizeAPI.canBeSignedAsGachaPrize - foundGachaPrizeOpt = gachaPrizes.find { gachaPrize => - if (gachaPrize.signOwner) { - gachaPrize - .materializeWithOwnerSignature(player.getName)(canBeSignedAsGachaPrize) - .isSimilar(itemStack) - } else { - gachaPrize.itemStack.isSimilar(itemStack) + ): F[Vector[(ItemStack, Option[MineStackObject[ItemStack]])]] = { + for { + gachaPrizes <- gachaPrizeAPI.gachaPrizesWhenGachaEventsIsNotHolding + mineStackObjects <- allMineStackObjects + } yield { + implicit val canBeSignedAsGachaPrize: CanBeSignedAsGachaPrize[ItemStack] = + gachaPrizeAPI.canBeSignedAsGachaPrize + + val signedItemStacks = gachaPrizes.map { gachaPrize => + gachaPrize.materializeWithOwnerSignature(player.getName) -> gachaPrize.itemStack } - } - isGachaPrize = foundGachaPrizeOpt.nonEmpty - mineStackObjects <- allMineStackObjects - } yield { - // ItemStackのLoreはnullの可能性がある - val isSignedItemStack = - Option(itemStack.getItemMeta.getLore).exists(_.contains("所有者:")) - if (isGachaPrize && foundGachaPrizeOpt.get.signOwner) { - mineStackObjects.find { mineStackObject => - foundGachaPrizeOpt.get.itemStack.isSimilar(mineStackObject.itemStack) + + itemStacks.map { _itemStack => + signedItemStacks.find(_._1.isSimilar(_itemStack)) match { + case Some((_, notSignedItemStack)) => + _itemStack -> mineStackObjects.find(_.itemStack.isSimilar(notSignedItemStack)) + case None => + mineStackObjects.find(_.itemStack.isSimilar(_itemStack)) match { + case Some(value) + if value.category != GACHA_PRIZES || minestackBuiltinGachaPrizes.exists( + _.swap.contains(value) + ) => + _itemStack -> Some(value) + case _ => _itemStack -> None + } + } } - } else if (isSignedItemStack) { - // 所有者名が違うとガチャ景品として認識しないが、違ったらそもそも見つかっていない - // 記名が入っていないアイテムは収納できてしまうが仕様 - None - } else { - mineStackObjects.find(_.itemStack.isSimilar(itemStack)) } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackRepository.scala index 80e77fded1..5e6763f417 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/BukkitMineStackRepository.scala @@ -66,9 +66,38 @@ class BukkitMineStackRepository[F[_]: Sync]( ) } - override def tryIntoMineStack(player: Player, itemStack: ItemStack, amount: Int): F[Boolean] = + override def tryIntoMineStack( + player: Player, + itemStack: ItemStack, + amount: Int + ): F[Boolean] = { + for { + foundMineStackObject <- mineStackObjectList.findBySignedItemStacks( + Vector(itemStack), + player + ) + _ <- foundMineStackObject.head.traverse { + case Some(mineStackObject) => + addStackedAmountOf(player, mineStackObject, amount) + case None => Sync[F].unit + } + } yield foundMineStackObject.head._2.isDefined + } + + override def tryIntoMineStack( + player: Player, + itemStacks: Vector[ItemStack] + ): F[(Vector[ItemStack], Vector[ItemStack])] = { for { - foundMineStackObject <- mineStackObjectList.findBySignedItemStack(itemStack, player) - _ <- foundMineStackObject.traverse(addStackedAmountOf(player, _, amount)) - } yield foundMineStackObject.isDefined + mineStackObjects <- mineStackObjectList.findBySignedItemStacks(itemStacks, player) + _ <- mineStackObjects.traverse { + case (itemStack, Some(mineStackObject)) => + addStackedAmountOf(player, mineStackObject, itemStack.getAmount) + case _ => Sync[F].unit + } + } yield mineStackObjects.partitionMap { + case (itemStack, Some(_)) => Right(itemStack) + case (itemStack, None) => Left(itemStack) + } + } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/PlayerPickupItemListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/PlayerPickupItemListener.scala index b97140073a..e9d998d394 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/PlayerPickupItemListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/bukkit/PlayerPickupItemListener.scala @@ -37,9 +37,9 @@ class PlayerPickupItemListener[F[_]: ConcurrentEffect, G[_]: ContextCoercion[*[_ currentAutoMineStackState <- ContextCoercion( mineStackSettingRepository(player).isAutoCollectionTurnedOn ) - isSucceedTryIntoMineStack <- whenAOrElse(currentAutoMineStackState)( - mineStackRepository.tryIntoMineStack(player, itemStack, itemStack.getAmount), - false + intoSucceedItemStacksAndFailedItemStacks <- whenAOrElse(currentAutoMineStackState)( + mineStackRepository.tryIntoMineStack(player, Vector(itemStack)), + (Vector(itemStack), Vector.empty) ) _ <- Sync[F] .delay { @@ -48,13 +48,13 @@ class PlayerPickupItemListener[F[_]: ConcurrentEffect, G[_]: ContextCoercion[*[_ item.remove() if (SeichiAssist.DEBUG) { player.sendMessage(RED.toString + "pick:" + itemStack.toString) - player.sendMessage(RED.toString + "pickDurability:" + itemStack.getDurability) } } - .whenA(isSucceedTryIntoMineStack) + .whenA(intoSucceedItemStacksAndFailedItemStacks._2.nonEmpty) } yield () program.toIO.unsafeRunAsyncAndForget() + case _ => () } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/MineStackRepository.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/MineStackRepository.scala index 1dd9e97231..a6b48d13f9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/MineStackRepository.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/MineStackRepository.scala @@ -37,4 +37,14 @@ trait MineStackRepository[F[_], Player, ItemStack] { */ def tryIntoMineStack(player: Player, itemStack: ItemStack, amount: Int): F[Boolean] + /** + * [[Player]]のMineStackリポジトリに[[ItemStack]]を格納することを試みます。 + * @return `itemStacks`の要素である[[ItemStack]]をMineStackに格納し + * 格納できなかったアイテムをTupleの第1要素、格納できたアイテムを第2要素として返す作用 + */ + def tryIntoMineStack( + player: Player, + itemStacks: Vector[ItemStack] + ): F[(Vector[ItemStack], Vector[ItemStack])] + } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObject.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObject.scala index f742352f38..7a95afeb3a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObject.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObject.scala @@ -54,15 +54,14 @@ object MineStackObject { category: MineStackObjectCategory, mineStackObjectName: String, japaneseName: String, - material: Material, - durability: Short + material: Material )( implicit minecraftMaterial: MinecraftMaterial[Material, ItemStack] ): MineStackObject[ItemStack] = { MineStackObject( mineStackObjectName, Some(japaneseName), - minecraftMaterial.toItemStack(material, durability), + minecraftMaterial.toItemStack(material), hasNameLore = false, category ) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectList.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectList.scala index bd30603044..5a1ce7590a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectList.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectList.scala @@ -11,12 +11,12 @@ trait MineStackObjectList[F[_], ItemStack, Player] { /** * @param itemStack 記名することのできるアイテムは、既に記名されていることを想定している - * @return [[ItemStack]]から[[MineStackObject]]を取得しようとする作用 + * @return `itemStack`の各要素に紐づいた[[MineStackObject]]を返す作用 */ - def findBySignedItemStack( - itemStack: ItemStack, + def findBySignedItemStacks( + itemStack: Vector[ItemStack], player: Player - ): F[Option[MineStackObject[ItemStack]]] + ): F[Vector[(ItemStack, Option[MineStackObject[ItemStack]])]] protected implicit val F: Functor[F] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithColorVariants.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithKindVariants.scala similarity index 52% rename from src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithColorVariants.scala rename to src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithKindVariants.scala index 35db22e653..3be993045a 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithColorVariants.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/MineStackObjectWithKindVariants.scala @@ -1,10 +1,10 @@ package com.github.unchama.seichiassist.subsystems.minestack.domain.minestackobject -case class MineStackObjectWithColorVariants[ItemStack]( +case class MineStackObjectWithKindVariants[ItemStack]( representative: MineStackObject[ItemStack], - coloredVariants: List[MineStackObject[ItemStack]] + kindVariants: List[MineStackObject[ItemStack]] ) { - require(coloredVariants.forall(_.category == representative.category)) + require(kindVariants.forall(_.category == representative.category)) def category: MineStackObjectCategory = representative.category } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/package.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/package.scala index 77b55a1aca..d1649c73ba 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/package.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/minestack/domain/minestackobject/package.scala @@ -3,6 +3,6 @@ package com.github.unchama.seichiassist.subsystems.minestack.domain package object minestackobject { type MineStackObjectGroup[ItemStack] = - Either[MineStackObject[ItemStack], MineStackObjectWithColorVariants[ItemStack]] + Either[MineStackObject[ItemStack], MineStackObjectWithKindVariants[ItemStack]] } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/openirontrapdoor/bukkit/listeners/PlayerClickIronTrapDoor.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/openirontrapdoor/bukkit/listeners/PlayerClickIronTrapDoor.scala index 1935fce2be..e4208cb298 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/openirontrapdoor/bukkit/listeners/PlayerClickIronTrapDoor.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/openirontrapdoor/bukkit/listeners/PlayerClickIronTrapDoor.scala @@ -2,11 +2,12 @@ package com.github.unchama.seichiassist.subsystems.openirontrapdoor.bukkit.liste import com.github.unchama.util.external.WorldGuardWrapper.isRegionMember import org.bukkit.Material +import org.bukkit.block.data.BlockData import org.bukkit.event.block.Action import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.event.{EventHandler, Listener} import org.bukkit.inventory.EquipmentSlot -import org.bukkit.material.{MaterialData, Openable} +import org.bukkit.material.Openable object PlayerClickIronTrapDoor extends Listener { @EventHandler @@ -21,10 +22,15 @@ object PlayerClickIronTrapDoor extends Listener { ) return // TODO: 手に何も持っていない場合は機能するが、ブロックなどを持っている場合は機能しない(手に持っているものが設置できるもののときや弓矢は反応する) - val blockState = clickedBlock.getState - val materialData = blockState.getData.asInstanceOf[Openable] - materialData.setOpen(!materialData.isOpen) - blockState.setData(materialData.asInstanceOf[MaterialData]) - blockState.update() + val blockData = clickedBlock.getBlockData + blockData match { + case openable: Openable => + openable.setOpen(!openable.isOpen) + + val blockState = clickedBlock.getState + blockState.setBlockData(openable.asInstanceOf[BlockData]) + blockState.update() + case _ => + } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/System.scala index f63133a04e..841ea82975 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/System.scala @@ -1,8 +1,7 @@ package com.github.unchama.seichiassist.subsystems.present -import cats.effect.{ConcurrentEffect, IO} +import cats.effect.ConcurrentEffect import com.github.unchama.concurrent.NonServerThreadContextShift -import com.github.unchama.generic.effect.unsafe.EffectEnvironment import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.domain.actions.UuidToLastSeenName import com.github.unchama.seichiassist.meta.subsystem.Subsystem @@ -11,10 +10,10 @@ import com.github.unchama.seichiassist.subsystems.present.infrastructure.JdbcBac import org.bukkit.command.TabExecutor object System { - def wired[ConcurrentContext[_]: ConcurrentEffect: NonServerThreadContextShift]( - implicit environment: EffectEnvironment, - uuidToLastSeenName: UuidToLastSeenName[ConcurrentContext], - ioOnMainThread: OnMinecraftServerThread[IO] + def wired[ConcurrentContext[ + _ + ]: ConcurrentEffect: NonServerThreadContextShift: OnMinecraftServerThread]( + implicit uuidToLastSeenName: UuidToLastSeenName[ConcurrentContext] ): Subsystem[ConcurrentContext] = { implicit val repo: JdbcBackedPresentPersistence[ConcurrentContext] = new JdbcBackedPresentPersistence[ConcurrentContext] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/bukkit/command/PresentCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/bukkit/command/PresentCommand.scala index ace10b8278..466a9fa608 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/bukkit/command/PresentCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/bukkit/command/PresentCommand.scala @@ -1,8 +1,8 @@ package com.github.unchama.seichiassist.subsystems.present.bukkit.command -import cats.Monad +import cats.data.Kleisli import cats.effect.implicits._ -import cats.effect.{ConcurrentEffect, IO} +import cats.effect.{ConcurrentEffect, Sync} import cats.implicits._ import com.github.unchama.concurrent.NonServerThreadContextShift import com.github.unchama.contextualexecutor.ContextualExecutor @@ -18,8 +18,8 @@ import com.github.unchama.seichiassist.domain.actions.UuidToLastSeenName import com.github.unchama.seichiassist.subsystems.present.domain.OperationResult.DeleteResult import com.github.unchama.seichiassist.subsystems.present.domain._ import com.github.unchama.seichiassist.util.InventoryOperations -import com.github.unchama.targetedeffect.commandsender.MessageEffect -import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffect} +import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffectF} +import com.github.unchama.targetedeffect.commandsender.{MessageEffect, MessageEffectF} import eu.timepit.refined.api.Refined import eu.timepit.refined.auto._ import eu.timepit.refined.numeric.Positive @@ -28,7 +28,6 @@ import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import org.bukkit.{ChatColor, Material} import shapeless.HNil -import shapeless.syntax.std.tuple._ /** * `/present` コマンドを定義する。 @@ -38,8 +37,10 @@ import shapeless.syntax.std.tuple._ * 別に表記がない限り、この実装は以下の条件を満たす: * - 存在しないプレゼントIDの指定は必ずエラーになる。 * - 操作が成功しなかったときは適切なメッセージを表示する。 + * + * TODO: 型パラメータが関数のあちこちに散りばめられているが、classの型引数に集約できそう */ -class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { +class PresentCommand { private val presentIdParser = Parsers.integer(MessageEffect("presentコマンドに与えるプレゼントIDは整数である必要があります。")) @@ -54,7 +55,8 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { MessageEffect("presentコマンドで対象を指定する際のモードは、playerまたはallを指定してください。") ) - private val noPermissionMessage = MessageEffect("You don't have the permission.") + private def noPermissionMessage[F[_]: Sync] = + MessageEffectF[F]("You don't have the permission.") private object SubCommands { object State { @@ -166,47 +168,47 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { * * 出力: 受け取った場合は、その旨表示する。失敗した場合は、適切なエラーメッセージを表示する。 */ - def executor[F[_]: ConcurrentEffect: NonServerThreadContextShift]( + def executor[F[ + _ + ]: ConcurrentEffect: NonServerThreadContextShift: OnMinecraftServerThread]( implicit persistence: PresentPersistence[F, ItemStack] ): ContextualExecutor = playerCommandBuilder .thenParse(presentIdParser) .ifArgumentsMissing(help) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => val player = context.sender.getUniqueId val presentId = context.args.parsed.head - val eff: F[TargetedEffect[Player]] = for { - _ <- NonServerThreadContextShift[F].shift - states <- persistence.fetchState(player) - claimState = states.getOrElse(presentId, PresentClaimingState.Unavailable) - effect <- claimState match { + (for { + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) + states <- Kleisli.liftF(persistence.fetchState(player)) + } yield { + val claimState = states.getOrElse(presentId, PresentClaimingState.Unavailable) + + claimState match { case PresentClaimingState.Claimed => - Monad[F].pure(MessageEffect(s"ID: ${presentId}のプレゼントはすでに受け取っています。")) + MessageEffectF[F](s"ID: ${presentId}のプレゼントはすでに受け取っています。") case PresentClaimingState.NotClaimed => - for { - _ <- persistence.markAsClaimed(presentId, player) - item <- persistence.lookup(presentId) - } yield { - // 注釈: この明示的な型変数の指定は必要 - // see: https://discord.com/channels/237758724121427969/565935041574731807/823495317499805776 - item.fold[TargetedEffect[Player]]( - MessageEffect(s"ID: ${presentId}のプレゼントは存在しません。IDをお確かめください。") - ) { item => - SequentialEffect( - InventoryOperations.grantItemStacksEffect[IO](item), - MessageEffect(s"ID: ${presentId}のプレゼントを付与しました。") - ) + Kleisli + .liftF(for { + _ <- persistence.markAsClaimed(presentId, player) + item <- persistence.lookup(presentId) + } yield item) + .flatMap { item => + item.fold[TargetedEffectF[F, Player]]( + MessageEffectF[F](s"ID: ${presentId}のプレゼントは存在しません。IDをお確かめください。") + ) { item => + SequentialEffect( + InventoryOperations.grantItemStacksEffect[F](item), + MessageEffectF[F](s"ID: ${presentId}のプレゼントを付与しました。") + ) + } } - } case PresentClaimingState.Unavailable => - Monad[F].pure( - MessageEffect(s"ID: ${presentId}のプレゼントは存在しないか、あるいは配布対象ではありません。") - ) + MessageEffectF[F](s"ID: ${presentId}のプレゼントは存在しないか、あるいは配布対象ではありません。") } - } yield effect - - eff + }).flatten } } @@ -228,25 +230,23 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { def executor[F[_]: ConcurrentEffect: NonServerThreadContextShift]( implicit persistence: PresentPersistence[F, ItemStack] ): ContextualExecutor = - playerCommandBuilder.buildWithExecutionF { context => + playerCommandBuilder.buildWithExecutionCSEffect { context => val player = context.sender if (player.hasPermission("seichiassist.present.define")) { val mainHandItem = player.getInventory.getItemInMainHand - if (mainHandItem.getType eq Material.AIR) { + if (mainHandItem.getType == Material.AIR) { // おそらくこれは意図した動作ではないのでエラーメッセージを表示する - ConcurrentEffect[F].pure( - MessageEffect("メインハンドに何も持っていません。プレゼントを定義するためには、メインハンドに対象アイテムを持ってください。") - ) + MessageEffectF[F]("メインハンドに何も持っていません。プレゼントを定義するためには、メインハンドに対象アイテムを持ってください。") } else { - for { - _ <- NonServerThreadContextShift[F].shift - presentID <- persistence.define(mainHandItem) + (for { + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) + presentID <- Kleisli.liftF(persistence.define(mainHandItem)) } yield { - MessageEffect(s"メインハンドに持ったアイテムをプレゼントとして定義しました。IDは${presentID}です。") - } + MessageEffectF(s"メインハンドに持ったアイテムをプレゼントとして定義しました。IDは${presentID}です。") + }).flatten } } else { - ConcurrentEffect[F].pure(noPermissionMessage) + noPermissionMessage } } } @@ -270,21 +270,21 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { .beginConfiguration .thenParse(presentIdParser) .ifArgumentsMissing(help) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => { val presentId = context.args.parsed.head if (!context.sender.hasPermission("seichiassist.present.delete")) { - ConcurrentEffect[F].pure(noPermissionMessage) + noPermissionMessage } else { - for { - _ <- NonServerThreadContextShift[F].shift - result <- persistence.delete(presentId) + (for { + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) + result <- Kleisli.liftF(persistence.delete(presentId)) } yield result match { case DeleteResult.Done => - MessageEffect(s"IDが${presentId}のプレゼントの消去は正常に行われました。") + MessageEffectF(s"IDが${presentId}のプレゼントの消去は正常に行われました。") case DeleteResult.NotFound => - MessageEffect(s"IDが${presentId}のプレゼントは存在しませんでした。") - } + MessageEffectF(s"IDが${presentId}のプレゼントは存在しませんでした。") + }).flatten } } } @@ -325,16 +325,16 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { .thenParse(presentIdParser) .thenParse(presentScopeModeParser) .ifArgumentsMissing(help) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => if (context.sender.hasPermission("seichiassist.present.grant")) { import shapeless.:: val presentId :: mode :: HNil = context.args.parsed // Parserを通した段階でargs[0]は "player" | "all" になっているのでこれでOK val isGlobal = mode == "all" - for { - _ <- NonServerThreadContextShift[F].shift + (for { + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) // TODO: 以下の処理は多分共通化できるがうまい方法が思いつかない - globalUUID2Name <- globalPlayerAccessor.entries + globalUUID2Name <- Kleisli.liftF(globalPlayerAccessor.entries) // 可変長引数には対応していないので`yetToBeParsed`を使う restArg = context .args @@ -348,19 +348,19 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { else globalUUID2Name.filter { case (_, name) => restArg.contains(name) }.keys errorIfNobody = Option.when(target.isEmpty) { - MessageEffect("対象のプレイヤーが存在しません!") + MessageEffectF("対象のプレイヤーが存在しません!") } - grantError <- persistence.grant(presentId, target.toSet) + grantError <- Kleisli.liftF(persistence.grant(presentId, target.toSet)) } yield errorIfNobody.getOrElse( grantError .map { case GrantRejectReason.NoSuchPresentID => - MessageEffect("指定されたプレゼントIDは存在しません!") + MessageEffectF("指定されたプレゼントIDは存在しません!") } - .getOrElse(MessageEffect(s"プレゼント(id: $presentId)を受け取れるプレイヤーを追加しました。")) - ) + .getOrElse(MessageEffectF(s"プレゼント(id: $presentId)を受け取れるプレイヤーを追加しました。")) + )).flatten } else { - ConcurrentEffect[F].pure(noPermissionMessage) + noPermissionMessage } } } @@ -399,15 +399,15 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { .thenParse(presentIdParser) .thenParse(presentScopeModeParser) .ifArgumentsMissing(help) - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => if (context.sender.hasPermission("seichiassist.present.revoke")) { import shapeless.:: val args = context.args val presentId :: presentScope :: HNil = args.parsed val isGlobal = presentScope == "all" - for { - _ <- NonServerThreadContextShift[F].shift - globalUUID2Name <- globalPlayerAccessor.entries + (for { + _ <- Kleisli.liftF(NonServerThreadContextShift[F].shift) + globalUUID2Name <- Kleisli.liftF(globalPlayerAccessor.entries) // 可変長引数には対応していないので`yetToBeParsed`を使う restArg = args // プレイヤー名は /[A-Za-z0-9_]{,16}/であるため空白が誤って解釈されることはない @@ -420,22 +420,23 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { else globalUUID2Name.filter { case (_, name) => restArg.contains(name) }.keys errorIfNobody = - if (target.isEmpty) Some(MessageEffect("対象のプレイヤーが存在しません!")) else None - warning <- persistence.revoke(presentId, target.toSet) + if (target.isEmpty) Some(MessageEffectF("対象のプレイヤーが存在しません!")) else None + warning <- Kleisli.liftF(persistence.revoke(presentId, target.toSet)) } yield { errorIfNobody.getOrElse { warning .map { - case RevokeWarning.NoSuchPresentID => MessageEffect("そのようなプレゼントIDはありません!") - case RevokeWarning.NoPlayers => MessageEffect("対象となるプレイヤーが存在しません!") + case RevokeWarning.NoSuchPresentID => + MessageEffectF("そのようなプレゼントIDはありません!") + case RevokeWarning.NoPlayers => MessageEffectF("対象となるプレイヤーが存在しません!") } .getOrElse { - MessageEffect(s"プレゼント(id: $presentId)を受け取れるプレイヤーを削除しました。") + MessageEffectF(s"プレゼント(id: $presentId)を受け取れるプレイヤーを削除しました。") } } - } + }).flatten } else { - ConcurrentEffect[F].pure(noPermissionMessage) + noPermissionMessage } } } @@ -473,7 +474,7 @@ class PresentCommand(implicit val ioOnMainThread: OnMinecraftServerThread[IO]) { } } - def executor[F[_]: ConcurrentEffect: NonServerThreadContextShift]( + def executor[F[_]: ConcurrentEffect: NonServerThreadContextShift: OnMinecraftServerThread]( implicit persistence: PresentPersistence[F, ItemStack], globalPlayerAccessor: UuidToLastSeenName[F] ): TabExecutor = BranchedExecutor( diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/infrastructure/JdbcBackedPresentPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/infrastructure/JdbcBackedPresentPersistence.scala index 197c85ee08..394b95c437 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/present/infrastructure/JdbcBackedPresentPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/present/infrastructure/JdbcBackedPresentPersistence.scala @@ -22,7 +22,7 @@ class JdbcBackedPresentPersistence[F[_]: Sync] extends PresentPersistence[F, Ite DB.localTx { implicit session => // プレゼントのIDはauto_incrementなので明示的に指定しなくて良い sql"""INSERT INTO present (itemstack) VALUES ($stackAsBlob)""" - .updateAndReturnGeneratedKey + .updateAndReturnGeneratedKey() .apply() } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/domain/RankingRecord.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/domain/RankingRecord.scala index 4efa97c7da..08ea3b1b2c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/domain/RankingRecord.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/domain/RankingRecord.scala @@ -1,5 +1,7 @@ package com.github.unchama.seichiassist.subsystems.ranking.domain -case class RankingRecord[V](playerName: String, value: V) +import java.util.UUID + +case class RankingRecord[V](playerName: String, uuid: UUID, value: V) case class RankingRecordWithPosition[V](record: RankingRecord[V], positionInRanking: Int) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcBuildRankingRecordPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcBuildRankingRecordPersistence.scala index 710c99798a..f63e8a4b52 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcBuildRankingRecordPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcBuildRankingRecordPersistence.scala @@ -9,15 +9,18 @@ import com.github.unchama.seichiassist.subsystems.ranking.domain.{ } import scalikejdbc.{DB, scalikejdbcSQLInterpolationImplicitDef} +import java.util.UUID + class JdbcBuildRankingRecordPersistence[F[_]: Sync] extends RankingRecordPersistence[F, BuildAmountData] { override def getAllRankingRecords: F[Vector[RankingRecord[BuildAmountData]]] = Sync[F].delay { DB.readOnly { implicit session => - sql"SELECT name,build_count from playerdata" + sql"SELECT name, uuid, build_count from playerdata" .map { rs => RankingRecord( rs.string("name"), + UUID.fromString(rs.string("uuid")), BuildAmountData(BuildExpAmount(BigDecimal(rs.string("build_count")))) ) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcLoginRankingRecordPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcLoginRankingRecordPersistence.scala index 73182ccd80..be6114a338 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcLoginRankingRecordPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcLoginRankingRecordPersistence.scala @@ -8,12 +8,20 @@ import com.github.unchama.seichiassist.subsystems.ranking.domain.{ } import scalikejdbc.{DB, scalikejdbcSQLInterpolationImplicitDef} +import java.util.UUID + class JdbcLoginRankingRecordPersistence[F[_]: Sync] extends RankingRecordPersistence[F, LoginTime] { override def getAllRankingRecords: F[Vector[RankingRecord[LoginTime]]] = Sync[F].delay { DB.readOnly { implicit session => - sql"SELECT name,playtick from playerdata" - .map { rs => RankingRecord(rs.string("name"), LoginTime(rs.long("playtick"))) } + sql"SELECT name, uuid, playtick from playerdata" + .map { rs => + RankingRecord( + rs.string("name"), + UUID.fromString(rs.string("uuid")), + LoginTime(rs.long("playtick")) + ) + } .list() .apply() .toVector diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcSeichiRankingRecordPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcSeichiRankingRecordPersistence.scala index ea8c6ef7cc..8e94d12df6 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcSeichiRankingRecordPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcSeichiRankingRecordPersistence.scala @@ -9,16 +9,19 @@ import com.github.unchama.seichiassist.subsystems.ranking.domain.{ } import scalikejdbc.{DB, scalikejdbcSQLInterpolationImplicitDef} +import java.util.UUID + class JdbcSeichiRankingRecordPersistence[F[_]: Sync] extends RankingRecordPersistence[F, SeichiAmountData] { override def getAllRankingRecords: F[Vector[RankingRecord[SeichiAmountData]]] = Sync[F].delay { DB.localTx { implicit session => - sql"select name, totalbreaknum from playerdata" + sql"select name, uuid, totalbreaknum from playerdata" .map { rs => RankingRecord( rs.string("name"), + UUID.fromString(rs.string("uuid")), SeichiAmountData( SeichiExpAmount.ofNonNegative(rs.bigInt("totalbreaknum").longValueExact()) ) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcVoteRankingRecordPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcVoteRankingRecordPersistence.scala index 2a06e54cc6..e64e034e96 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcVoteRankingRecordPersistence.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/ranking/infrastructure/JdbcVoteRankingRecordPersistence.scala @@ -8,12 +8,20 @@ import com.github.unchama.seichiassist.subsystems.ranking.domain.{ } import scalikejdbc.{DB, scalikejdbcSQLInterpolationImplicitDef} +import java.util.UUID + class JdbcVoteRankingRecordPersistence[F[_]: Sync] extends RankingRecordPersistence[F, VoteCount] { override def getAllRankingRecords: F[Vector[RankingRecord[VoteCount]]] = Sync[F].delay { DB.readOnly { implicit session => - sql"SELECT playerdata.name,vote_number FROM vote INNER JOIN playerdata ON vote.uuid = playerdata.uuid" - .map { rs => RankingRecord(rs.string("name"), VoteCount(rs.int("vote_number"))) } + sql"SELECT playerdata.name, playerdata.uuid, vote_number FROM vote INNER JOIN playerdata ON vote.uuid = playerdata.uuid" + .map { rs => + RankingRecord( + rs.string("name"), + UUID.fromString(rs.string("uuid")), + VoteCount(rs.int("vote_number")) + ) + } .list() .apply() .toVector diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/rescueplayer/bukkit/listeners/RescuePlayerListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/rescueplayer/bukkit/listeners/RescuePlayerListener.scala index 0dd495654e..0efebbcceb 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/rescueplayer/bukkit/listeners/RescuePlayerListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/rescueplayer/bukkit/listeners/RescuePlayerListener.scala @@ -7,7 +7,7 @@ import org.bukkit.event.{EventHandler, Listener} class RescuePlayerListener extends Listener { @EventHandler def onPlayerFallenToVoid(event: PlayerMoveEvent): Unit = { - if (event.getTo.getBlockY < 0.0) { + if (event.getTo.getBlockY < -64.0) { val player = event.getPlayer val worldSpawnLocation = player.getWorld.getSpawnLocation diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryItemData.scala index 259899bcf2..cc5bb366db 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryItemData.scala @@ -3,7 +3,7 @@ package com.github.unchama.seichiassist.subsystems.seasonalevents.anniversary import com.github.unchama.itemstackbuilder.{SkullItemStackBuilder, SkullOwnerTextureValue} import com.github.unchama.seichiassist.subsystems.seasonalevents.anniversary.Anniversary.ANNIVERSARY_COUNT import com.github.unchama.seichiassist.util.EnchantNameToJapanese -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.Bukkit import org.bukkit.ChatColor._ import org.bukkit.Material._ @@ -36,13 +36,13 @@ object AnniversaryItemData { .map(lore => s"$RESET$GRAY$lore") .asJava - val itemMeta = Bukkit.getItemFactory.getItemMeta(SAPLING).tap { meta => + val itemMeta = Bukkit.getItemFactory.getItemMeta(OAK_SAPLING).tap { meta => import meta._ setDisplayName(s"$GOLD${BOLD}「気になる木」の苗") setLore(loreList) } - val itemStack = new ItemStack(SAPLING, 1) + val itemStack = new ItemStack(OAK_SAPLING, 1) itemStack.setItemMeta(itemMeta) new NBTItem(itemStack) @@ -64,25 +64,29 @@ object AnniversaryItemData { COAL_BLOCK, DIAMOND_BLOCK, DRAGON_EGG, - FENCE, + OAK_FENCE, + JUNGLE_FENCE, + ACACIA_FENCE, + BIRCH_FENCE, + DARK_OAK_FENCE, FLOWER_POT, GLOWSTONE, GOLD_BLOCK, GRASS, ICE, IRON_BLOCK, - MELON_BLOCK, + MELON, NETHER_BRICK, QUARTZ_BLOCK, SAND, SPONGE, - WORKBENCH + CRAFTING_TABLE ) val strangeSaplingSiinaRate = 0.0008 def isStrangeSapling(item: ItemStack): Boolean = - item != null && item.getType == SAPLING && { + item != null && item.getType == OAK_SAPLING && { new NBTItem(item).getByte(NBTTagConstants.typeIdTag) == 1 } @@ -135,14 +139,15 @@ object AnniversaryItemData { val loreList = { val enchDescription = enchantments.map { - case (ench, lvl) => s"$GRAY${EnchantNameToJapanese.getEnchantName(ench.getName, lvl)}" + case (ench, lvl) => + s"$GRAY${EnchantNameToJapanese.getEnchantName(ench.getKey.getKey, lvl)}" }.toList val lore = List("", "特殊なエンチャントが付与されています").map(lore => s"$YELLOW$lore") enchDescription ::: lore }.map(lore => s"$RESET$lore").asJava - val itemMeta = Bukkit.getItemFactory.getItemMeta(DIAMOND_SPADE).tap { meta => + val itemMeta = Bukkit.getItemFactory.getItemMeta(DIAMOND_SHOVEL).tap { meta => import meta._ setDisplayName(s"$GOLD${BOLD}SCARLET") setLore(loreList) @@ -150,7 +155,7 @@ object AnniversaryItemData { enchantments.foreach { case (ench, lvl) => addEnchant(ench, lvl, true) } } - val itemStack = new ItemStack(DIAMOND_SPADE, 1) + val itemStack = new ItemStack(DIAMOND_SHOVEL, 1) itemStack.setItemMeta(itemMeta) new NBTItem(itemStack) @@ -162,7 +167,7 @@ object AnniversaryItemData { } def isAnniversaryShovel(item: ItemStack): Boolean = - item != null && item.getType == DIAMOND_SPADE && { + item != null && item.getType == DIAMOND_SHOVEL && { new NBTItem(item).getByte(NBTTagConstants.typeIdTag) == 3 } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryListener.scala index ff9311350f..d65cfe0348 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/anniversary/AnniversaryListener.scala @@ -91,7 +91,7 @@ class AnniversaryListener( // Y座標を下に動かして(木の上方から)オークの木の頂点を探し、そのブロックを置き換える (10 to 0 by -1) .map(placedBlock.getRelative(0, _, 0)) - .find(block => block.getType == Material.LOG || block.getType == Material.LEAVES) + .find(block => block.getType == Material.OAK_LOG || block.getType == Material.OAK_LEAVES) .foreach(replaceBlockOnTreeTop(_, event.getPlayer.getName)) } @@ -109,7 +109,6 @@ class AnniversaryListener( val offHandItem = player.getInventory.getItemInOffHand if (offHandItem == null) return - offHandItem.setDurability(0) removeItemfromPlayerInventory(player.getInventory, item, 1) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemData.scala index 44b8541612..75a1564a03 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemData.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.seasonalevents.christmas import com.github.unchama.seichiassist.subsystems.seasonalevents.christmas.Christmas.EVENT_YEAR -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Color.fromRGB import org.bukkit.enchantments.Enchantment @@ -197,7 +197,7 @@ object ChristmasItemData { s"$RED${UNDERLINE}スポーン地点にいる村人に欲しい物を詰めてもらおう!" ).map(str => s"$RESET$str").asJava - val itemMeta = Bukkit.getItemFactory.getItemMeta(Material.INK_SACK).tap { meta => + Bukkit.getItemFactory.getItemMeta(Material.INK_SAC).tap { meta => import meta._ setDisplayName(s"${AQUA}靴下(${EVENT_YEAR}年)") setLore(loreList) @@ -206,11 +206,7 @@ object ChristmasItemData { } // 赤の染料 - val itemStack = new ItemStack(Material.INK_SACK, 1).tap { itemStack => - import itemStack._ - setDurability(1.toShort) - setItemMeta(itemMeta) - } + val itemStack = new ItemStack(Material.RED_DYE, 1) itemStack } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemListener.scala index 3a9efe1632..a2b12ad3bb 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/christmas/ChristmasItemListener.scala @@ -13,7 +13,7 @@ import com.github.unchama.seichiassist.util.InventoryOperations.{ isPlayerInventoryFull, removeItemfromPlayerInventory } -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.entity.EntityType._ import org.bukkit.entity.{EntityType, LivingEntity, Player} @@ -57,7 +57,7 @@ class ChristmasItemListener[F[_], G[_]: SyncEffect](instance: JavaPlugin)( val rand = new Random().nextDouble() val potionEffectType = if (rand > 0.5) PotionEffectType.LUCK else PotionEffectType.UNLUCK - player.addPotionEffect(new PotionEffect(potionEffectType, 20 * 30, 0), true) + player.addPotionEffect(new PotionEffect(potionEffectType, 20 * 30, 0)) removeItemfromPlayerInventory(player.getInventory, item, 1) @@ -74,7 +74,7 @@ class ChristmasItemListener[F[_], G[_]: SyncEffect](instance: JavaPlugin)( val rand = new Random().nextDouble() val potionEffectType = if (rand > 0.5) PotionEffectType.SPEED else PotionEffectType.SLOW - event.getPlayer.addPotionEffect(new PotionEffect(potionEffectType, 20 * 30, 0), true) + event.getPlayer.addPotionEffect(new PotionEffect(potionEffectType, 20 * 30, 0)) } @EventHandler @@ -117,7 +117,7 @@ class ChristmasItemListener[F[_], G[_]: SyncEffect](instance: JavaPlugin)( GUARDIAN, HUSK, MAGMA_CUBE, - PIG_ZOMBIE, + ZOMBIFIED_PIGLIN, SHULKER, SILVERFISH, SKELETON, @@ -186,7 +186,7 @@ class ChristmasItemListener[F[_], G[_]: SyncEffect](instance: JavaPlugin)( addItem(player, christmasSock) player.sendMessage(s"$AQUA「靴下」を見つけたよ!") } - player.playSound(player.getLocation, Sound.BLOCK_NOTE_HARP, 3.0f, 1.0f) + player.playSound(player.getLocation, Sound.BLOCK_NOTE_BLOCK_HARP, 3.0f, 1.0f) } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemData.scala index 11ad0aeaf1..62e86be13d 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemData.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.seasonalevents.halloween import com.github.unchama.seichiassist.util.EnchantNameToJapanese -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Color.fromRGB import org.bukkit.enchantments.Enchantment @@ -82,7 +82,7 @@ object HalloweenItemData { val year = Calendar.getInstance().get(Calendar.YEAR) val enchDescription = enchantments.map { case (ench, lvl) => - s"$RESET$GRAY${EnchantNameToJapanese.getEnchantName(ench.getName, lvl)}" + s"$RESET$GRAY${EnchantNameToJapanese.getEnchantName(ench.getKey.toString, lvl)}" }.toList val lore = List( "", diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemListener.scala index 00c6368525..7e379643b9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/halloween/HalloweenItemListener.scala @@ -9,7 +9,7 @@ import com.github.unchama.seichiassist.subsystems.seasonalevents.halloween.Hallo isHalloweenHoe, isHalloweenPotion } -import com.github.unchama.util.external.WorldGuardWrapper.isRegionMember +import com.github.unchama.util.external.WorldGuardWrapper import org.bukkit.ChatColor.{DARK_GREEN, LIGHT_PURPLE, UNDERLINE} import org.bukkit.Material import org.bukkit.block.Block @@ -40,7 +40,7 @@ object HalloweenItemListener extends Listener { // 10分 event .getPlayer - .addPotionEffect(new PotionEffect(PotionEffectType.SATURATION, 20 * 60 * 10, 0), true) + .addPotionEffect(new PotionEffect(PotionEffectType.SATURATION, 20 * 60 * 10, 0)) } } @@ -62,19 +62,18 @@ object HalloweenItemListener extends Listener { val player = event.getPlayer // まず、Playerが自分でクリックしたブロックについて判定する if (!canBeReplacedWithSoil(player, clickedBlock)) return - clickedBlock.setType(Material.SOIL) + clickedBlock.setType(Material.FARMLAND) // 次にクリックされたブロックから半径4ブロック以内のブロックについて判定する for (relX <- -4 to 4; relZ <- -4 to 4) { val block = clickedBlock.getRelative(relX, 0, relZ) - if (block != null && canBeReplacedWithSoil(player, block)) block.setType(Material.SOIL) + if (block != null && canBeReplacedWithSoil(player, block)) + block.setType(Material.FARMLAND) } } private def canBeReplacedWithSoil(player: Player, block: Block) = { - (block.getType == Material.DIRT || block.getType == Material.GRASS) && isRegionMember( - player, - block.getLocation - ) + (block.getType == Material.FARMLAND || block.getType == Material.GRASS) && WorldGuardWrapper + .isRegionMember(player, block.getLocation) } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearItemData.scala index 92ff0f8111..546a083420 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearItemData.scala @@ -6,7 +6,7 @@ import com.github.unchama.seichiassist.subsystems.seasonalevents.newyear.NewYear EVENT_YEAR, NEW_YEAR_EVE } -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.enchantments.Enchantment import org.bukkit.inventory.{ItemFlag, ItemStack} @@ -43,7 +43,7 @@ object NewYearItemData { .tap { item => import item._ setByte(NBTTagConstants.typeIdTag, 1.toByte) - setObject(NBTTagConstants.expiryDateTag, END_DATE) + setLong(NBTTagConstants.expiryDateTag, END_DATE.toEpochDay) } .pipe(_.getItem) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearListener.scala index a09d4ac3a8..89f53e1a2c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/newyear/NewYearListener.scala @@ -20,7 +20,7 @@ import com.github.unchama.targetedeffect.SequentialEffect import com.github.unchama.targetedeffect.TargetedEffect.emptyEffect import com.github.unchama.targetedeffect.commandsender.MessageEffect import com.github.unchama.targetedeffect.player.FocusedSoundEffect -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Sound import org.bukkit.entity.Player @@ -91,7 +91,7 @@ class NewYearListener[F[_]: ConcurrentEffect: NonServerThreadContextShift, G[_]: val player = event.getPlayer val today = LocalDate.now() val expiryDate = - new NBTItem(item).getObject(NBTTagConstants.expiryDateTag, classOf[LocalDate]) + LocalDate.ofEpochDay(new NBTItem(item).getLong(NBTTagConstants.expiryDateTag)) if (today.isBefore(expiryDate) || today.isEqual(expiryDate)) { // マナを10%回復する manaApi.manaAmount(player).restoreFraction(0.1).runSync[SyncIO].unsafeRunSync() @@ -117,7 +117,7 @@ class NewYearListener[F[_]: ConcurrentEffect: NonServerThreadContextShift, G[_]: addItem(player, newYearBag) player.sendMessage(s"$AQUA「お年玉袋」を見つけたよ!") } - player.playSound(player.getLocation, Sound.BLOCK_NOTE_HARP, 3.0f, 1.0f) + player.playSound(player.getLocation, Sound.BLOCK_NOTE_BLOCK_HARP, 3.0f, 1.0f) } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiItemData.scala index d5a72532db..b0e0e3db04 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiItemData.scala @@ -1,7 +1,7 @@ package com.github.unchama.seichiassist.subsystems.seasonalevents.seizonsiki import com.github.unchama.seichiassist.subsystems.seasonalevents.seizonsiki.Seizonsiki.END_DATE -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.inventory.ItemStack import org.bukkit.{Bukkit, Material} @@ -36,7 +36,7 @@ object SeizonsikiItemData { .tap { item => import item._ setByte(NBTTagConstants.typeIdTag, 1.toByte) - setObject(NBTTagConstants.expiryDateTag, END_DATE) + setLong(NBTTagConstants.expiryDateTag, END_DATE.toEpochDay) } .pipe(_.getItem) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiListener.scala index e23d9fa1c2..40211b4de8 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/seizonsiki/SeizonsikiListener.scala @@ -6,9 +6,9 @@ import com.github.unchama.seichiassist.subsystems.mana.ManaWriteApi import com.github.unchama.seichiassist.subsystems.seasonalevents.Util.randomlyDropItemAt import com.github.unchama.seichiassist.subsystems.seasonalevents.seizonsiki.Seizonsiki._ import com.github.unchama.seichiassist.subsystems.seasonalevents.seizonsiki.SeizonsikiItemData._ -import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreference +import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO import com.github.unchama.seichiassist.util.EntityDeathCause.isEntityKilledByThornsEnchant -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor.{DARK_GREEN, LIGHT_PURPLE, UNDERLINE} import org.bukkit.Sound import org.bukkit.entity.{EntityType, Player} @@ -56,7 +56,7 @@ class SeizonsikiListener[F[_], G[_]: SyncEffect](implicit manaApi: ManaWriteApi[ val player = event.getPlayer val today = LocalDate.now() - val exp = new NBTItem(item).getObject(NBTTagConstants.expiryDateTag, classOf[LocalDate]) + val exp = LocalDate.ofEpochDay(new NBTItem(item).getLong(NBTTagConstants.expiryDateTag)) if (today.isBefore(exp)) { // マナを10%回復する manaApi.manaAmount(player).restoreFraction(0.1).runSync[SyncIO].unsafeRunSync() @@ -67,7 +67,8 @@ class SeizonsikiListener[F[_], G[_]: SyncEffect](implicit manaApi: ManaWriteApi[ player.setHealth(0) val messages = deathMessages(player.getName) - sendMessageToEveryoneIgnoringPreference(messages(new Random().nextInt(messages.size))) + sendMessageToEveryoneIgnoringPreferenceIO(messages(new Random().nextInt(messages.size))) + .unsafeRunAsyncAndForget() } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineItemData.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineItemData.scala index 80a4411381..f1b2d369a2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineItemData.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineItemData.scala @@ -5,13 +5,13 @@ import com.github.unchama.seichiassist.subsystems.seasonalevents.valentine.Valen EVENT_DURATION, EVENT_YEAR } -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.SkullMeta import org.bukkit.{Bukkit, Material} -import java.time.LocalDateTime +import java.time.{LocalDateTime, ZoneOffset} import java.util.UUID import scala.jdk.CollectionConverters._ import scala.util.chaining._ @@ -43,9 +43,12 @@ object ValentineItemData { */ def isUsableCookie(item: ItemStack): Boolean = { val now = LocalDateTime.now() - val exp = Option( - new NBTItem(item).getObject(NBTTagConstants.expiryDateTimeTag, classOf[LocalDateTime]) - ).getOrElse(return false) + val exp = LocalDateTime.ofEpochSecond( + Option(new NBTItem(item).getLong(NBTTagConstants.expiryDateTimeTag)) + .getOrElse(return false), + 0, + ZoneOffset.of("+9") + ) now.isBefore(exp) || now.isEqual(exp) } @@ -74,7 +77,10 @@ object ValentineItemData { .tap { item => import item._ setByte(NBTTagConstants.typeIdTag, droppedCookieTypeId.toByte) - setObject(NBTTagConstants.expiryDateTimeTag, EVENT_DURATION.to) + setLong( + NBTTagConstants.expiryDateTimeTag, + EVENT_DURATION.to.toEpochSecond(ZoneOffset.of("+9")) + ) } .pipe(_.getItem) } @@ -113,8 +119,11 @@ object ValentineItemData { .tap { item => import item._ setByte(NBTTagConstants.typeIdTag, giftedCookieTypeId.toByte) - setObject(NBTTagConstants.expiryDateTimeTag, EVENT_DURATION.to) - setObject(NBTTagConstants.producerUuidTag, playerUuid) + setLong( + NBTTagConstants.expiryDateTimeTag, + EVENT_DURATION.to.toEpochSecond(ZoneOffset.of("+9")) + ) + setUUID(NBTTagConstants.producerUuidTag, playerUuid) setString(NBTTagConstants.producerNameTag, playerName) } .pipe(_.getItem) @@ -128,7 +137,7 @@ object ValentineItemData { * @return UUIDが設定されていれば[[Some]]、なければ[[None]] */ def ownerOf(item: ItemStack): Option[UUID] = - Option(new NBTItem(item).getObject(NBTTagConstants.producerUuidTag, classOf[UUID])) + Option(new NBTItem(item).getOrNull[UUID](NBTTagConstants.producerUuidTag, classOf[UUID])) def deathMessages(playerName: String, cookieProducerName: String): Seq[String] = Seq( s"${playerName}は${cookieProducerName}のチョコチップクッキーを食べた!猟奇的な味だった。", diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineListener.scala index 689ed38b76..3c2050bfca 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seasonalevents/valentine/ValentineListener.scala @@ -10,11 +10,11 @@ import com.github.unchama.seichiassist.subsystems.seasonalevents.valentine.Valen import com.github.unchama.seichiassist.subsystems.seasonalevents.valentine.ValentineCookieEffectsHandler._ import com.github.unchama.seichiassist.subsystems.seasonalevents.valentine.ValentineItemData._ import com.github.unchama.seichiassist.util.InventoryOperations.grantItemStacksEffect -import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreference +import com.github.unchama.seichiassist.util.SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO import com.github.unchama.targetedeffect.commandsender.MessageEffect import com.github.unchama.targetedeffect.player.FocusedSoundEffect import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffect} -import de.tr7zw.itemnbtapi.NBTItem +import de.tr7zw.nbtapi.NBTItem import org.bukkit.ChatColor._ import org.bukkit.Sound import org.bukkit.attribute.Attribute @@ -56,7 +56,7 @@ class ValentineListener[F[_]: ConcurrentEffect: NonServerThreadContextShift]( val damager = event.getDamager if (damager == null || damager.getType != EntityType.CREEPER) return - val excludedMonsters = Set(EntityType.WITCH, EntityType.PIG_ZOMBIE) + val excludedMonsters = Set(EntityType.WITCH, EntityType.ZOMBIFIED_PIGLIN) event.getEntity match { case damaged: Monster if !excludedMonsters.contains(damaged.getType) => val entityMaxHealth = damaged.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue @@ -139,7 +139,8 @@ class ValentineListener[F[_]: ConcurrentEffect: NonServerThreadContextShift]( player.getName, new NBTItem(item).getString(NBTTagConstants.producerNameTag) ) - sendMessageToEveryoneIgnoringPreference(messages(new Random().nextInt(messages.size))) + sendMessageToEveryoneIgnoringPreferenceIO(messages(new Random().nextInt(messages.size))) + .unsafeRunAsyncAndForget() } player.playSound(player.getLocation, Sound.ENTITY_WITCH_DRINK, 1.0f, 1.2f) } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/System.scala index abbaca504c..aab6684b24 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/System.scala @@ -1,7 +1,6 @@ package com.github.unchama.seichiassist.subsystems.seichilevelupgift import cats.effect.Async -import com.github.unchama.generic.ContextCoercion import com.github.unchama.generic.effect.stream.StreamExtra import com.github.unchama.minecraft.actions.{OnMinecraftServerThread, SendMinecraftMessage} import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountReadAPI @@ -17,9 +16,7 @@ import org.bukkit.inventory.ItemStack object System { - def backGroundProcess[F[_]: OnMinecraftServerThread: ErrorLogger: Async, G[ - _ - ]: ContextCoercion[*[_], F]]( + def backGroundProcess[F[_]: OnMinecraftServerThread: ErrorLogger: Async, G[_]]( implicit breakCountReadApi: BreakCountReadAPI[F, G, Player], send: SendMinecraftMessage[F, Player], gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/bukkit/BukkitGrantLevelUpGift.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/bukkit/BukkitGrantLevelUpGift.scala index b5437bdd97..473fa15998 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/bukkit/BukkitGrantLevelUpGift.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/seichilevelupgift/bukkit/BukkitGrantLevelUpGift.scala @@ -1,8 +1,6 @@ package com.github.unchama.seichiassist.subsystems.seichilevelupgift.bukkit import cats.data.Kleisli -import cats.effect.Sync -import com.github.unchama.generic.ContextCoercion import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.data.ItemData import com.github.unchama.seichiassist.subsystems.gacha.GachaDrawAPI @@ -17,9 +15,7 @@ import com.github.unchama.seichiassist.util.InventoryOperations.grantItemStacksE import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack -class BukkitGrantLevelUpGift[F[_]: Sync: OnMinecraftServerThread, G[_]: ContextCoercion[*[ - _ -], F]]( +class BukkitGrantLevelUpGift[F[_]: OnMinecraftServerThread, G[_]]( implicit gachaPointApi: GachaPointApi[F, G, Player], gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], gachaDrawAPI: GachaDrawAPI[F, Player] @@ -43,7 +39,7 @@ class BukkitGrantLevelUpGift[F[_]: Sync: OnMinecraftServerThread, G[_]: ContextC object BukkitGrantLevelUpGift { - implicit def apply[F[_]: Sync: OnMinecraftServerThread, G[_]: ContextCoercion[*[_], F]]( + implicit def apply[F[_]: OnMinecraftServerThread, G[_]]( implicit gachaPrizeAPI: GachaPrizeAPI[F, ItemStack, Player], gachaPointApi: GachaPointApi[F, G, Player], gachaDrawAPI: GachaDrawAPI[F, Player] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/System.scala index f9758db42b..9c8ca2dbab 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/System.scala @@ -1,6 +1,7 @@ package com.github.unchama.seichiassist.subsystems.sharedinventory import cats.effect.{Concurrent, ConcurrentEffect, Timer} +import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.meta.subsystem.Subsystem import com.github.unchama.seichiassist.subsystems.sharedinventory.bukkit.command.ShareInventoryCommand import com.github.unchama.seichiassist.subsystems.sharedinventory.domain.bukkit.InventoryContents @@ -23,7 +24,8 @@ object System { import cats.implicits._ - def wired[F[_]: ConcurrentEffect: Timer, G[_]: Concurrent]: G[System[F]] = { + def wired[F[_]: ConcurrentEffect: Timer: OnMinecraftServerThread, G[_]: Concurrent] + : G[System[F]] = { implicit val persistence: SharedInventoryPersistence[F] = new JdbcSharedInventoryPersistence[F] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/bukkit/command/ShareInventoryCommand.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/bukkit/command/ShareInventoryCommand.scala index 93347afcdd..7cf7009c98 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/bukkit/command/ShareInventoryCommand.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/sharedinventory/bukkit/command/ShareInventoryCommand.scala @@ -1,106 +1,104 @@ package com.github.unchama.seichiassist.subsystems.sharedinventory.bukkit.command -import cats.effect.ConcurrentEffect.ops.toAllConcurrentEffectOps -import cats.effect.{ConcurrentEffect, IO, Sync} +import cats.data.Kleisli +import cats.effect.{ConcurrentEffect, Sync} +import com.github.unchama.minecraft.actions.OnMinecraftServerThread import com.github.unchama.seichiassist.commands.contextual.builder.BuilderTemplates.playerCommandBuilder -import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread import com.github.unchama.seichiassist.subsystems.sharedinventory.SharedInventoryAPI import com.github.unchama.seichiassist.subsystems.sharedinventory.domain.SharedFlag import com.github.unchama.seichiassist.subsystems.sharedinventory.domain.bukkit.InventoryContents import com.github.unchama.seichiassist.util.InventoryOperations -import com.github.unchama.targetedeffect.commandsender.MessageEffect -import com.github.unchama.targetedeffect.player.CommandEffect -import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffect} +import com.github.unchama.targetedeffect.commandsender.MessageEffectF +import com.github.unchama.targetedeffect.player.CommandEffectF +import com.github.unchama.targetedeffect.{SequentialEffect, TargetedEffectF} import org.bukkit.ChatColor._ import org.bukkit.command.TabExecutor import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import org.bukkit.{Bukkit, Material} -class ShareInventoryCommand[F[_]: ConcurrentEffect]( +class ShareInventoryCommand[F[_]: ConcurrentEffect: OnMinecraftServerThread]( implicit sharedInventoryAPI: SharedInventoryAPI[F, Player] ) { import cats.implicits._ val executor: TabExecutor = playerCommandBuilder - .buildWithExecutionF { context => + .buildWithExecutionCSEffect { context => val sender = context.sender - for { - // TODO: this `toIO` is not needed - sharedFlag <- sharedInventoryAPI.sharedFlag(sender).toIO - eff <- - if (sharedFlag == SharedFlag.Sharing) { - withdrawFromSharedInventory(sender) - } else { - depositToSharedInventory(sender) - } - } yield eff + + Kleisli.liftF(sharedInventoryAPI.sharedFlag(sender)).flatMap { sharedFlag => + if (sharedFlag == SharedFlag.Sharing) { + withdrawFromSharedInventory(sender) + } else { + depositToSharedInventory(sender) + } + } } .asNonBlockingTabExecutor() - private def withdrawFromSharedInventory(player: Player): IO[TargetedEffect[Player]] = { + private def withdrawFromSharedInventory(player: Player): TargetedEffectF[F, Player] = { val uuid = player.getUniqueId - val eff = for { - oldSharedFlag <- sharedInventoryAPI.sharedFlag(player) - loadedInventory <- sharedInventoryAPI.load(uuid) - _ <- sharedInventoryAPI.clear(uuid) - newSharedFlag <- sharedInventoryAPI.sharedFlag(player) - _ <- Sync[F] - .delay { - val playerInventory = player.getInventory - val inventoryContents = loadedInventory.get.inventoryContents - // 手持ちのアイテムをドロップする - playerInventory - .getContents - .filterNot(itemStack => itemStack == null || itemStack.getType == Material.AIR) - .foreach(itemStack => dropIfNotEmpty(Some(itemStack), player)) - // 取り出したアイテムをセットする - playerInventory.setContents(inventoryContents.toArray) - Bukkit.getLogger.info(s"${player.getName}がアイテム取り出しを実施(DB)書き換え成功") - } - .whenA(oldSharedFlag != newSharedFlag && loadedInventory.nonEmpty) + (for { + oldSharedFlag <- Kleisli.liftF(sharedInventoryAPI.sharedFlag(player)) + loadedInventory <- Kleisli.liftF(sharedInventoryAPI.load(uuid)) + _ <- Kleisli.liftF(sharedInventoryAPI.clear(uuid)) + newSharedFlag <- Kleisli.liftF(sharedInventoryAPI.sharedFlag(player)) + _ <- Kleisli.liftF( + Sync[F] + .delay { + val playerInventory = player.getInventory + val inventoryContents = loadedInventory.get.inventoryContents + // 手持ちのアイテムをドロップする + playerInventory + .getContents + .filterNot(itemStack => itemStack == null || itemStack.getType == Material.AIR) + .foreach(itemStack => dropIfNotEmpty(Some(itemStack), player)) + // 取り出したアイテムをセットする + playerInventory.setContents(inventoryContents.toArray) + Bukkit.getLogger.info(s"${player.getName}がアイテム取り出しを実施(DB)書き換え成功") + } + .whenA(oldSharedFlag != newSharedFlag && loadedInventory.nonEmpty) + ) } yield { if (oldSharedFlag != newSharedFlag && loadedInventory.nonEmpty) - MessageEffect(s"${GREEN}アイテムを取得しました。手持ちにあったアイテムはドロップしました。") + MessageEffectF(s"${GREEN}アイテムを取得しました。手持ちにあったアイテムはドロップしました。") else if (oldSharedFlag == newSharedFlag) - MessageEffect(s"$RESET$RED${BOLD}もう少し待ってからアイテム取り出しを行ってください。") + MessageEffectF(s"$RESET$RED${BOLD}もう少し待ってからアイテム取り出しを行ってください。") else - MessageEffect(s"$RESET$RED${BOLD}収納アイテムが存在しません。") - } - - eff.toIO + MessageEffectF(s"$RESET$RED${BOLD}収納アイテムが存在しません。") + }).flatten } - private def depositToSharedInventory(player: Player): IO[TargetedEffect[Player]] = { + private def depositToSharedInventory(player: Player): TargetedEffectF[F, Player] = { val uuid = player.getUniqueId val playerInventory = player.getInventory val inventoryContents = playerInventory.getContents.toList if (inventoryContents.forall(_ == null)) - return IO.pure(MessageEffect(s"$RESET$RED${BOLD}収納アイテムが存在しません。")) + return MessageEffectF(s"$RESET$RED${BOLD}収納アイテムが存在しません。") - val eff = for { - oldSharedFlag <- sharedInventoryAPI.sharedFlag(player) - _ <- sharedInventoryAPI.save(uuid, InventoryContents(inventoryContents)) - newSharedFlag <- sharedInventoryAPI.sharedFlag(player) - _ <- Sync[F] - .delay { - playerInventory.clear() - Bukkit.getLogger.info(s"${player.getName}がアイテム収納を実施(SQL送信成功)") - } - .whenA(oldSharedFlag != newSharedFlag) + (for { + oldSharedFlag <- Kleisli.liftF(sharedInventoryAPI.sharedFlag(player)) + _ <- Kleisli.liftF(sharedInventoryAPI.save(uuid, InventoryContents(inventoryContents))) + newSharedFlag <- Kleisli.liftF(sharedInventoryAPI.sharedFlag(player)) + _ <- Kleisli.liftF( + Sync[F] + .delay { + playerInventory.clear() + Bukkit.getLogger.info(s"${player.getName}がアイテム収納を実施(SQL送信成功)") + } + .whenA(oldSharedFlag != newSharedFlag) + ) } yield { if (oldSharedFlag == newSharedFlag) - MessageEffect(s"$RESET$RED${BOLD}もう少し待ってからアイテムを収納してください。") + MessageEffectF(s"$RESET$RED${BOLD}もう少し待ってからアイテムを収納してください。") else SequentialEffect( - CommandEffect("stick"), - MessageEffect(s"${GREEN}アイテムを収納しました。10秒以上あとに、手持ちを空にして取り出してください。") + CommandEffectF("stick"), + MessageEffectF(s"${GREEN}アイテムを収納しました。10秒以上あとに、手持ちを空にして取り出してください。") ) - } - - eff.toIO + }).flatten } private def dropIfNotEmpty(itemStackOption: Option[ItemStack], to: Player): Unit = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/listeners/GachaTradeListener.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/listeners/GachaTradeListener.scala index dc31b743fe..4cb3e1dfce 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/listeners/GachaTradeListener.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/listeners/GachaTradeListener.scala @@ -39,7 +39,7 @@ class GachaTradeListener[F[_]: ConcurrentEffect, G[_]](rule: GachaTradeRule[Item // インベントリサイズが6列でない時終了 if (inventory.row != 6) return - if (inventory.getTitle != s"$LIGHT_PURPLE${BOLD}交換したい景品を入れてください") return + if (event.getView.getTitle != s"$LIGHT_PURPLE${BOLD}交換したい景品を入れてください") return // 交換後の情報 val tradedInformation = diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/traderules/BukkitTrade.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/traderules/BukkitTrade.scala index 9bfae53479..d950c96fd6 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/traderules/BukkitTrade.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gachatrade/bukkit/traderules/BukkitTrade.scala @@ -1,6 +1,5 @@ package com.github.unchama.seichiassist.subsystems.tradesystems.subsystems.gachatrade.bukkit.traderules -import com.github.unchama.generic.ListExtra import com.github.unchama.seichiassist.subsystems.gachaprize.bukkit.factories.BukkitGachaSkullData import com.github.unchama.seichiassist.subsystems.gachaprize.domain.GachaRarity.GachaRarity import com.github.unchama.seichiassist.subsystems.gachaprize.domain.GachaRarity.GachaRarity._ @@ -44,7 +43,7 @@ class BukkitTrade(owner: String, gachaPrizeTable: Vector[GachaPrizeTableEntry[It } val (nonTradable, tradable) = - ListExtra.partitionWith(contents) { itemStack => + contents.partitionMap { itemStack => if (bigList.exists(_.isSimilar(itemStack))) Right(BigOrRegular.Big -> itemStack.getAmount) else if (regularList.exists(_.isSimilar(itemStack))) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/BukkitStaticTradeItemFactory.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/BukkitStaticTradeItemFactory.scala index 58b97594fb..aaa05f58b2 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/BukkitStaticTradeItemFactory.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/BukkitStaticTradeItemFactory.scala @@ -11,9 +11,8 @@ import scala.util.chaining.scalaUtilChainingOps object BukkitStaticTradeItemFactory extends StaticTradeItemFactory[ItemStack] { override val getMaxRingo: String => ItemStack = (name: String) => - new ItemStack(Material.GOLDEN_APPLE, 1).tap { itemStack => + new ItemStack(Material.ENCHANTED_GOLDEN_APPLE, 1).tap { itemStack => import itemStack._ - setDurability(1.toShort) val meta = getItemMeta meta.setDisplayName(s"$YELLOW$BOLD${ITALIC}椎名林檎") meta.setLore( diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/listeners/GtToSiinaringo.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/listeners/GtToSiinaringo.scala index e09ac172a9..1b1b1c65e4 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/listeners/GtToSiinaringo.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/tradesystems/subsystems/gttosiina/bukkit/listeners/GtToSiinaringo.scala @@ -36,7 +36,7 @@ class GtToSiinaringo[F[_]: ConcurrentEffect]( // インベントリサイズが4列でない時終了 if (inventory.row != 4) return - if (inventory.getTitle != s"$GOLD${BOLD}椎名林檎と交換したい景品を入れてネ") return + if (event.getView.getTitle != s"$GOLD${BOLD}椎名林檎と交換したい景品を入れてネ") return // 交換後の情報 val tradedInformation = new BukkitTrade(name, gachaPrizeAPI.allGachaPrizeList.toIO.unsafeRunSync()) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/System.scala index df672e185d..004a5794ce 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/System.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/System.scala @@ -43,7 +43,7 @@ object System { override def togglePlaySoundOnSpeech: Kleisli[F, Player, Unit] = Kleisli { player => for { fairyPlaySound <- playSoundOnSpeech(player.getUniqueId) - _ <- persistence.setPlaySoundOnSpeech(player.getUniqueId, fairyPlaySound) + _ <- persistence.setPlaySoundOnSpeech(player.getUniqueId, !fairyPlaySound) } yield () } diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/bukkit/BukkitFairySpeechGateway.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/bukkit/BukkitFairySpeechGateway.scala index 5cee695de1..9f6b05cb6c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/bukkit/BukkitFairySpeechGateway.scala +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/vote/subsystems/fairyspeech/bukkit/BukkitFairySpeechGateway.scala @@ -24,11 +24,11 @@ class BukkitFairySpeechGateway[F[_]: Sync: Timer](player: Player) import cats.implicits._ override def playSpeechSound: F[Unit] = for { - _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_PLING, 2.0f, 1.0f).run(player) + _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_BLOCK_PLING, 2.0f, 1.0f).run(player) _ <- Timer[F].sleep(100.millis) - _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_PLING, 2.0f, 1.5f).run(player) + _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_BLOCK_PLING, 2.0f, 1.5f).run(player) _ <- Timer[F].sleep(100.millis) - _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_PLING, 2.0f, 2.0f).run(player) + _ <- FocusedSoundEffectF(Sound.BLOCK_NOTE_BLOCK_PLING, 2.0f, 2.0f).run(player) } yield {} } diff --git a/src/main/scala/com/github/unchama/seichiassist/task/GiganticBerserkTask.scala b/src/main/scala/com/github/unchama/seichiassist/task/GiganticBerserkTask.scala index 37ee8ffdb4..fc74f93b88 100644 --- a/src/main/scala/com/github/unchama/seichiassist/task/GiganticBerserkTask.scala +++ b/src/main/scala/com/github/unchama/seichiassist/task/GiganticBerserkTask.scala @@ -1,7 +1,6 @@ package com.github.unchama.seichiassist.task import cats.effect.{ConcurrentEffect, IO, SyncIO} -import com.github.unchama.concurrent.NonServerThreadContextShift import com.github.unchama.seichiassist.data.player.PlayerData import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI import com.github.unchama.seichiassist.subsystems.mana.ManaApi @@ -15,9 +14,7 @@ import org.bukkit.entity.Player import scala.util.Random class GiganticBerserkTask { - def PlayerKillEnemy[F[ - _ - ]: ConcurrentEffect: NonServerThreadContextShift: DiscordNotificationAPI]( + def PlayerKillEnemy[F[_]: ConcurrentEffect: DiscordNotificationAPI]( p: Player )(implicit manaApi: ManaApi[IO, SyncIO, Player]): Unit = { val player = p @@ -35,7 +32,7 @@ class GiganticBerserkTask { // 確率でマナを回復させる val d = Math.random - if (d < playerdata.giganticBerserk.manaRegenerationProbability) { + if (d < playerdata.giganticBerserk.manaRegenerationProbability()) { if (playerdata.giganticBerserk.reachedLimit()) { manaApi.manaAmount(p).restoreCompletely.unsafeRunSync() player.sendMessage( @@ -92,9 +89,8 @@ class GiganticBerserkTask { val program = List( DiscordNotificationAPI[F].sendPlainText(messageWithoutColor).toIO, IO { - SendSoundEffect.sendEverySound(Sound.ENTITY_ENDERDRAGON_DEATH, 1, 1.2f) - SendMessageEffect.sendMessageToEveryoneIgnoringPreference(messageWithColor) - } + SendSoundEffect.sendEverySound(Sound.ENTITY_ENDER_DRAGON_DEATH, 1, 1.2f) + } >> SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO(messageWithColor) ).sequence program.unsafeRunAsyncAndForget() diff --git a/src/main/scala/com/github/unchama/seichiassist/task/PlayerDataSaveTask.scala b/src/main/scala/com/github/unchama/seichiassist/task/PlayerDataSaveTask.scala index 98f9160091..361712165e 100644 --- a/src/main/scala/com/github/unchama/seichiassist/task/PlayerDataSaveTask.scala +++ b/src/main/scala/com/github/unchama/seichiassist/task/PlayerDataSaveTask.scala @@ -166,19 +166,20 @@ object PlayerDataSaveTask { .delay { println(s"$RED${playerdata.name}のプレイヤーデータ保存失敗") } - .as(Right(ActionStatus.Fail)) - } else + .as(Right(())) + } else { commitUpdate.flatMap { result => if (result == ActionStatus.Ok) { Sync[F] .delay { println(s"$GREEN${player.getName}のプレイヤーデータ保存完了") } - .as(Right(ActionStatus.Ok)) + .as(Right(())) } else { Monad[F].pure(Left(remaining - 1)) } } + } } } } diff --git a/src/main/scala/com/github/unchama/seichiassist/task/global/PlayerDataBackupRoutine.scala b/src/main/scala/com/github/unchama/seichiassist/task/global/PlayerDataBackupRoutine.scala index 957646237c..ab5653c732 100644 --- a/src/main/scala/com/github/unchama/seichiassist/task/global/PlayerDataBackupRoutine.scala +++ b/src/main/scala/com/github/unchama/seichiassist/task/global/PlayerDataBackupRoutine.scala @@ -27,8 +27,10 @@ object PlayerDataBackupRoutine { import scala.jdk.CollectionConverters._ for { + _ <- SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO( + s"${AQUA}プレイヤーデータセーブ中…" + ) _ <- IO { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference(s"${AQUA}プレイヤーデータセーブ中…") Bukkit.getLogger.info(s"${AQUA}プレイヤーデータセーブ中…") } players <- IO { @@ -38,8 +40,10 @@ object PlayerDataBackupRoutine { PlayerDataSaveTask .savePlayerData[IO](player, SeichiAssist.playermap(player.getUniqueId)) } + _ <- SendMessageEffect.sendMessageToEveryoneIgnoringPreferenceIO( + s"${AQUA}プレイヤーデータセーブ完了" + ) _ <- IO { - SendMessageEffect.sendMessageToEveryoneIgnoringPreference(s"${AQUA}プレイヤーデータセーブ完了") Bukkit.getLogger.info(s"${AQUA}プレイヤーデータセーブ完了") } } yield () diff --git a/src/main/scala/com/github/unchama/seichiassist/util/BreakUtil.scala b/src/main/scala/com/github/unchama/seichiassist/util/BreakUtil.scala index 4ad89f1da6..89902ed84c 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/BreakUtil.scala +++ b/src/main/scala/com/github/unchama/seichiassist/util/BreakUtil.scala @@ -3,7 +3,6 @@ package com.github.unchama.seichiassist.util import cats.Monad import cats.effect.{IO, SyncIO} import com.github.unchama.generic.ApplicativeExtra.whenAOrElse -import com.github.unchama.generic.effect.unsafe.EffectEnvironment import com.github.unchama.seichiassist.MaterialSets.{BlockBreakableBySkill, BreakTool} import com.github.unchama.seichiassist._ import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts @@ -19,18 +18,18 @@ import com.github.unchama.seichiassist.subsystems.breakcount.domain.level.Seichi import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.domain.BreakSkillTargetConfigKey import com.github.unchama.targetedeffect.player.ActionBarMessageEffect import com.github.unchama.util.bukkit.ItemStackUtil -import com.github.unchama.util.external.ExternalPlugins +import com.github.unchama.util.external.{ExternalPlugins, WorldGuardWrapper} import org.bukkit.ChatColor._ import org.bukkit.World.Environment import org.bukkit._ -import org.bukkit.block.Block +import org.bukkit.block.{Block, Container} import org.bukkit.enchantments.Enchantment import org.bukkit.entity.{Entity, EntityType, Player} import org.bukkit.inventory.ItemStack -import org.bukkit.material.Dye import java.util.Random import java.util.stream.IntStream +import scala.jdk.CollectionConverters._ object BreakUtil { @@ -66,7 +65,11 @@ object BreakUtil { val playerData = SeichiAssist.playermap(player.getUniqueId) // 壊されるブロックがワールドガード範囲だった場合処理を終了 - if (!ExternalPlugins.getWorldGuard.canBuild(player, checkTarget.getLocation)) { + if ( + !WorldGuardWrapper.canBuild(player, checkTarget.getLocation) && ManagedWorld + .fromBukkitWorld(checkTarget.getWorld) + .forall(_.shouldMuteCoreProtect) + ) { if (playerData.settings.shouldDisplayWorldGuardLogs) { player.sendMessage(s"${RED}ワールドガードで保護されています。") } @@ -102,9 +105,8 @@ object BreakUtil { } val isBlockProtectedSlab = - checkTarget.getType == Material.STEP && - checkTarget.getY == halfBlockLayerYCoordinate && - checkTarget.getData == 0.toByte + checkTarget.getType == Material.STONE_SLAB && + checkTarget.getY == halfBlockLayerYCoordinate if (isBlockProtectedSlab) return false } @@ -125,26 +127,26 @@ object BreakUtil { } def isProtectedChest(player: Player, checkTarget: Block): Boolean = { - checkTarget.getType match { - case Material.CHEST | Material.TRAPPED_CHEST => - if ( - !SeichiAssist - .instance - .breakSkillTargetConfigSystem - .api - .breakSkillTargetConfig(player, BreakSkillTargetConfigKey.Chest) - .unsafeRunSync() - ) { - ActionBarMessageEffect(s"${RED}スキルでのチェスト破壊は無効化されています").run(player).unsafeRunSync() - true - } else if (!player.getWorld.isSeichi) { - ActionBarMessageEffect(s"${RED}スキルでのチェスト破壊は整地ワールドでのみ有効です").run(player).unsafeRunSync() - true - } else { - false - } - case _ => false - } + if ( + checkTarget.getType == Material.CHEST || checkTarget.getType == Material.TRAPPED_CHEST + ) { + if ( + !SeichiAssist + .instance + .breakSkillTargetConfigSystem + .api + .breakSkillTargetConfig(player, BreakSkillTargetConfigKey.Chest) + .unsafeRunSync() + ) { + ActionBarMessageEffect(s"${RED}スキルでのチェスト破壊は無効化されています").run(player).unsafeRunSync() + true + } else if (!player.getWorld.isSeichi) { + ActionBarMessageEffect(s"${RED}スキルでのチェスト破壊は整地ワールドでのみ有効です").run(player).unsafeRunSync() + true + } else { + false + } + } else false } /** @@ -157,9 +159,8 @@ object BreakUtil { val materialType = targetBlock.getType val isNotQuartzBlockAndQuartzStairs = materialType != Material.QUARTZ_BLOCK && materialType != Material.QUARTZ_STAIRS - // NOTE: targetBlock#getDataが7は下つきハーフブロック、15は上つきハーフブロック val isNotQuartzSlab = - materialType != Material.STEP || (targetBlock.getData != 7.toByte && targetBlock.getData != 15.toByte) + materialType != Material.QUARTZ_SLAB val isNotMadeFromQuartz = isNotQuartzBlockAndQuartzStairs && isNotQuartzSlab if (isNotMadeFromQuartz) { return true @@ -185,214 +186,6 @@ object BreakUtil { world.shouldMuteCoreProtect } - // ブロックを破壊する処理、ドロップも含む、統計増加も含む - def breakBlock( - player: Player, - targetBlock: BlockBreakableBySkill, - dropLocation: Location, - tool: BreakTool, - shouldPlayBreakSound: Boolean - )(implicit effectEnvironment: EffectEnvironment): Unit = - effectEnvironment.unsafeRunEffectAsync( - "単一ブロックを破壊する", - massBreakBlock(player, Set(targetBlock), dropLocation, tool, shouldPlayBreakSound) - ) - - sealed trait BlockBreakResult - - object BlockBreakResult { - - case class ItemDrop(itemStack: ItemStack) extends BlockBreakResult - - case class SpawnSilverFish(location: Location) extends BlockBreakResult - - } - - /** - * ブロックをツールで破壊した時のドロップを計算する - * - * Bukkit/Spigotが提供するBlock.getDropsは信頼できる値を返さない。 本来はNMSのメソッドを呼ぶのが確実らしいが、一時的な実装として使用している。 参考: - * https://www.spigotmc.org/threads/getdrops-on-crops-not-functioning-as-expected.167751/#post-1779788 - */ - def dropItemOnTool( - tool: BreakTool - )(blockInformation: (Location, Material, Byte)): Option[BlockBreakResult] = { - val fortuneLevel = tool.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS) - - val (blockLocation, blockMaterial, blockData) = blockInformation - - blockMaterial match { - case Material.GRASS_PATH | Material.SOIL => - return Some(BlockBreakResult.ItemDrop(new ItemStack(Material.DIRT))) - case Material.MOB_SPAWNER | Material.ENDER_PORTAL_FRAME | Material.ENDER_PORTAL => - return None - case _ => - } - - val rand = Math.random() - val bonus = Math.max(1, rand * (fortuneLevel + 2)).toInt - - val blockDataLeast4Bits = (blockData & 0x0f).toByte - val b_tree = (blockData & 0x03).toByte - - val silkTouch = tool.getEnchantmentLevel(Enchantment.SILK_TOUCH) - - if (silkTouch > 0) { - // シルクタッチの処理 - Some { - BlockBreakResult.ItemDrop { - blockMaterial match { - case Material.GLOWING_REDSTONE_ORE => - new ItemStack(Material.REDSTONE_ORE) - case Material.LOG | Material.LOG_2 | Material.LEAVES | Material.LEAVES_2 => - new ItemStack(blockMaterial, 1, b_tree.toShort) - case Material.MONSTER_EGGS => - new ItemStack(Material.STONE) - case Material.WOOD_STEP | Material.STEP | Material.STONE_SLAB2 | - Material.PURPUR_SLAB if (blockDataLeast4Bits & 8) != 0 => - // 上付きハーフブロックのmissing texture化を防ぐ - new ItemStack(blockMaterial, 1, (blockDataLeast4Bits & 7).toShort) - case Material.QUARTZ_BLOCK if (blockData >= 2 && blockData <= 4) => - // 柱状クォーツブロックのmissing texture化を防ぐ - new ItemStack(blockMaterial, 1, 2.toShort) - case _ => - new ItemStack(blockMaterial, 1, blockDataLeast4Bits.toShort) - } - } - } - } else if (fortuneLevel > 0 && MaterialSets.fortuneMaterials.contains(blockMaterial)) { - // 幸運の処理 - Some { - BlockBreakResult.ItemDrop { - blockMaterial match { - case Material.COAL_ORE => - new ItemStack(Material.COAL, bonus) - case Material.DIAMOND_ORE => - new ItemStack(Material.DIAMOND, bonus) - case Material.EMERALD_ORE => - new ItemStack(Material.EMERALD, bonus) - case Material.QUARTZ_ORE => - new ItemStack(Material.QUARTZ, bonus) - // レッドストーン鉱石, グロウストーン, スイカブロック, シーランタン, ラピスラズリ鉱石は、 - // ドロップアイテムの個数を求める計算が通常の鉱石の扱いと異なるため、特別な処理が必要である。 - case Material.REDSTONE_ORE | Material.GLOWING_REDSTONE_ORE => - val withBonus = (rand * (fortuneLevel + 2) + 4).toInt - new ItemStack(Material.REDSTONE, withBonus) - case Material.LAPIS_ORE => - val dye = new Dye() - dye.setColor(DyeColor.BLUE) - // 幸運エンチャントなしで掘った時のアイテムが得られる個数(4~9)に、幸運ボーナスを掛ける - val withBonus = (rand * 6 + 4).toInt * bonus - dye.toItemStack(withBonus) - // グロウストーンは幸運エンチャントがついていると高確率でより多くのダストをドロップする - // しかし、最大でも4個までしかドロップしない - case Material.GLOWSTONE => - val withBonus = (rand * (fortuneLevel + 3) + 2).toInt - val amount = if (withBonus > 4) 4 else withBonus - new ItemStack(Material.GLOWSTONE_DUST, amount) - // 同様に、メロンブロックは幸運エンチャントがついている場合、9個までしかドロップしない - case Material.MELON_BLOCK => - val withBonus = (rand * (fortuneLevel + 5) + 3).toInt - val amount = if (withBonus > 9) 9 else withBonus - new ItemStack(Material.MELON, amount) - case Material.SEA_LANTERN => - val withBonus = (rand * (fortuneLevel + 2) + 2).toInt - val amount = if (withBonus > 5) 5 else withBonus - new ItemStack(Material.PRISMARINE_CRYSTALS, amount) - case _ => - // unreachable - new ItemStack(blockMaterial, bonus) - } - } - } - } else { - // シルク幸運なしの処理 - blockMaterial match { - case Material.COAL_ORE => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.COAL))) - case Material.DIAMOND_ORE => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.DIAMOND))) - case Material.LAPIS_ORE => - val dye = new Dye() - dye.setColor(DyeColor.BLUE) - Some(BlockBreakResult.ItemDrop(dye.toItemStack((rand * 6 + 4).toInt))) - case Material.EMERALD_ORE => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.EMERALD))) - case Material.REDSTONE_ORE | Material.GLOWING_REDSTONE_ORE => - Some( - BlockBreakResult.ItemDrop(new ItemStack(Material.REDSTONE, ((rand * 2) + 4).toInt)) - ) - case Material.QUARTZ_ORE => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.QUARTZ))) - // グロウストーンは、2から4個のグロウストーンダストをドロップする - case Material.GLOWSTONE => - Some( - BlockBreakResult - .ItemDrop(new ItemStack(Material.GLOWSTONE_DUST, (rand * 3 + 2).toInt)) - ) - // スイカブロックは、3から7個のスイカをドロップする - case Material.MELON_BLOCK => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.MELON, (rand * 5 + 3).toInt))) - // シーランタンは、2から3個のプリズマリンクリスタルをドロップする - case Material.SEA_LANTERN => - Some( - BlockBreakResult - .ItemDrop(new ItemStack(Material.PRISMARINE_CRYSTALS, (rand * 2 + 2).toInt)) - ) - case Material.STONE => - Some { - BlockBreakResult.ItemDrop { - if (blockData.toInt == 0x00) { - // 焼き石の処理 - new ItemStack(Material.COBBLESTONE) - } else { - // 他の石の処理 - new ItemStack(blockMaterial, 1, blockDataLeast4Bits.toShort) - } - } - } - case Material.GRASS => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.DIRT))) - case Material.GRAVEL => - val p = fortuneLevel match { - case 1 => 0.14 - case 2 => 0.25 - case 3 => 1.00 - case _ => 0.1 - } - val dropMaterial = if (p > rand) Material.FLINT else Material.GRAVEL - - Some(BlockBreakResult.ItemDrop(new ItemStack(dropMaterial, bonus))) - case Material.LEAVES | Material.LEAVES_2 => - None - case Material.CLAY => - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.CLAY_BALL, 4))) - case Material.MONSTER_EGGS => - Some(BlockBreakResult.SpawnSilverFish(blockLocation)) - case Material.LOG | Material.LOG_2 => - Some(BlockBreakResult.ItemDrop(new ItemStack(blockMaterial, 1, b_tree.toShort))) - case Material.WOOD_STEP | Material.STEP | Material.STONE_SLAB2 | Material.PURPUR_SLAB - if (blockDataLeast4Bits & 8) != 0 => - // 上付きハーフブロックをそのままドロップするとmissing textureとして描画されるため、下付きの扱いとする - Some( - BlockBreakResult - .ItemDrop(new ItemStack(blockMaterial, 1, (blockDataLeast4Bits & 7).toShort)) - ) - case Material.QUARTZ_BLOCK if (blockData >= 2 && blockData <= 4) => - // 柱状クォーツブロックのmissing texture化を防ぐ (柱状クォーツのData valueは2, 3, 4のいずれか) - Some(BlockBreakResult.ItemDrop(new ItemStack(blockMaterial, 1, 2.toShort))) - case Material.BOOKSHELF => - // 本棚を破壊すると、本が3つドロップする - Some(BlockBreakResult.ItemDrop(new ItemStack(Material.BOOK, 3))) - case _ => - Some( - BlockBreakResult - .ItemDrop(new ItemStack(blockMaterial, 1, blockDataLeast4Bits.toShort)) - ) - } - } - } - /** * TODO: これはビジネスロジックである。breakcountシステムによって管理されるべき。 * @@ -417,10 +210,10 @@ object BreakUtil { def totalBreakCount(materials: Seq[Material]): Long = materials .filter(MaterialSets.materialsToCountBlockBreak.contains) - .map { + .map { m => // 氷塊とマグマブロックの整地量を2倍 - case Material.PACKED_ICE | Material.MAGMA => 2L - case _ => 1L + if (m == Material.PACKED_ICE || m == Material.MAGMA_BLOCK) 2L + else 1L } .sum @@ -446,34 +239,46 @@ object BreakUtil { targetBlocksInformation <- PluginExecutionContexts .onMainThread .runAction(SyncIO { - val seq: Seq[(Location, Material, Byte)] = targetBlocks + val seq: Seq[(Location, Block, Vector[ItemStack])] = targetBlocks .toSeq .filter { block => - block.getType match { - case Material.AIR => - if (SeichiAssist.DEBUG) - Bukkit.getLogger.warning(s"AIRの破壊が${block.getLocation.toString}にて試行されました。") - false - case _ => true - } + if (block.getType == Material.AIR) { + if (SeichiAssist.DEBUG) + Bukkit.getLogger.warning(s"AIRの破壊が${block.getLocation.toString}にて試行されました。") + false + } else true } - .map(block => (block.getLocation.clone(), block.getType, block.getData)) + .map { block => + val containerItemStacks = block.getState match { + case container: Container => + container.getInventory.getContents.toVector + case _ => + Vector.empty + } - // ブロックをすべて[[toMaterial]]に変える - targetBlocks.foreach(_.setType(toMaterial)) + (block.getLocation.clone(), block, containerItemStacks) + } seq }) breakResults = { - val plainBreakResult = targetBlocksInformation.flatMap(dropItemOnTool(miningTool)) - val drops = plainBreakResult.mapFilter { - case BlockBreakResult.ItemDrop(itemStack) => Some(itemStack) - case BlockBreakResult.SpawnSilverFish(_) => None + val plainBreakResult = targetBlocksInformation.map { + case (location, block, containerItemStacks) => + val clonedTool = miningTool.clone() + clonedTool.setType(Material.NETHERITE_PICKAXE) + (location, block.getDrops(clonedTool, player).asScala ++ containerItemStacks) } + val drops = plainBreakResult.mapFilter { + case (_, drops) if drops.nonEmpty => Some(drops) + case _ => None + }.flatten val silverFishLocations = plainBreakResult.mapFilter { - case BlockBreakResult.ItemDrop(_) => None - case BlockBreakResult.SpawnSilverFish(location) => Some(location) + case (location, _) + if location.getBlock.getType == Material.INFESTED_STONE && !miningTool + .containsEnchantment(Enchantment.SILK_TOUCH) => + Some(location) + case _ => None } // 纏めなければ、FAWEの干渉を受け勝手に消される危険性などがある @@ -502,18 +307,29 @@ object BreakUtil { ).map(Option.unless(_)(itemStack)) } + // NOTE: SpigotのBlockはLocationを保存しているため、Blockを置き換える前にMaterialとして + // 保存しておかないとすべてMaterial.AIRとして取得されてしまう + breakMaterials = targetBlocksInformation.map { case (_, block, _) => block.getType } + + _ <- PluginExecutionContexts + .onMainThread + .runAction(SyncIO { + // ブロックをすべて[[toMaterial]]に変える + targetBlocks.foreach(_.setType(toMaterial)) + }) + _ <- IO { // 壊した時の音を再生する if (shouldPlayBreakSound) { targetBlocksInformation.foreach { - case (location, material, _) => - dropLocation.getWorld.playEffect(location, Effect.STEP_SOUND, material) + case (location, block, _) => + dropLocation.getWorld.playEffect(location, Effect.STEP_SOUND, block) } } } // プレイヤーの統計を増やす - totalCount = totalBreakCount(targetBlocksInformation.map { case (_, m, _) => m }) + totalCount = totalBreakCount(breakMaterials) blockCountWeight <- blockCountWeight[IO](player.getWorld) expIncrease = SeichiExpAmount.ofNonNegative(totalCount * blockCountWeight) @@ -531,6 +347,7 @@ object BreakUtil { // アイテムドロップは非同期スレッドで行ってはならない itemsToBeDropped .flatten + .filterNot(_.getType == Material.AIR) .foreach(dropLocation.getWorld.dropItemNaturally(dropLocation, _)) breakResults._2.foreach { location => location.getWorld.spawnEntity(location, EntityType.SILVERFISH) @@ -569,11 +386,9 @@ object BreakUtil { * ref: [バージョン1.12.x時の最新記事アーカイブ](https://minecraft.fandom.com/wiki/Solid_block?oldid=1132868) */ private def isAffectedByGravity(material: Material): Boolean = { - material match { - case Material.BEDROCK => false - case m if MaterialSets.fluidMaterials.contains(m) || m.isSolid => true - case _ => false - } + if (material == Material.BEDROCK) false + else if (MaterialSets.fluidMaterials.contains(material)) true + else material.isSolid } /** diff --git a/src/main/scala/com/github/unchama/seichiassist/util/EnemyEntity.scala b/src/main/scala/com/github/unchama/seichiassist/util/EnemyEntity.scala index 10de3f680f..bb72bc2cc3 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/EnemyEntity.scala +++ b/src/main/scala/com/github/unchama/seichiassist/util/EnemyEntity.scala @@ -5,15 +5,20 @@ import org.bukkit.entity.EntityType.{ BLAZE, CAVE_SPIDER, CREEPER, + DROWNED, ELDER_GUARDIAN, ENDERMAN, ENDERMITE, EVOKER, GHAST, GUARDIAN, + HOGLIN, HUSK, MAGMA_CUBE, - PIG_ZOMBIE, + PIGLIN, + PIGLIN_BRUTE, + PILLAGER, + RAVAGER, SHULKER, SILVERFISH, SKELETON, @@ -24,8 +29,10 @@ import org.bukkit.entity.EntityType.{ VINDICATOR, WITCH, WITHER_SKELETON, + ZOGLIN, ZOMBIE, - ZOMBIE_VILLAGER + ZOMBIE_VILLAGER, + ZOMBIFIED_PIGLIN } object EnemyEntity { @@ -41,7 +48,7 @@ object EnemyEntity { GUARDIAN, HUSK, MAGMA_CUBE, - PIG_ZOMBIE, + ZOMBIFIED_PIGLIN, SHULKER, SILVERFISH, SKELETON, @@ -53,6 +60,13 @@ object EnemyEntity { WITCH, WITHER_SKELETON, ZOMBIE, - ZOMBIE_VILLAGER + ZOMBIE_VILLAGER, + PIGLIN, + HOGLIN, + DROWNED, + PIGLIN_BRUTE, + PILLAGER, + RAVAGER, + ZOGLIN ).contains(entityType) } diff --git a/src/main/scala/com/github/unchama/seichiassist/util/ItemInformation.scala b/src/main/scala/com/github/unchama/seichiassist/util/ItemInformation.scala index afdfeab6f9..015b1a0510 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/ItemInformation.scala +++ b/src/main/scala/com/github/unchama/seichiassist/util/ItemInformation.scala @@ -1,8 +1,10 @@ package com.github.unchama.seichiassist.util +import com.github.unchama.itemstackbuilder.SkullOwnerUuid +import com.github.unchama.seichiassist.SkullOwners import org.bukkit.ChatColor.GREEN -import org.bukkit.block.{Block, Skull} -import org.bukkit.{Material, SkullType} +import org.bukkit.block.Block +import org.bukkit.Material import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.SkullMeta @@ -11,61 +13,44 @@ import java.util.stream.IntStream object ItemInformation { import scala.jdk.CollectionConverters._ - import scala.util.chaining._ def isGachaTicket(itemStack: ItemStack): Boolean = { val containsRightClickMessage: String => Boolean = _.contains(s"${GREEN}右クリックで使えます") - if (itemStack.getType != Material.SKULL_ITEM) return false + if (itemStack.getType != Material.PLAYER_HEAD) return false val skullMeta = itemStack.getItemMeta.asInstanceOf[SkullMeta] - if (!(skullMeta.hasOwner && skullMeta.getOwner == "unchama")) return false + /* + Note: skullMeta.getOwner == "unchama"という条件は、後方互換性を保つためのコードである。 + 1.12.2のバージョンでskullMeta.getOwnerで頭のオーナーを取得できていたが、 + 1.18.2ではsetOwner、getOwnerともに使用できない。 + そのため、1.18.2からはPlayerProfileにUUIDを書き込み、UUIDを利用した判定を行うことになった。 + + 1.18.2の環境で、1.12.2から持ってきたガチャ券(1.12.2の環境でItemStack化されたもの)からgetOwnerすることが + できなければ該当のコードを削除して良い。 + */ + if ( + !(skullMeta.hasOwner && (SkullOwnerUuid( + skullMeta.getOwningPlayer.getPlayerProfile.getUniqueId + ) == SkullOwners.unchama || skullMeta.getOwner == "unchama")) + ) return false skullMeta.hasLore && skullMeta.getLore.asScala.exists(containsRightClickMessage) } def isMineHeadItem(itemstack: ItemStack): Boolean = { - itemstack.getType == Material.CARROT_STICK && + itemstack.getType == Material.CARROT_ON_A_STICK && loreIndexOf(itemstack.getItemMeta.getLore.asScala.toList, "頭を狩り取る形をしている...") >= 0 } def getSkullDataFromBlock(block: Block): Option[ItemStack] = { - if (block.getType != Material.SKULL) return None - - val skull = block.getState.asInstanceOf[Skull] - val itemStack = new ItemStack(Material.SKULL_ITEM) + if (block.getType != Material.PLAYER_HEAD) return None - // SkullTypeがプレイヤー以外の場合,SkullTypeだけ設定して終わり - if (skull.getSkullType != SkullType.PLAYER) { - val durability = skull.getSkullType match { - case SkullType.CREEPER => SkullType.CREEPER.ordinal.toShort - case SkullType.DRAGON => SkullType.DRAGON.ordinal.toShort - case SkullType.SKELETON => SkullType.SKELETON.ordinal.toShort - case SkullType.WITHER => SkullType.WITHER.ordinal.toShort - case SkullType.ZOMBIE => SkullType.ZOMBIE.ordinal.toShort - case _ => itemStack.getDurability - } - return Some(itemStack.tap(_.setDurability(durability))) - } // プレイヤーの頭の場合,ドロップアイテムからItemStackを取得.データ値をPLAYERにして返す - Some(block.getDrops.asScala.head.tap(_.setDurability(SkullType.PLAYER.ordinal.toShort))) + Some(block.getDrops.asScala.head) } - /** - * 指定された`String`が指定された[[ItemStack]]のloreに含まれているかどうか - * - * @param itemStack - * 確認する`ItemStack` - * @param sentence - * 探す文字列 - * @return - * 含まれていれば`true`、含まれていなければ`false`。ただし、`ItemStack`に`ItemMeta`と`Lore`のいずれかがなければfalse - */ - def isContainedInLore(itemStack: ItemStack, sentence: String): Boolean = - if (!itemStack.hasItemMeta || !itemStack.getItemMeta.hasLore) false - else loreIndexOf(itemStack.getItemMeta.getLore.asScala.toList, sentence) >= 0 - /** * loreを捜査して、要素の中に`find`が含まれているかを調べる。 * diff --git a/src/main/scala/com/github/unchama/seichiassist/util/ItemMetaFactory.java b/src/main/scala/com/github/unchama/seichiassist/util/ItemMetaFactory.java index 6df78bcc77..56811061fa 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/ItemMetaFactory.java +++ b/src/main/scala/com/github/unchama/seichiassist/util/ItemMetaFactory.java @@ -9,5 +9,5 @@ @SuppressWarnings("UtilityClassCanBeEnum") public final class ItemMetaFactory { private static final ItemFactory FACTORY = Bukkit.getItemFactory(); - public static final ValueHolder SKULL = new ValueHolder<>((SkullMeta) FACTORY.getItemMeta(Material.SKULL_ITEM), SkullMeta::clone); + public static final ValueHolder SKULL = new ValueHolder<>((SkullMeta) FACTORY.getItemMeta(Material.PLAYER_HEAD), SkullMeta::clone); } diff --git a/src/main/scala/com/github/unchama/seichiassist/util/PlayerSendable.scala b/src/main/scala/com/github/unchama/seichiassist/util/PlayerSendable.scala index 7b14dcc0a7..a448f5da32 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/PlayerSendable.scala +++ b/src/main/scala/com/github/unchama/seichiassist/util/PlayerSendable.scala @@ -21,7 +21,7 @@ object PlayerSendable { implicit def forStringArray[F[_]: OnMinecraftServerThread] : PlayerSendable[Array[String], F] = { (player, content) => OnMinecraftServerThread[F].runAction(SyncIO { - player.sendMessage(content) + player.sendMessage(content.mkString("\n")) }) } diff --git a/src/main/scala/com/github/unchama/seichiassist/util/SendMessageEffect.scala b/src/main/scala/com/github/unchama/seichiassist/util/SendMessageEffect.scala index 23887c61e2..534cc1c6e5 100644 --- a/src/main/scala/com/github/unchama/seichiassist/util/SendMessageEffect.scala +++ b/src/main/scala/com/github/unchama/seichiassist/util/SendMessageEffect.scala @@ -1,25 +1,15 @@ package com.github.unchama.seichiassist.util import cats.Monad -import cats.effect.IO +import cats.effect.{IO, LiftIO} import com.github.unchama.minecraft.actions.GetConnectedPlayers import com.github.unchama.minecraft.bukkit.actions.GetConnectedBukkitPlayers import com.github.unchama.seichiassist.SeichiAssist import com.github.unchama.seichiassist.concurrent.PluginExecutionContexts.onMainThread -import org.bukkit.Bukkit import org.bukkit.entity.Player object SendMessageEffect { - import scala.jdk.CollectionConverters._ - - @deprecated("It's side-effectful") - def sendMessageToEveryoneIgnoringPreference[T]( - content: T - )(implicit send: PlayerSendable[T, IO]): Unit = { - sendMessageToEveryoneIgnoringPreferenceIO(content).unsafeRunAsyncAndForget() - } - def sendMessageToEveryoneIgnoringPreferenceIO[T: PlayerSendable[*, IO]]( content: T ): IO[Unit] = { @@ -38,23 +28,23 @@ object SendMessageEffect { } yield () } - @deprecated("It's side-effectful") - def sendMessageToEveryone[T](content: T)(implicit ev: PlayerSendable[T, IO]): Unit = { + def sendMessageToEveryone[T, F[_]: Monad: LiftIO: GetConnectedPlayers[*[_], Player]]( + content: T + )(implicit ev: PlayerSendable[T, F]): F[Unit] = { import cats.implicits._ - Bukkit - .getOnlinePlayers - .asScala - .toList - .traverse { player => + for { + players <- GetConnectedPlayers[F, Player].now + _ <- players.traverse { player => for { playerSettings <- SeichiAssist .playermap(player.getUniqueId) .settings .getBroadcastMutingSettings - _ <- IO { if (!playerSettings.shouldMuteMessages) ev.send(player, content) } + .to[F] + _ <- ev.send(player, content).unlessA(playerSettings.shouldMuteMessages) } yield () } - .unsafeRunSync() + } yield () } } diff --git a/src/main/scala/com/github/unchama/targetedeffect/commandsender/MessageEffect.scala b/src/main/scala/com/github/unchama/targetedeffect/commandsender/MessageEffect.scala index 424880affd..32667be2be 100644 --- a/src/main/scala/com/github/unchama/targetedeffect/commandsender/MessageEffect.scala +++ b/src/main/scala/com/github/unchama/targetedeffect/commandsender/MessageEffect.scala @@ -26,6 +26,6 @@ object MessageEffectF { TargetedEffect.delay(_.sendMessage(string)) def apply[F[_]: Sync](stringList: List[String]): Kleisli[F, CommandSender, Unit] = - TargetedEffect.delay(_.sendMessage(stringList.toArray)) + TargetedEffect.delay(_.sendMessage(stringList.mkString("\n"))) } diff --git a/src/main/scala/com/github/unchama/targetedeffect/player/CommandEffect.scala b/src/main/scala/com/github/unchama/targetedeffect/player/CommandEffect.scala index 1da9b76645..fe4e75fd1d 100644 --- a/src/main/scala/com/github/unchama/targetedeffect/player/CommandEffect.scala +++ b/src/main/scala/com/github/unchama/targetedeffect/player/CommandEffect.scala @@ -18,3 +18,12 @@ object CommandEffect { }) } } + +object CommandEffectF { + def apply[F[_]: OnMinecraftServerThread](string: String): Kleisli[F, Player, Unit] = + Kleisli { player => + OnMinecraftServerThread[F].runAction(SyncIO { + player.chat(s"/$string") + }) + } +} diff --git a/src/main/scala/com/github/unchama/targetedeffect/player/PlayerEffects.scala b/src/main/scala/com/github/unchama/targetedeffect/player/PlayerEffects.scala index 564eaaab65..6709c76cdd 100644 --- a/src/main/scala/com/github/unchama/targetedeffect/player/PlayerEffects.scala +++ b/src/main/scala/com/github/unchama/targetedeffect/player/PlayerEffects.scala @@ -9,7 +9,17 @@ import org.bukkit.entity.Player import org.bukkit.inventory.Inventory object PlayerEffects { - val closeInventoryEffect: TargetedEffect[Player] = TargetedEffect.delay(_.closeInventory()) + + def closeInventoryEffect( + implicit onMainThread: OnMinecraftServerThread[IO] + ): TargetedEffect[Player] = { + Kleisli { player => + // インベントリを閉じる操作はサーバースレッドでなければならない(Spigot 1.18.2) + onMainThread.runAction(SyncIO { + player.closeInventory() + }) + } + } def openInventoryEffect( inventory: => Inventory diff --git a/src/main/scala/com/github/unchama/util/bukkit/ItemStackUtil.scala b/src/main/scala/com/github/unchama/util/bukkit/ItemStackUtil.scala index d75eec2460..f0007d3c21 100644 --- a/src/main/scala/com/github/unchama/util/bukkit/ItemStackUtil.scala +++ b/src/main/scala/com/github/unchama/util/bukkit/ItemStackUtil.scala @@ -8,7 +8,7 @@ object ItemStackUtil { * `stacks` に含まれるアイテムスタックをできるだけマージしたような新たな `Seq` を返す */ def amalgamate(stacks: Seq[ItemStack]): Seq[ItemStack] = { - val originals = stacks.map(_.clone()) + val originals = stacks.filterNot(_ == null).map(_.clone()) val result = scala.collection.mutable.ArrayBuffer.empty[ItemStack] diff --git a/src/main/scala/com/github/unchama/util/bukkit/WorldUtil.scala b/src/main/scala/com/github/unchama/util/bukkit/WorldUtil.scala index 985501bf8e..8ceb0b3b11 100644 --- a/src/main/scala/com/github/unchama/util/bukkit/WorldUtil.scala +++ b/src/main/scala/com/github/unchama/util/bukkit/WorldUtil.scala @@ -6,10 +6,12 @@ import org.bukkit.World.Environment object WorldUtil { def getAbsoluteWorldFolder(world: World): String = { val base = world.getWorldFolder.getAbsolutePath + world.getEnvironment match { case Environment.NORMAL => base case Environment.NETHER => s"$base/DIM-1" case Environment.THE_END => s"$base/DIM1" + case Environment.CUSTOM => s"$base/COSTOM" } } } diff --git a/src/main/scala/com/github/unchama/util/external/CoreProtectWrapper.scala b/src/main/scala/com/github/unchama/util/external/CoreProtectWrapper.scala index cfae476980..eda19fff99 100644 --- a/src/main/scala/com/github/unchama/util/external/CoreProtectWrapper.scala +++ b/src/main/scala/com/github/unchama/util/external/CoreProtectWrapper.scala @@ -7,14 +7,11 @@ import org.bukkit.entity.Player class CoreProtectWrapper(val backbone: CoreProtectAPI) { def queueBlockRemoval(who: Player, where: Block): Boolean = { - // where.getDataが非推奨になっていますが、現在これ以外の方法でByteデータを取得する方法がないようです。 - backbone.logRemoval(who.getName, where.getLocation, where.getType, where.getData) + backbone.logRemoval(who.getName, where.getLocation, where.getType, where.getBlockData) } - /* - // For >= 1.13 - def queueBlockRemoval(who: Player, where: Location, data: BlockData): Boolean = { - return backbone.logRemoval(who.getName, where, where.getBlock.getType, data) + def isNotEditedBlock(where: Block): Boolean = { + backbone.blockLookup(where, Int.MaxValue).isEmpty } - */ + } diff --git a/src/main/scala/com/github/unchama/util/external/WorldEditWrapper.scala b/src/main/scala/com/github/unchama/util/external/WorldEditWrapper.scala index 15812be9e3..8b40674e36 100644 --- a/src/main/scala/com/github/unchama/util/external/WorldEditWrapper.scala +++ b/src/main/scala/com/github/unchama/util/external/WorldEditWrapper.scala @@ -1,7 +1,7 @@ package com.github.unchama.util.external import com.sk89q.worldedit.bukkit.WorldEditPlugin -import com.sk89q.worldedit.bukkit.selections.Selection +import com.sk89q.worldedit.math.BlockVector3 import org.bukkit.entity.Player object WorldEditWrapper { @@ -14,6 +14,7 @@ object WorldEditWrapper { /** * @return `player`が選択している範囲 */ - def getSelection(player: Player): Option[Selection] = Option(plugin.getSelection(player)) + def getSelection(player: Player): BlockVector3 = + plugin.getSession(player).getPlacementPosition(plugin.wrapPlayer(player)) } diff --git a/src/main/scala/com/github/unchama/util/external/WorldGuardWrapper.scala b/src/main/scala/com/github/unchama/util/external/WorldGuardWrapper.scala index e4e407a0b7..3ffee61781 100644 --- a/src/main/scala/com/github/unchama/util/external/WorldGuardWrapper.scala +++ b/src/main/scala/com/github/unchama/util/external/WorldGuardWrapper.scala @@ -1,12 +1,11 @@ package com.github.unchama.util.external -import com.sk89q.worldedit.BlockVector -import com.sk89q.worldguard.LocalPlayer -import com.sk89q.worldguard.bukkit.commands.AsyncCommandHelper -import com.sk89q.worldguard.bukkit.commands.task.RegionAdder +import com.sk89q.worldedit.bukkit.BukkitAdapter +import com.sk89q.worldguard.bukkit.WorldGuardPlugin +import com.sk89q.worldguard.protection.flags.Flags import com.sk89q.worldguard.protection.managers.RegionManager -import com.sk89q.worldguard.protection.regions.{ProtectedCuboidRegion, ProtectedRegion} -import com.sk89q.worldguard.protection.util.DomainInputResolver +import com.sk89q.worldguard.protection.regions.ProtectedRegion +import com.sk89q.worldguard.{LocalPlayer, WorldGuard} import org.bukkit.entity.Player import org.bukkit.{Location, World} @@ -19,141 +18,89 @@ import scala.jdk.CollectionConverters._ */ object WorldGuardWrapper { - /** - * WorldGuardのインスタンス - */ - private val plugin = ExternalPlugins.getWorldGuard + private val worldGuard = WorldGuard.getInstance() /** * [[LocalPlayer]]を返す */ - private def wrapPlayer(player: Player): LocalPlayer = plugin.wrapPlayer(player) - - /** - * [[RegionManager]]を返す - */ - def getRegionManager(world: World): Option[RegionManager] = Option( - // The expression is nullable: WorldConfiguration#useRegions is false => null - plugin.getRegionManager(world) - ) - - /** - * [[Player]]が[[World]]の中で持っている保護の数を返す - * - * @return [[Player]]が[[World]]の中で持っている保護の数。[[getRegionManager]]が[[None]]であれば0。 - */ - def getRegionCountOfPlayer(player: Player, world: World): Int = - getRegionManager(world).map(_.getRegionCountOfPlayer(wrapPlayer(player))).getOrElse(0) - - /** - * [[World]]における[[Player]] の最大保護可能数を取得します. - * @return [[Player]]の[[World]] における最大保護可能数 - */ - def getMaxRegionCount(player: Player, world: World): Int = - // TODO: migrate this to OptionalInt - plugin.getGlobalStateManager.get(world).getMaxRegionCount(player) - - /** - * 現在[[Player]]が[[World]]でオーナーになっている保護の数を返す。 - * @param who 誰か - * @param where どのワールドか - * @return オーナーになっている保護の数。どこのオーナーでもない場合は0 - */ - def getNumberOfRegions(who: Player, where: World): Int = - // TODO: migrate this to OptionalInt - plugin.getRegionContainer.get(where).getRegionCountOfPlayer(wrapPlayer(who)) - - /** - * 現在[[Player]]が[[Location]]の座標でOwnerになっている保護があるかどうかを返す。 - * @param player 調べる対象であるPlayer - * @param location どの座標か - * @return Ownerである保護が1つだけあればtrue、ないか保護が2個以上重なっていて判定できなければfalse - */ - def isRegionOwner(player: Player, location: Location): Boolean = - getOneRegion(location).exists(_.isOwner(wrapPlayer(player))) - - /** - * [[Player]]が[[Location]]の座標でMemberになっている保護があるかどうかを返す。 - * NOTE: Ownerでもある場合も含まれる。 - * @param player 調べる対象であるPlayer - * @param location どの座標か - * @return Memberである保護が1つだけあればtrue、ないか保護が2個以上重なっていて判定できなければfalse - */ - def isRegionMember(player: Player, location: Location): Boolean = - getOneRegion(location).exists(_.isMember(wrapPlayer(player))) + private def wrapPlayer(player: Player): LocalPlayer = + WorldGuardPlugin.inst().wrapPlayer(player) + + def getRegionManager(world: World): RegionManager = + worldGuard.getPlatform.getRegionContainer.get(BukkitAdapter.adapt(world)) + + def getRegion(loc: Location): List[ProtectedRegion] = { + val container = + worldGuard.getPlatform.getRegionContainer.get(BukkitAdapter.adapt(loc.getWorld)) + container + .getApplicableRegions(BukkitAdapter.adapt(loc).toVector.toBlockPoint) + .getRegions + .asScala + .toList + } - /** - * [[Location]]の座標にある保護を1つだけ取得する - * @param location どの座標か - * @return [[ProtectedRegion]]。保護が1個もないか、2個以上ある場合は[[None]] - */ - def getOneRegion(location: Location): Option[ProtectedRegion] = { - val regions = getRegions(location) + def getRegions(world: World): List[ProtectedRegion] = { + worldGuard + .getPlatform + .getRegionContainer + .get(BukkitAdapter.adapt(world)) + .getRegions + .values() + .asScala + .toList + } - Option.when(regions.size == 1)(regions.head) + def canBuild(p: Player, loc: Location): Boolean = { + worldGuard + .getPlatform + .getRegionContainer + .createQuery() + .testState(BukkitAdapter.adapt(loc), wrapPlayer(p), Flags.BUILD) } - /** - * [[Location]]の座標にある保護をすべて取得する - * @param location どの座標か - * @return [[ProtectedRegion]]の[[Set]] - */ - def getRegions(location: Location): Set[ProtectedRegion] = - getRegionManager(location.getWorld) - .map(_.getApplicableRegions(location).getRegions.asScala.toSet) - .getOrElse(Set.empty) + def findByRegionName(name: String): Option[RegionManager] = + worldGuard + .getPlatform + .getRegionContainer + .getLoaded + .asScala + .find(_.getRegions.asScala.exists(_._1 == name)) + + def removeByProtectedRegionRegion(world: World, region: ProtectedRegion): Unit = { + worldGuard + .getPlatform + .getRegionContainer + .get(BukkitAdapter.adapt(world)) + .removeRegion(region.getId) + } - /** - * `minimumPoint`と`maximumPoint`の範囲内にある保護の数を取得する - * @param world 調べたいワールド - * @param regionName 保護名 - * @param minimumPoint 範囲の対角の1つ - * @param maximumPoint 範囲の対角の1つ - * @return 指定した範囲の保護の数を返す作用 - */ - def getApplicableRegionCount( - world: World, - regionName: String, - minimumPoint: BlockVector, - maximumPoint: BlockVector - ): Int = { - val region = new ProtectedCuboidRegion(regionName, minimumPoint, maximumPoint) - getRegionManager(world).map(_.getApplicableRegions(region).size).getOrElse(0) + def getMaxRegion(player: Player, world: World): Int = { + worldGuard + .getPlatform + .getGlobalStateManager + .get(BukkitAdapter.adapt(world)) + .getMaxRegionCount(wrapPlayer(player)) } - /** - * @param regionName 保護名 - * @param regionOwner 保護のオーナー - * @param world 保護をしたいワールド - * @param minimumPoint 保護範囲の対角の1つ - * @param maximumPoint 保護範囲の対角の1つ - * @return 保護の作成を試みることができればtrue、できなければfalse - * ただし、trueでも確実に保護が作成できるとは限らない - */ - def tryCreateRegion( - regionName: String, - regionOwner: Player, - world: World, - minimumPoint: BlockVector, - maximumPoint: BlockVector - ): Boolean = { - val region = new ProtectedCuboidRegion(regionName, minimumPoint, maximumPoint) - - getRegionManager(world) match { - case Some(manager) => - val task = new RegionAdder(plugin, manager, region) - task.setLocatorPolicy(DomainInputResolver.UserLocatorPolicy.UUID_ONLY) - task.setOwnersInput(Array(regionOwner.getName)) - val future = plugin.getExecutorService.submit(task) - - AsyncCommandHelper - .wrap(future, plugin, regionOwner) - .formatUsing(regionName) - .registerWithSupervisor("保護申請中") - .thenRespondWith("保護申請完了。保護名: '%s'", "保護作成失敗") - true - case None => false - } + def getNumberOfRegions(player: Player, world: World): Int = + worldGuard + .getPlatform + .getRegionContainer + .get(BukkitAdapter.adapt(world)) + .getRegionCountOfPlayer(wrapPlayer(player)) + + def getWorldMaxRegion(world: World): Int = { + worldGuard + .getPlatform + .getGlobalStateManager + .get(BukkitAdapter.adapt(world)) + .maxRegionCountPerPlayer } + def isRegionMember(player: Player, location: Location): Boolean = + getRegion(location).exists(_.isMember(wrapPlayer(player))) + + def canProtectionWorld(world: World): Boolean = + worldGuard.getPlatform.getGlobalStateManager.get(BukkitAdapter.adapt(world)).useRegions + } diff --git a/src/main/scala/com/github/unchama/util/nms/v1_12_2/world/WorldChunkSaving.scala b/src/main/scala/com/github/unchama/util/nms/v1_18_2/world/WorldChunkSaving.scala similarity index 92% rename from src/main/scala/com/github/unchama/util/nms/v1_12_2/world/WorldChunkSaving.scala rename to src/main/scala/com/github/unchama/util/nms/v1_18_2/world/WorldChunkSaving.scala index 4b048b1366..351400bac3 100644 --- a/src/main/scala/com/github/unchama/util/nms/v1_12_2/world/WorldChunkSaving.scala +++ b/src/main/scala/com/github/unchama/util/nms/v1_18_2/world/WorldChunkSaving.scala @@ -1,4 +1,4 @@ -package com.github.unchama.util.nms.v1_12_2.world +package com.github.unchama.util.nms.v1_18_2.world import cats.effect.{Concurrent, Sync} @@ -7,12 +7,12 @@ object WorldChunkSaving { import scala.jdk.CollectionConverters._ private object Reflection { - private val nmsPackage_1_12_R1 = "net.minecraft.server.v1_12_R1" - private val craftBukkitPackage_1_12_R1 = "org.bukkit.craftbukkit.v1_12_R1" + private val nmsPackage_1_18_R1 = "net.minecraft.server.v1_18_R1" + private val craftBukkitPackage_1_18_R1 = "org.bukkit.craftbukkit.v1_18_R1" object FileIOThread { private[Reflection] lazy val clazz: Class[_] = - Class.forName(s"$nmsPackage_1_12_R1.FileIOThread") + Class.forName(s"$nmsPackage_1_18_R1.FileIOThread") // public static FileIOThread method() lazy val getInstance: () => AnyRef = { @@ -32,7 +32,7 @@ object WorldChunkSaving { object Entity { private[Reflection] lazy val clazz: Class[_] = - Class.forName(s"$nmsPackage_1_12_R1.Entity") + Class.forName(s"$nmsPackage_1_18_R1.Entity") // public int field lazy val chunkX: AnyRef => Int = { @@ -56,7 +56,7 @@ object WorldChunkSaving { } object Chunk { - private[Reflection] lazy val clazz: Class[_] = Class.forName(s"$nmsPackage_1_12_R1.Chunk") + private[Reflection] lazy val clazz: Class[_] = Class.forName(s"$nmsPackage_1_18_R1.Chunk") // public void method(Entity) lazy val untrackEntity: AnyRef => AnyRef => Unit = { @@ -66,7 +66,7 @@ object WorldChunkSaving { } object World { - private[Reflection] lazy val clazz: Class[_] = Class.forName(s"$nmsPackage_1_12_R1.World") + private[Reflection] lazy val clazz: Class[_] = Class.forName(s"$nmsPackage_1_18_R1.World") // public final List field lazy val entityList: AnyRef => java.util.List[_ <: AnyRef] = { @@ -121,7 +121,7 @@ object WorldChunkSaving { object CraftWorld { private[Reflection] lazy val clazz: Class[_] = - Class.forName(s"$craftBukkitPackage_1_12_R1.CraftWorld") + Class.forName(s"$craftBukkitPackage_1_18_R1.CraftWorld") // public final nms.WorldServer (<: nms.World) // originally diff --git a/src/scalafix/scala/fix/MatchForMaterialToErrorForPerformance.scala b/src/scalafix/scala/fix/MatchForMaterialToErrorForPerformance.scala new file mode 100644 index 0000000000..a1d058274a --- /dev/null +++ b/src/scalafix/scala/fix/MatchForMaterialToErrorForPerformance.scala @@ -0,0 +1,31 @@ +package fix + +import scalafix.v1._ + +import scala.meta._ + +/** + * Lints on string interpolation where its variable part contains `case class` without `toString`. + */ +// noinspection ScalaUnusedSymbol; referred from scalafix implicitly +// NOTE: see AST on https://xuwei-k.github.io/scalameta-ast/ or https://astexplorer.net +class MatchForMaterialToErrorForPerformance extends SemanticRule("MatchForMaterialToErrorForPerformance") { + override def fix(implicit doc: SemanticDocument): Patch = { + doc.tree.collect { + case t @ Term.Match.After_4_4_5(term, _, _) => + term.symbol.info match { + case Some(info) if info.signature.toString == "Material" => + info.signature match { + case ValueSignature(TypeRef(_, symbol, _)) if SymbolMatcher.normalized("org/bukkit/Material").matches(symbol) => + val message = + s""" + |Don't use org.bukkit.Material in scrutinee of match expressions! + |See https://github.com/GiganticMinecraft/SeichiAssist/issues/2226 for more detail.""".stripMargin + Patch.lint(Diagnostic("error", message, t.pos)) + case _ => Patch.empty + } + case _ => Patch.empty + } + }.asPatch + } +} diff --git a/src/test/scala/com/github/unchama/generic/effect/ResourceScopeSpec.scala b/src/test/scala/com/github/unchama/generic/effect/ResourceScopeSpec.scala index a06b51d455..041c51b15b 100644 --- a/src/test/scala/com/github/unchama/generic/effect/ResourceScopeSpec.scala +++ b/src/test/scala/com/github/unchama/generic/effect/ResourceScopeSpec.scala @@ -138,7 +138,7 @@ class ResourceScopeSpec extends AnyWordSpec with Matchers with MockFactory { useTracked(firstResourceScope, NumberedObject(0), finalizer) { o => // noinspection ZeroIndexToHead runImpureFunction(o) >> - blockerList(0).await >> + blockerList(0).await() >> IO.never }.start _ <- blockerList(1).await() @@ -253,7 +253,7 @@ class ResourceScopeSpec extends AnyWordSpec with Matchers with MockFactory { useTrackedForSome(firstResourceScope, NumberedObject(0), finalizer) { o => // noinspection ZeroIndexToHead runImpureFunction(o) >> - blockerList(0).await >> + blockerList(0).await() >> IO.never }.start _ <- blockerList(1).await() diff --git a/src/test/scala/com/github/unchama/seichiassist/ManagedWorldSpec.scala b/src/test/scala/com/github/unchama/seichiassist/ManagedWorldSpec.scala index 74e5550757..41c080ddf1 100644 --- a/src/test/scala/com/github/unchama/seichiassist/ManagedWorldSpec.scala +++ b/src/test/scala/com/github/unchama/seichiassist/ManagedWorldSpec.scala @@ -6,6 +6,8 @@ import org.scalamock.scalatest.MockFactory import org.scalatest.Inspectors.forAll import org.scalatest.wordspec.AnyWordSpec +import scala.annotation.nowarn + /** * Created by karayuu on 2020/10/07 */ @@ -40,6 +42,7 @@ class ManagedWorldSpec extends AnyWordSpec with MockFactory { "return the appropriate truth-value" in { forAll(blockLineUpSkillEnableMap) { case (worldName, value) => + @nowarn val world = mock[World] (world.getName _).expects().returning(worldName) assert(world.isBlockLineUpSkillEnabled == value) @@ -51,6 +54,7 @@ class ManagedWorldSpec extends AnyWordSpec with MockFactory { "return the appropriate truth-value" in { forAll(inTrackedWorldMap) { case (worldName, value) => + @nowarn val world = mock[World] (world.getName _).expects().returning(worldName) assert(world.shouldTrackBuildBlock == value)