# 😇 点击这里开始你的旅程

<figure><img src="/files/L3fm6gQt0VcMKw0Hrjde" alt=""><figcaption></figcaption></figure>


# 前往新文档

该文档已搬迁，请前往下面的网站获取文档。

{% embed url="<https://ce.gtemc.cn/zh-Hans/>" %}


# 🍅 CustomCrops


# ❓️ 常见问题

## 问题 1: 如何使用原版耕地作为种植盆

现在你得在插件的浇水系统（①）和原版的湿度系统（②）之间做个选择。

① 如果你想使用插件的浇水和施肥系统，必须在config.yml中禁用原版的湿度设置，以避免冲突。

```yaml
  # 原版耕地设置
  vanilla-farmland:
    # 禁用原版耕地的湿度机制
    # 这个选项是因为一些用户更喜欢使用原版耕地，但水系统与原版耕地冲突
    disable-moisture-mechanic: true
```

然后编辑 /contents/pots 文件夹中的 default.yml。

```yaml
default:
  # 最大水储存容量
  max-water-storage: 7
  # 最基本的设置
  base:
    # 种植盆模型
    dry: minecraft:farmland[moisture=0]
    wet: minecraft:farmland[moisture=7]
  # 种植盆是否吸收雨水
  absorb-rainwater: true
  # 附近的水是否让种植盆变湿
  absorb-nearby-water: true
```

② 如果你更喜欢原版耕地的机制，可以直接在 CustomCrops 中禁用所有浇水机制。你需要做的是编辑 /contents/pots 文件夹下的 default.yml。

```yaml
default:
  vanilla-farmland: true
```

然后，你需要对每种作物的生长条件进行修改，否则它们在原版耕地上不会生长，因为 `water-more-than` 检查的是插件提供的水，而 `moisture-more-than` 检查的是原版耕地方块数据的湿度。

```yaml
water_condition:
  type: water-more-than
  value: 0
----->
moisture_condition:
  type: moisture-more-than
  value: 0
```

## 问题 2: 我无法使用插件的任何功能

确保你的世界不在黑名单中 / 确保你的世界在白名单中

```yaml
# 世界设置
worlds:
  # 这是为使用独立文件夹存放世界的服务器设计的
  # 特别适用于领域系统
  absolute-world-folder-path: ''
  # 一个决定插件机制生效的世界列表
  # 模式：whitelist/blacklist
  mode: blacklist
  list:
    - blacklist_world
```

## 问题 3: 如何让洒水壶可损坏

以 ItemsAdder 为例，你需要将材料设置为可损坏的物品，比如 "WOODEN\_SWORD"。CustomCrops 会为你处理耐久度系统，所以你不需要做其他任何事情！

<figure><img src="/files/1o7S7xbcHTJGSXfh4a1R" alt=""><figcaption></figcaption></figure>

```yaml
items:
  watering_can_1:
    display_name: display-name-watering_can_1
    resource:
      generate: false
      material: WOODEN_SWORD
      model_path: item/wateringcans/watering_can_1
    item_flags:
    - HIDE_ATTRIBUTES
```

## 问题 4: 我想使用其他插件中的物品作为种子/掉落物

首先，在 config.yml 中添加插件的名称。您可以在页面上获取所有兼容的插件：

{% content-ref url="/pages/6c6LrjfyHDxsTMdfCxXt" %}
[🤝 兼容性](/customcrops/cha-jian-wiki/customcrops/jian-rong-xing)
{% endcontent-ref %}

```yaml
  item-detection-order:
    - MMOItems
```

然后你就可以在任何地方使用 MMOItems

```yaml
  # 作物种子
  seed: MMOItems:MATERIAL:TOMATO_SEEDS
```

```yaml
  # 掉落物
  quality_crop_action:
    type: quality-crops
    value:
      min: 1
      max: 4
      items:
        1: MMOItems:MATERIAL:TOMATO
        2: MMOItems:MATERIAL:TOMATO_SILVER_STAR
        3: MMOItems:MATERIAL:TOMATO_GOLDEN_STAR
```

## 问题 5: 如何将等级插件的等级应用到作物的掉落数量？/ 我如何从收获作物中获得等级插件的经验？/ 如何为种植作物设置等级要求？

首先检查该插件是否在 [支持的等级插件](/customcrops/cha-jian-wiki/customcrops/jian-rong-xing/zhi-chi-de-deng-ji-xi-tong) 中。

然后将该占位符注册到 CustomCrops 中

```yaml
  placeholder-register:
    '{skill-level}': '%levelplugin_farming%'
```

现在你可以在掉落数量中使用占位符和表达式了

```yaml
  # 掉落物
  quality_crop_action:
    type: quality-crops
    value:
      min: "1 + {skill-level} * 0.1"
      max: "4 + {skill-level} * 0.1"
      ...
```

要从收获中获得经验，你必须在破坏/交互事件部分添加一个动作

```yaml
  action_exp:
    type: plugin-exp
    value:
      plugin: AureliumSkills
      target: FARMING  # 目标由你使用的等级插件决定
      exp: 100
    chance: 1
```

要使用种植作物的等级要求，你可以参考以下示例

```yaml
  requirements:
    plant:
      requirement_0:
        type: plugin-level
        value:
          plugin: AureliumSkills
          target: FARMING  # 目标由你使用的等级插件决定
          level: 10
        not-met-actions:
          message_action:
            type: message
            value: "这些种子需要 10 级以上的农业技能等级"
      requirement_1:
        type: season
        value:
          - Spring
          - Autumn
        not-met-actions:
          message_action:
            type: message
            value: "现在不是种植番茄的好季节"
```

## 问题 6: "protect-original-lore" 如何工作？

你可以在 config.yml 中仔细查找此选项

```yaml
  # 是否保护物品的原始描述
  # 这使用计分板组件来识别插件的描述，
  # 这可能会与仍在使用 SpigotAPI#ItemMeta 的某些插件产生冲突。
  protect-original-lore: false
```

以 ItemsAdder 为例

```yaml
items:
  watering_can_1:
    display_name: display-name-watering_can_1
    resource:
      generate: false
      material: WOODEN_SWORD
      model_path: item/wateringcans/watering_can_1
    item_flags:
    - HIDE_ATTRIBUTES
    lore:
      - '1111111111'
      - '2222'
      - '333333'
```

![](/files/JVjhvoZnrWgx8enaSHUV)

```yaml
protect-original-lore: true
```

![](/files/CLqdSuTflRlGNQ57Bwmd)

```yaml
protect-original-lore: false
```

![](/files/P5jSJ9beyquXwFBdgUHO)

## 问题 7: 我无法种植更多作物

情况1：我能听到种植的声音，种子被消耗了

如果你正在使用 ItemsAdder，请打开 ItemsAdder 的 config.yml 并将该值设置得更高

```yaml
entities:
  max-furniture-vehicles-per-chunk: 30
```

如果你使用的是 ItemsAdder 并且使用的是 `BLOCK` 模式，请打开 ItemsAdder 的 config.yml 并参考下面设置

```yaml
# IA 3.6
disable-REAL_WIRE: false
# IA 4.0+
wire: true
```

情况2：什么也没发生

打开 CustomCrops 的 config.yml

<pre class="language-yaml"><code class="lang-yaml"># 限制一个区块中作物的最大数量
<strong>max-per-chunk: 150
</strong></code></pre>

## 问题 8: 如果玩家无法种植更多作物，如何通知玩家？

在 pot/crop/sprinkler 的配置中，有一个名为`reach_limitation`的事件类型，您可以在其中添加自定义操作。

```yaml
events:
  reach_limit:
    actionbar_action:
      type: actionbar
      value: '<red><bold>[X] 你不能种植更多作物'
```

## 问题 9: 如何禁用作物的骨粉？

例如，从作物配置中删除`custom-bone-meal`部分

```yaml
  # 骨粉使用的自定义设置
  custom-bone-meal: {}
```

## 问题 10: 如何在种植盆里种植原版作物？

首先，你需要在config.yml中添加方块类型来禁用某种作物的原版机制。这将防止原版作物被更新并掉落物品。

```yaml
# 指定应该被插件覆盖的方块类型
# 一些常见的作物: WHEAT/CARROTS/POTATOES/BEETROOTS/SWEET_BERRY_BUSH
override-vanilla-blocks:
  - WHEAT
```

然后在/contents/crops/文件夹下创建一个新文件，例如`wheat.yml`

```yaml
# 作物的唯一标识符
wheat:
  # 物品类型
  type: BLOCK
  # 指定作物可以种植在哪个种植盆里
  pot-whitelist:
    - default
  # 用于种植作物的种子
  seed: WHEAT_SEEDS
  # 种植和破坏等动作的事件设置
  events:
    plant:
      # 种植时播放挥手动画
      swing_hand_action:
        type: swing-hand
        value: true
      # 种植作物时播放声音
      sound_action:
        type: sound
        value:
          source: player
          key: minecraft:item.hoe.till
          volume: 1
          pitch: 1
    break:
      # 破坏作物时播放声音
      sound_action:
        type: sound
        value:
          source: player
          key: minecraft:block.crop.break
          volume: 1
          pitch: 1
  # 作物的最大生长阶段
  max-points: 7
  # 作物每个生长阶段的动作和设置
  points:
    0:
      model: minecraft:wheat[age=0]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    1:
      model: minecraft:wheat[age=1]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    2:
      model: minecraft:wheat[age=2]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    3:
      model: minecraft:wheat[age=3]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    4:
      model: minecraft:wheat[age=4]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    5:
      model: minecraft:wheat[age=5]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    6:
      model: minecraft:wheat[age=6]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 1
    7:
      model: minecraft:wheat[age=7]
      events:
        break:
          action_1:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT_SEEDS
              min: 1
              max: 2
          action_2:
            type: drop-item
            value:
              ignore-fertilizer: true
              item: WHEAT
              min: 1
              max: 1
  grow-conditions: {}
  death-conditions: {}
  custom-bone-meal:
    bone_meal_1:
      item: BONE_MEAL
      dispenser: true
      chance:
        2: 0.5
        1: 1
      actions:
        swing_action:
          type: swing-hand
          value: true
        particle_action:
          type: particle
          value:
            particle: VILLAGER_HAPPY
            x: 0.5
            y: 0.5
            z: 0.5
            count: 5
            offset-x: 0.3
            offset-y: 0.3
            offset-z: 0.3
        sound_action:
          type: sound
          value:
            source: player
            key: minecraft:item.bone_meal.use
            volume: 1
            pitch: 1
```

<figure><img src="/files/HV5wM9h1QqnfQIADhyVP" alt=""><figcaption></figcaption></figure>

## 问题 11: 如何使用原版物品作为掉落物/种子？

只需使用大写字母，例如“APPLE”

```yaml
seed: APPLE
```

## 问题 12: 如何使用其他原版方块作为种植盆？

要继续使用插件的水和肥料机制，请按如下方式配置：

```yaml
# 种植盆的唯一标识符
default:
  # 种植盆的最大储水容量
  max-water-storage: 5
  # 种植盆外观和行为的基本设置
  base:
    # 种植盆外观的模型
    dry: minecraft:xxx[xxx=xxx]  # 种植盆干燥时的模型ID
    wet: minecraft:xxx[xxx=xxx]  # 种植盆湿润时的模型ID
```

要禁用插件的机制，只需按如下方式配置即可：

```yaml
# 种植盆的唯一标识符
grass_pot:
  vanilla-blocks:
    - minecraft:grass_block[snowy=false]
```

## 问题 13: 如何让不同的种植盆有不同的刻模式 <a href="#q13-how-to-let-different-pots-have-different-tick-modes" id="q13-how-to-let-different-pots-have-different-tick-modes"></a>

首先在 config.yml 中将刻模式设置为 `ALL`

```yaml
pot:
  # RANDOM_TICK / SCHEDULED_TICK / ALL
  mode: ALL

crop:
  # RANDOM_TICK / SCHEDULED_TICK / ALL
  mode: ALL
```

然后在其自己的配置中配置特定种植盆的刻模式，可以在以下位置找到

{% content-ref url="/pages/oeUNtsz4aXomqwfXB8L0" %}
[🪴 种植盆](/customcrops/cha-jian-wiki/customcrops/ge-shi/zhong-zhi-pen)
{% endcontent-ref %}

{% content-ref url="/spaces/orsLN8iAxZurNZDMTgzR/pages/tGGU1ol9FwiXhcUPQwEZ" %}
[🌽 作物](/customcrops/cha-jian-wiki/customcrops/ge-shi/zuo-wu)
{% endcontent-ref %}


# 📄 格式


# ✏️ 文本

文本的格式

该插件采用 `MiniMessage` (<https://docs.advntr.dev/minimessage/format.html>) 格式来表示文本。该系统提供了一种丰富而灵活的方式来使用颜色、样式和其他功能来格式化文本。但是，如果您更喜欢或需要旧的颜色格式（使用“&”符号），它仍然受支持。

旧版颜色代码支&#x6301;**:**

它在 `config.yml` 中应如下所示：&#x20;

要启用对旧颜色格式的支持：

```yaml
other-settings:
  legacy-color-code-support: true
```


# 🌽 作物

/CustomCrops/contents/crops/\_\_CROP\_\_.yml

让我们以 `tomato` 为例来配置作物的设置

**你的作物的唯一标识符**：\
首先，给你的作物命名一个唯一标识符，例如 `tomato`。这使得以后引用和自定义变得容易。

**自定义作物类型**：\
将 `type` 设置为 `BLOCK` 或 `FURNITURE`。对于 "tomato"，它被设置为 `BLOCK`。此设置影响整个配置中出现的所有自定义物品类型。但你也可以通过一些额外的配置单独设置物品的类型。

```yaml
# 物品类型
# BLOCK / FURNITURE
type: BLOCK
```

**设置种植限制**：\
使用 `pot-whitelist` 指定允许种植的花盆。"tomato" 作物只能种植在默认花盆中。如果你修改了花盆的配置，请务必同时修改此配置。

```yaml
# 作物只能种植在白名单中的花盆上
pot-whitelist:
  - default
```

**控制作物刻模式**

```yaml
# 有时您可能配置了多个作物，并希望为各个种植盆设置不同的刻模式。
# 你可以在 config.yml 中将刻模式改为 ALL，然后在此处分别进行配置。
ignore-random-tick: false
ignore-scheduled-tick: true
```

**配置种子信息**：\
`seed` 字段标识用于种植作物的物品。这里，`tomato_seeds` 是番茄作物的种子。

```yaml
# 作物的种子
seed: tomato_seeds
```

**管理旋转（仅适用于 FURNITURE 模式）**：\
`random-rotation` 控制作物种植时是否随机旋转。这仅在 `type` 为 `FURNITURE` 时适用。

```yaml
# 仅在 FURNITURE 模式下有效
random-rotation: true
```

**设置基本要求**：\
在 `requirements` 下自定义此作物的条件。例如，"tomato" 只能在春季或秋季种植，如果不满足这些条件，将显示一个动作栏消息。

```yaml
# 破坏/种植/互动要求
requirements:
  interact: {}
  break: {}
  plant:
    requirement_1:
      type: season
      value:
        - Spring
        - Autumn
      not-met-actions:
        message_action:
          type: message
          value: '<red><bold>[X] 现在不是种植番茄的好季节'
```

**配置事件设置**：\
在 `events` 下自定义作物事件，如种植或破坏。例如，当种植 "tomato" 时，会播放一个声音（`minecraft:item.hoe.till`），并出现手部挥动动画。作物的可用事件：`reach_limit`/`plant`/`break`/`interact`/`death`

```yaml
events:
  break: {}
  interact: {}
  death: {}
  reach_limit:
    actionbar_action:
      type: actionbar
      value: '<red><bold>[X] 你不能种植更多的作物'
  plant:
    # 挥动主手
    swing_hand_action:
      type: swing-hand
      value: true
    # 种植时发送声音
    sound_action:
      type: sound
      value:
        source: player
        key: minecraft:item.hoe.till
        volume: 1
        pitch: 1
```

**自定义生长阶段和模型**：\
使用 `points` 部分来概述作物的生长阶段。对于每个阶段，指定一个模型（外观）和发生的动作，如种子掉落或全息图调整。

作物的可用事件：`grow`/`break`/`interact`

```yaml
# 这决定了作物的最大生长阶段
max-points: 6
```

```yaml
# 作物每个生长阶段的动作和设置
points:
  0:
    # 代表作物在此生长阶段的模型
    model: tomato_stage_1
    # 调整全息图位置以匹配作物模型的高度
    hologram-offset-correction: 0.2
    # 如果此阶段的类型与上面设置的全局类型不同，请设置类型
    type: BLOCK
    # 此阶段的破坏/互动要求
    requirements:
      break: 
        ...
      interact:
        ...
    # 作物在此阶段被破坏时触发的事件
    events:
      grow: {}
      interact: {}
      break:
        # 破坏时有30%的几率掉落番茄种子
        action_1:
          type: drop-item
          value:
            ignore-fertilizer: true
            item: tomato_seeds
            min: 1
            max: 1
          chance: 0.3
```

**自定义生长和死亡条件**：\
使用 `grow-conditions` 设置作物生长的条件，如季节或水位。同样，`death-conditions` 决定作物在何时死亡，如乌鸦攻击或不适合的季节。

```yaml
# 作物可以生长的条件
grow-conditions:
  default:
    point: 1
    conditions:
      season_condition:
        type: suitable_season
        value:
          - Spring
          - Autumn
      water_condition:
        type: water_more_than
        value: 0
```

```yaml
# 可能导致作物死亡的条件
death-conditions:
  no_water:
    # 由于缺水触发的死亡阶段的自定义模型
    model: crop_stage_death
    conditions:
      '&&':
        condition_1:
          type: water_less_than
          value: 1
        condition_2:
          type: random
          value: 0.7
  unsuitable_season:
    # 作物在不适合的季节死亡
    model: crop_stage_death
    conditions:
      condition_1:
        type: unsuitable_season
        value:
          - Winter
  crow_attack:
    # 由于乌鸦攻击导致的作物移除
    conditions:
      condition_1:
        type: crow_attack
        value:
          chance: 0.005
          fly-model: crow_fly
          stand-model: crow_stand
    # 乌鸦攻击后作物被移除的延迟
    delay: 150
```

**自定义自定义骨粉效果**：\
在 `custom-bone-meal` 下配置使用骨粉触发的特殊效果和动作，如粒子、声音或生长几率。

```yaml
# 使用骨粉的自定义设置
custom-bone-meal:
  bone_meal_1:
    item: BONE_MEAL
    # 允许通过发射器使用
    dispenser: true
    chance:
      2: 0.2
      1: 0.6
    actions:
      swing_action:
        type: swing-hand
        value: true
      particle_action:
        type: particle
        value:
          particle: VILLAGER_HAPPY
          x: 0.5
          y: 0.5
          z: 0.5
          count: 5
          offset-x: 0.3
          offset-y: 0.3
          offset-z: 0.3
      sound_action:
        type: sound
        value:
          source: player
          key: minecraft:item.bone_meal.use
          volume: 1
          pitch: 1
```


# 💦 洒水器

/CustomCrops/contents/sprinklers/\_\_SPRINKLER\_\_.yml

让我们以 `sprinkler_1` 为例来配置洒水器的设置

**你的洒水器的唯一标识符**：\
首先，给你的洒水器命名一个唯一标识符，例如 `sprinkler_1`。这使得以后引用和自定义变得容易。

**指定洒水器的类型**：\
`type` 参数定义洒水器为 `FURNITURE`，将其与基于方块的类型区分开来，并允许在放置时有更多的灵活性。

```yaml
# 洒水器的类型（BLOCK 或 FURNITURE）
type: FURNITURE
```

**选择喷洒模式并设置范围**：\
决定你的洒水器如何喷洒！`working-mode` 允许你设置喷洒模式：

* `1` 为方形模式
* `2` 为菱形模式（当前选择）
* `3` 为圆形模式 这为你的浇水策略增加了创意！

```yaml
# 喷洒模式：
# 1 = 方形, 2 = 菱形, 3 = 圆形
working-mode: 2
```

`range` 参数指定洒水器的覆盖范围。在此示例中，`1` 的范围覆盖一个紧凑的区域：

```yaml
# 洒水器的工作范围：
# □■□
# ■▼■
# □■□
range: 1
```

<figure><img src="/files/MUvNbh7EOSq0iK6QL8Uc" alt=""><figcaption><p>模式1</p></figcaption></figure>

<figure><img src="/files/aOFHFMEnhiigcBWTvnbD" alt=""><figcaption><p>模式2</p></figcaption></figure>

<figure><img src="/files/Z9Pd5ewFyMWAIo8DpnYo" alt=""><figcaption><p>模式3</p></figcaption></figure>

**设置储水容量**：\
`storage` 参数决定了你的洒水器可以容纳多少水——在这个例子中是 `4`。这限制了洒水器在需要补水之前可以运行的时间。

```yaml
# 最大储水容量
storage: 4
```

**决定无限或有限的水供应**：\
将 `infinite` 设置为 `false`，洒水器有一个有限的水供应。如果你想要一个无限的洒水器，将其改为 `true`！

```yaml
# 表示洒水器是否有无限的水供应
infinite: false
```

**控制每次操作的水消耗**： `water` 和 `sprinkling` 参数决定每次喷洒循环中添加到种植盆的水量和消耗的水量，这里都设置为 `1` 以实现平衡的浇水。

```yaml
# 每次喷洒操作添加到种植盆的水量
water: 1
# 每次喷洒操作消耗的水量
sprinkling: 1
```

**洒水器的视觉表示**：\
使用 `3D-item` 和 `3D-item-with-water` 定义洒水器在干燥和有水状态下的外观。这个视觉提示通过反映洒水器的状态增强了游戏体验。

```yaml
# 洒水器的3D模型标识符
3D-item: sprinkler_1 # 无水状态
3D-item-with-water: sprinkler_1 # 有水状态
```

**可选的2D模型**：\
`2D-item` 是一个可选参数，适用于那些喜欢更简单的视觉表示或在某些场景中使用2D视图的人。

```yaml
# 可选的2D物品模型标识符
2D-item: sprinkler_1_item
```

**种植盆的白名单**：\
通过将种植盆添加到 `pot-whitelist` 确保你的洒水器仅在指定的种植盆中工作。示例允许默认的种植盆类型。

```yaml
# 洒水器可以工作的种植种植盆的列表
pot-whitelist:
  - default
```

**定义补水方法**：\
在 `fill-method` 下，你可以创意地定义洒水器的补水方式。例如，使用 `WATER_BUCKET` 返回一个空的 `BUCKET`，并添加 `3` 单位的水，而使用 `POTION` 返回一个 `GLASS_BOTTLE` 并添加 `1` 单位的水。

```yaml
# 洒水器补水的方法
fill-method:
  # 自定义补水方法1配置
  method_1:
    # 用于补水的物品
    item: WATER_BUCKET
    # 补水后返回的物品（可选）
    return: BUCKET
    # 此方法添加的水量
    amount: 3
  # 自定义补水方法2配置
  method_2:
    item: POTION
    return: GLASS_BOTTLE
    amount: 1
```

**自定义水位显示**：\
`water-bar` 部分允许你使用符号创建独特的水位表示。调整这些字符以匹配你的游戏风格或偏好。

```yaml
# 水位显示条的配置
water-bar:
  left: '뀂'   # 水位条的左端
  full: '뀁뀃' # 表示水位满的段
  empty: '뀁뀄' # 表示水位空的段
  right: '뀁뀅' # 水位条的右端
```

**设置事件**：\
在 `events` 下，你可以配置洒水器如何响应不同的玩家操作。可用事件：`break`/`place`/`interact`/`work`/`add_water`/`full`/`reach_limit`

```yaml
# 各种互动和动作的事件设置
events:
  place:
    # 放置洒水器时执行的动作
    swing_hand_action:
      type: swing-hand
      value: true
    # 放置洒水器时触发的音效
    sound_action:
      type: sound
      value:
        source: player
        key: minecraft:block.bone_block.place
        volume: 1
        pitch: 1
  interact:
    # 互动时执行的条件动作
    force_work_action:
      type: conditional
      value:
        conditions:
          requirement_1:
            type: sneak
            value: true
        actions:
          action_1:
            type: force-tick
    # 互动时显示的全息图动作
    hologram_action:
      type: hologram
      value:
        text: '<font:customcrops:default>{water_bar}</font>'
        duration: 40
        x: 0.5
        y: -0.3
        z: 0.5
        visible-to-all: false
  work:
    # 洒水器工作时显示的视觉效果
    fake_item_action:
      type: fake-item
      value:
        item: water_effect
        duration: 100
        x: 0.5
        y: 0.4
        z: 0.5
        visible-to-all: true
  add_water:
    # 添加水时显示的粒子效果
    particle_action:
      type: particle
      value:
        particle: WATER_SPLASH
        x: 0.5
        y: 0.7
        z: 0.5
        count: 5
    # 添加水时播放的音效
    sound_action:
      type: sound
      value:
        key: "minecraft:item.bucket.empty"
        source: 'player'
        volume: 1
        pitch: 1
```

**设置要求**：\
在 `requirements` 下，你可以配置玩家在使用洒水器之前必须满足的条件。可用事件：`break`/`place`/`use`

```yaml
requirements:
  use: {}
  place: {}
  break:
    requirement_1:
      type: permission
      value: xxx.xxx
```


# 🚰 洒水壶

/CustomCrops/contents/watering-cans/\_\_WATERING-CAN\_\_.yml

让我们以 `watering_can_1` 为例来配置洒水壶的设置

**你的洒水壶的唯一标识符**：\
首先，给你的洒水壶命名一个唯一标识符，例如 `watering_can_1`。这使得以后引用和自定义变得容易。

**分配唯一标识符**：\
首先使用 ItemsAdder 或 Oraxen 为你的洒水壶设置一个唯一的 `item` 标识符。例如，`watering_can_1` 唯一标识了这个特定的洒水壶，使其在游戏中易于引用。

```yaml
# ItemsAdder/Oraxen 的唯一物品标识符
item: watering_can_1
```

**自定义洒水壶的外观**：\
你可以选择自定义洒水壶在不同水位时的外观。取消注释 `appearance` 部分并分配 `CustomModelData` 值，以便在视觉上区分空的、部分填充的或完全填充的洒水壶。这是为玩家提供洒水壶状态的视觉反馈的好方法。

```yaml
# 基于水容量的洒水壶外观的可选设置
# 如果希望为不同水位设置不同的外观，请取消注释并自定义 CustomModelData
#appearance:
#  0: 1000 # 空壶的 CustomModelData
#  1: 1001 # 部分填充壶的 CustomModelData
#  2: 1002 # 更多填充壶的 CustomModelData
#  3: 1003 # 完全填充壶的 CustomModelData
```

**设置水容量**：\
使用 `capacity` 参数定义你的洒水壶可以容纳的最大水量。这里设置为 `3`，意味着洒水壶一次最多可以存储三个单位的水。这个容量控制了洒水壶在需要补充之前可以使用的时间。

```yaml
# 洒水壶可以存储的最大水量
capacity: 3
```

**确定每次使用的水量**：\
`water` 参数指定每次使用洒水壶时分配的水量。将其设置为 `1` 意味着每次使用洒水壶将消耗一个单位的水，并向种植盆添加 `1` 单位的水。

```yaml
# 添加到种植盆的水量
water: 1
```

**定义有效的浇水范围**：\
通过设置 `effective-range` 参数来自定义使用时水的覆盖范围。`width` 和 `length` 定义了玩家周围的一个矩形区域，在这个区域内水将有效。在这种情况下，是玩家正前方的 1x1 区域。

```yaml
# 洒水壶使用时的有效范围
effective-range:
  width: 1  # 受影响区域的宽度
  length: 1 # 受影响区域的长度
```

**设置补水方法**：\
通过配置 `fill-method` 定义玩家如何补充洒水壶的水。在 `method_1` 中，玩家可以通过与 `WATER` 方块（如水源或井）互动来补充洒水壶。`amount` 指定每次互动添加 `1` 单位的水。这一特性允许你在游戏世界中创建互动水源。

```yaml
fill-method:
  # 自定义补水方法配置
  method_1:
    target: WATER  # 提供水的方块或物体（例如，minecraft:block_id）
    amount: 1      # 每次补水添加的水量
```

**指定兼容的种植种植盆**：\
使用 `pot-whitelist` 指定洒水壶可以使用的种植种植盆类型。通过列出 `default`，你确保洒水壶与基本种植盆类型兼容，但你可以添加更多种植盆类型以增加多样性。

```yaml
# 指定洒水壶可以使用的种植种植盆类型
pot-whitelist:
  - default  # 允许的默认种植盆类型
```

**允许与洒水器互动**：\
如果你希望你的洒水壶用于填充洒水器，请在 `sprinkler-whitelist` 下列出兼容的洒水器ID。在此配置中，洒水壶可以填充 `sprinkler_1`、`sprinkler_2` 和 `sprinkler_3`，扩展了其功能。

```yaml
# 允许洒水壶填充兼容的洒水器
sprinkler-whitelist:
  - sprinkler_1
  - sprinkler_2
  - sprinkler_3
```

**启用动态描述**：\
动态描述通过显示洒水壶状态的实时信息增加了一层沉浸感。通过启用 `dynamic-lore`，描述将根据水位变化。使用 `{water_bar}` 等占位符来直观地表示水位，使用 `{current}` 表示当前水量，使用 `{storage}` 表示最大容量。这确保了玩家始终能一眼看出洒水壶的状态。

```yaml
# 洒水壶描述的动态描述设置
dynamic-lore:
  enable: true  # 启用或禁用基于水位的动态描述
  # 将动态显示的描述文本
  # 可用占位符：
  # {water_bar}：水位的视觉表示
  # {current}：当前水量
  # {storage}：最大储水容量
  lore:
    - '<italic:false><white><font:customcrops:default>{water_bar}</font>'
    - '<italic:false><gray>右键点击水源以补充洒水壶的水。'
```

**自定义水位显示条**：\
`water-bar` 配置允许你使用自定义字符创建独特的水位指示器。此显示提供了一种快速且视觉上吸引人的方式来检查洒水壶中剩余的水量。

```yaml
# 水位显示条的配置
water-bar:
  left: '뀂'   # 水位条的左端
  full: '뀁뀃' # 表示水位满的段
  empty: '뀁뀄' # 表示水位空的段
  right: '뀁뀅' # 水位条的右端
```

**设置事件**：\
`events` 部分是游戏真正发挥作用的地方。在这里，你可以定义游戏如何响应与洒水壶的不同互动。可用事件：`full`/`add_water`/`no_water`/`consume_water`/`wrong_pot`/`wrong_sprinkler`

```yaml
# 处理与洒水壶相关的各种动作的事件设置
events:
  # 当洒水壶中没有水时触发的事件
  no_water:
    sound_action:
      type: sound
      value:
        key: "minecraft:item.bundle.insert"  # 播放的声音
        source: 'player'                     # 声音来源
        volume: 1
        pitch: 1
    actionbar_action:
      type: actionbar
      value: '<red><bold>[X] 水已用完'  # 在动作栏显示的消息
  # 当洒水壶中的水被消耗时触发的事件
  consume_water:
    sound_action:
      type: sound
      value:
        key: "minecraft:block.water.ambient"  # 水被消耗时的声音
        source: 'player'
        volume: 1
        pitch: 1
    actionbar_action:
      type: actionbar
      value: '<font:customcrops:default>{water_bar}</font>' # 显示更新后的水位条
  # 当洒水壶中添加水时触发的事件
  add_water:
    particle_action:
      type: particle
      value:
        particle: WATER_SPLASH  # 添加水时的粒子效果
        x: 0.5
        y: 1.3
        z: 0.5
        count: 5
    sound_action:
      type: sound
      value:
        key: "minecraft:item.bucket.empty"  # 补水时播放的声音
        source: 'player'
        volume: 1
        pitch: 1
    actionbar_action:
      type: actionbar
      value: '<font:customcrops:default>{water_bar}</font>' # 更新水位条显示
```

**设置要求**：\
在 `requirements` 下，你可以配置玩家在使用洒水壶之前必须满足的条件。

```yaml
requirements:
  requirement_1:
    type: permission
    value: xxx.xxx
```


# 🪴 种植盆

/CustomCrops/contents/pots/\_\_POT\_\_.yml

让我们以 `default` 为例来配置种植盆的设置

**你的种植盆的唯一标识符**: \
首先，给你的种植盆命名一个唯一标识符，例如 `default`。这使得以后引用和自定义变得容易。

**设置最大储水容量**: \
使用 `max-water-storage` 来定义你的种植盆可以储存多少水。例如，将其设置为 `5` 意味着种植盆最多可以容纳五个单位的水。这确保了你的植物在两次浇水之间有足够的水分。

```yaml
# 种植盆的最大储水容量
max-water-storage: 5
```

**自定义种植盆的基本外观**: \
`base` 部分允许你在不同条件下定义种植盆的视觉外观:

* `dry`: 种植盆干燥时使用的模型ID，显示需要浇水。
* `wet`: 种植盆湿润时使用的模型ID。 这些设置为玩家提供了视觉提示，使他们一眼就能看出种植盆是否需要浇水。

```yaml
# 种植盆外观和行为的基本设置
base:
  # 种植盆外观的模型
  dry: dry_pot  # 种植盆干燥时的模型ID
  wet: wet_pot  # 种植盆湿润时的模型ID
```

**控制种植盆与环境的互动**:

* `absorb-rainwater`: 如果你希望种植盆自动吸收雨水，保持湿润而无需手动浇水，请设置为 `true`。
* `absorb-nearby-water`: 设置为 `false` 以防止种植盆从附近的水源吸收水分。此设置确保你的种植盆只在预期时得到浇水。

```yaml
# 确定种植盆在下雨时是否吸收雨水
absorb-rainwater: true
# 确定附近水源的水是否能湿润种植盆
absorb-nearby-water: false
```

**控制种植盆刻模式**

```yaml
# 有时你可能配置了多个种植盆，
# 并且你希望这些种植盆有不同的刻模式。
# 你可以在config.yml中将刻模式改为ALL，
# 然后在这里单独配置。
ignore-random-tick: false
ignore-scheduled-tick: true
```

**管理肥料的应用**: \
`max-fertilizers` 参数控制一次可以施加到种植盆上的肥料单位数。将其设置为 `1` 限制为单次应用，帮助防止过度施肥可能对植物造成的伤害。目前建议保持为 `1`，因为全息图最多会同时显示一个肥料。

```yaml
# 可以施加到种植盆上的最大肥料数量
max-fertilizers: 1
```

**为施肥后的种植盆定义自定义外观**: \
在 `fertilized-pots` 下，你可以根据不同的肥料效果设置种植盆的独特模型。每种类型（例如 `quality`、`yield_increase`、`variation`、`soil_retain`、`speed_grow`）都可以有不同的 `dry` 和 `wet` 外观。这种自定义增加了深度，视觉上反映了施加到种植盆上的不同肥料的好处。

```yaml
# 不同肥料效果的种植盆自定义外观
fertilized-pots:
  quality:
    dry: dry_pot  # 'quality' 肥料效果下干燥种植盆的模型ID
    wet: wet_pot  # 'quality' 肥料效果下湿润种植盆的模型ID
  yield_increase:
    dry: dry_pot  # 'yield increase' 肥料效果下干燥种植盆的模型ID
    wet: wet_pot  # 'yield increase' 肥料效果下湿润种植盆的模型ID
  variation:
    dry: dry_pot  # 'variation' 肥料效果下干燥种植盆的模型ID
    wet: wet_pot  # 'variation' 肥料效果下湿润种植盆的模型ID
  soil_retain:
    dry: dry_pot  # 'soil retain' 肥料效果下干燥种植盆的模型ID
    wet: wet_pot  # 'soil retain' 肥料效果下湿润种植盆的模型ID
  speed_grow:
    dry: dry_pot  # 'speed grow' 肥料效果下干燥种植盆的模型ID
    wet: wet_pot  # 'speed grow' 肥料效果下湿润种植盆的模型ID
```

**配置水的补充方法**: \
`fill-method` 部分允许你定义各种补充种植盆水的方法:

* **方法 1**: 使用 `WATER_BUCKET` 添加 `3` 单位的水。补充后，玩家会收到一个空的 `BUCKET`。
* **方法 2**: 使用 `POTION` 添加 `1` 单位的水，并返回一个 `GLASS_BOTTLE`。 两种方法都包括播放声音（`minecraft:item.bucket.fill` 或 `minecraft:item.bottle.fill`）和手部挥动动画，以在补充过程中提供反馈。

```yaml
# 可用于给洒水壶补水的方法
fill-method:
  # 可自定义的补水方法 1
  method_1:
    # 补水所需的物品
    item: WATER_BUCKET
    # 补水后返回的物品（可选）
    return: BUCKET
    # 使用此方法添加的水量
    amount: 3
    actions:
      # 补水时播放的音效
      sound_action:
        type: sound
        value:
          source: player
          key: minecraft:item.bucket.fill
          volume: 1
          pitch: 1
      # 补水时的手部挥动动作
      swing_hand_action:
        type: swing-hand
        value: true
  # 可自定义的补水方法 2
  method_2:
    item: POTION
    return: GLASS_BOTTLE
    amount: 1
    actions:
      sound_action:
        type: sound
        value:
          source: player
          key: minecraft:item.bottle.fill
          volume: 1
          pitch: 1
      swing_hand_action:
        type: swing-hand
        value: true
```

**自定义水位显示条**: \
`water-bar` 配置允许你使用自定义字符创建独特的水位指示器。此显示提供了一种快速且视觉上吸引人的方式来检查洒水壶中剩余的水量。

```yaml
# 水位显示条的配置
water-bar:
  left: '뀂'   # 水位条的左端
  full: '뀁뀃' # 表示水位满的段
  empty: '뀁뀄' # 表示水位空的段
  right: '뀁뀅' # 水位条的右端
```

**设置事件**: \
`events` 部分是游戏真正发挥作用的地方。在这里，你可以定义游戏如何响应与种植盆的不同互动。可用事件: `place`/`break`/`interact`/`tick`/`reach_limitation`/`add_water`/`full`/`max_fertilizers`

```yaml
# 处理互动和效果的事件设置
events:
  add_water:
    particle_action:
      type: particle
      value:
        particle: WATER_SPLASH  # 添加水时的粒子效果
        x: 0.5
        y: 1.3
        z: 0.5
        count: 5
        offset-x: 0.3
        offset-z: 0.3
  interact:
    # 持有指定物品时显示全息图的动作
    conditional_action:
      type: conditional
      value:
        conditions:
          requirement_1:
            type: item-in-hand
            value:
              amount: 1
              item: soil_surveyor
        actions:
          # 如果存在肥料，则显示肥料状态的全息图
          conditional_fertilizer_action:
            type: conditional
            value:
              conditions:
                requirement_1:
                  type: fertilizer
                  value:
                    has: true
              actions:
                fertilizer_hologram:
                  type: hologram
                  value:
                    duration: 20  # 全息图可见的持续时间
                    text: '<font:customcrops:default>{icon}</font> {left_times}/{max_times}'
                    apply-correction: true
                    x: 0.5
                    y: 0.83
                    z: 0.5
                    visible-to-all: false
          # 显示种植盆当前水位的全息图
          water_hologram:
            type: hologram
            value:
              duration: 20  # 全息图可见的持续时间
              text: '<font:customcrops:default>{water_bar}</font>'
              apply-correction: true
              x: 0.5
              y: 0.6
              z: 0.5
              visible-to-all: false
```

**设置要求**: \
在 `requirements` 下，你可以配置玩家在使用种植盆之前必须满足的条件。可用事件: `break`/`place`/`use`

```yaml
requirements:
  use: {}
  place: {}
  break:
    requirement_1:
      type: permission
      value: xxx.xxx
```


# 💩 肥料

/CustomCrops/contents/fertilizers/\_\_FERTILIZER\_\_.yml

以`quality_1`为例配置肥料设置

**肥料的唯一标识符**： 首先为每种肥料类型分配一个唯一的标识符。在此示例中，肥料名为`quality_1` 。该标识符对于区分游戏中不同的肥料类型至关重要。

**定义肥料类型和图标**：

* **`type`** ：设置为`QUALITY` ，表示该肥料可以提高所施用作物的质量。
* **`icon`** ：代表当玩家查看或使用此肥料时，将出现在游戏界面中的视觉图标。图标“뀆”是一个独特的符号，直观地代表了这种特定的肥料。

可用肥料类型及其效果：

```yaml
QUALITY: 更改星级作物掉落的权重
SOIL_RETAIN: 减缓水分消耗速度
SPEED_GROW: 加速作物生长
VARIATION: 作物有更高的变异概率
YIELD_INCREASE: 增加作物产量
```

```yaml
type: QUALITY  # 肥料的类型
```

**设置肥料的有效性**：

* **`chance`** ：这是影响肥料有效性或成功率的概率因子（此处设置为`1` ）。调整该值可以使肥料或多或少地更有可能产生其预期效果。
* **`times`** ：指定肥料保持有效的持续时间或游戏中的刻数。值为`28` 时，肥料将持续 28 个刻周期，对作物生长产生持续影响。

```yaml
chance: 1  # 影响肥料效果的概率因子
```

**分配唯一的物品 ID** ：

* **`item`** ：唯一的物品`quality_1`将此配置链接到游戏内的物品，确保当玩家使用此物品时，游戏将其识别为`quality_1`肥料。

```yang
item: quality_1  # 此肥料的唯一物品 ID
```

**指定应用时间和盆栽兼容性**：

* **`before-plant`** ：设置为 `true` 时，此参数确保肥料必须在种植任何作物之前施用。它强制进行战略规划，要求玩家提前准备土壤。
* **`pot-whitelist`** ：列出可以施用此肥料的所有种植盆类型。在此示例中，仅允许使用`default`种植盆，但您可以添加更多种植盆类型以扩展兼容性。

```yaml
before-plant: true  # 表示此肥料必须在种植作物之前施用
pot-whitelist:
  - default  # 可以使用此肥料的允许种植盆列表
```

**设置事件**： \
`events`部分是游戏真正发挥作用的地方。在这里，你可以定义游戏如何响应与肥料的不同互动。可用事件： `use` / `before_plant` / `wrong_pot`

```yaml
events:
  use:  # 施用肥料时触发的动作
    particle_action:
      type: particle
      value:
        particle: SCRAPE
        x: 0.5
        y: 1.3
        z: 0.5
        count: 5
        offset-x: 0.3
        offset-z: 0.3
    sound_action:
      type: sound
      value:
        source: player
        key: minecraft:item.hoe.till
        volume: 1
        pitch: 1
  wrong_pot:  # 如果肥料用于错误的种植盆类型时触发的动作
    sound_action:
      type: sound
      value:
        key: "minecraft:item.bundle.insert"
        source: 'player'
        volume: 1
        pitch: 1
    actionbar_action:
      type: actionbar
      value: '<red><bold>[X] 此肥料只能用于种植盆中。'  # 在动作栏上显示的消息
  before_plant:  # 如果肥料在种植后使用时触发的动作
    sound_action:
      type: sound
      value:
        key: "minecraft:item.bundle.insert"
        source: 'player'
        volume: 1
        pitch: 1
    actionbar_action:
      type: actionbar
      value: '<red><bold>[X] 你只能在种植作物之前使用此肥料。'
```

**设置要求**：\
&#x20;在`requirements`下，您可以配置玩家使用肥料之前必须满足的条件。

```yaml
requirements:
  requirement_1:
    type: permission
    value: xxx.xxx
```


# ⚙️ config.yml

```yaml
# 不要更改此值
config-version: '${config_version}'
# 启用或禁用调试模式
debug: false
# 启用或禁用使用 BStats 的指标收集
metrics: true
# 启用自动更新检查
update-checker: true
# 强制使用特定语言环境（例如，zh_cn）
force-locale: ''
# 世界设置
worlds:
  # 一些服务器使用单独的目录来存储玩家的世界，这些目录可能不在服务器的根目录中。
  # 此选项允许你指定这些世界文件夹的自定义路径。仅适用于 Bukkit 世界。
  absolute-world-folder-path: ''
  # 指定插件机制应适用于哪些世界
  # 选项：whitelist/blacklist/regex
  mode: blacklist
  list:
    - blacklist_world # 一个不存在的世界
  settings:
    # 应用于所有世界的默认设置
    _DEFAULT_:
      # 是否启用插件的预配置系统
      # 禁用此选项将停止所有机制的计时，除非通过 API 完全管理。
      # 如果你不熟悉使用 CustomCropsAPI，请保持此设置为 true，因为它满足 99% 用户的需求。
      enable: true
      # 季节设置
      season:
        enable: true
        # 自动循环季节
        auto-alternation: true
        # 每个季节的持续时间（游戏天数）
        duration: 28
      # 这与原版的 RandomTickSpeed 不同。
      # 这里的“随机刻”指的是每秒在 16x16x16 区域内随机选择 n 个方块进行刻动，不同于 Minecraft 的每刻动方式。
      # 因此，CustomCrops 的随机刻对服务器的影响最小，并且在多个线程上运行。
      random-tick-speed: 20
      # 使用定时刻动模式时的最小刻动间隔（秒）
      # 180 秒的值意味着作物至少每 180 秒保证刻动一次
      # 对于作物，在相同条件下生长率几乎是均匀的
      # 洒水器和种植盆在此间隔内周期性地运行。
      min-tick-unit: 180
      # 离线时刻动设置
      # 允许作物即使在世界卸载或服务器关闭时也能生长
      # 这可能会导致与时间相关的条件（如季节）出现问题
      offline-tick:
        enable: false
        # 记录的最大离线时间（秒）
        # 避免设置过高，因为这可能导致长时间卸载的区块加载时间过长
        max-offline-seconds: 1200
        # 加载区块的最长时间
        # 有时，长时间卸载的大量数据区块可能需要一段时间来加载，
        # 可能会导致意外问题
        # 此设置允许插件在加载时间超过设定阈值时强制中断刻动过程
        max-loading-time: 100 # 毫秒
      # 作物设置
      crop:
        # [RANDOM_TICK]
        # 随机刻动模式模仿原版行为，作物随机生长
        # 这种随机性可能导致在相同条件下生长的作物之间存在显著的阶段差异
        # [SCHEDULED_TICK]
        # 定时刻动模式提供更可预测的生长管理，
        # 确保作物几乎以相同的速度生长
        mode: RANDOM_TICK
        # 刻动间隔决定在执行逻辑之前刻动方块的次数
        tick-interval: 1
        # 限制每个区块的作物数量（-1 表示无限制）
        max-per-chunk: -1
      # 种植盆设置
      pot:
        # RANDOM_TICK 或 SCHEDULED_TICK
        mode: SCHEDULED_TICK
        tick-interval: 3
        max-per-chunk: -1
      # 洒水器设置
      sprinkler:
        # RANDOM_TICK 或 SCHEDULED_TICK
        mode: SCHEDULED_TICK
        tick-interval: 2
        max-per-chunk: -1
    # 在此为特定世界覆盖默认设置
    _WORLDS_:
      world_nether:
        enable: false
      world_the_end:
        enable: false
# 机制设置
mechanics:
  # 通过添加更多斜杠创建额外的等级，例如 x/x/x/x/x
  # "x" 代表权重，决定概率比例
  # 17/2/1 = 85%/10%/5%
  # 85% 的计算方法是 17/(17+2+1) * 100%
  default-quality-ratio: 17/2/1
  # 稻草人设置，以防止作物被乌鸦攻击
  scarecrow:
    enable: true
    id: 'scarecrow'
    type: ITEM_FRAME
    range: 7
    # 如果启用，稻草人的范围将不受限制
    # 它将保护同一区块内的所有作物
    protect-chunk: false
  # 温室玻璃防止作物因季节变化而枯萎
  greenhouse:
    enable: true
    # 你可以在此使用 ID 列表；也支持原版方块
    id: 'greenhouse_glass'
    type: CHORUS
    range: 5
  # 与另一个世界同步季节
  sync-season:
    enable: false
    reference: world
  # 原版耕地机制
  vanilla-farmland:
    # 禁用原版耕地的湿润机制
    # 如果你更喜欢原版耕地，但水系统与原版机制冲突，这很有用
    disable-moisture-mechanic: false
    # 防止实体踩踏耕地
    prevent-trampling: false
  # 为不同方块设置全息图偏移校正
  hologram-offset-correction:
    "crop_stage_death": 0
  # 指定应由插件覆盖的方块类型
  # 一些常见作物：WHEAT/CARROTS/POTATOES/BEETROOTS/SWEET_BERRY_BUSH
  override-vanilla-blocks: []
other-settings:
  # 建议使用 MiniMessage 格式。如果你想使用传统颜色代码（"&"），请启用下面的支持。
  # 禁用此选项可以提高性能
  legacy-color-code-support: true
  # 需要 PlaceholderAPI 才能运行
  placeholder-register:
    '{skill-level}': '%levelplugin_farming%'
  # 使用其他插件的物品
  item-detection-order: []
  # 是否保护物品的原始描述
  # 使用记分板组件来识别插件的描述，
  # 这可能与一些仍使用 SpigotAPI#ItemMeta 的插件冲突
  protect-original-lore: false
  # 是否验证方块/家具是否与 CustomCrops 中的数据匹配
  # 如果使用 Oraxen，请启用此选项，因为其 API 更可靠
  double-check: false
```


# 💪 动作

动作系统提供了由插件提供的预设效果。不过，您也可以使用 API 添加自己的动作。此系统可应用于可以触发动作的任何地方，比如破坏作物、与种植盆互动等。

动作由三部分组成

```yaml
type: 动作类型
value: 动作的参数
chance: 可选 (0~1 默认: 1)
```

如果值是[整数](https://baike.baidu.com/item/%E6%95%B4%E6%95%B0/1293937)或[双精度值](https://baike.baidu.com/item/%E5%8F%8C%E7%B2%BE%E5%BA%A6%E6%B5%AE%E7%82%B9%E6%95%B0)，您可以使用[表达式](https://baike.baidu.com/item/%E8%A1%A8%E8%BE%BE%E5%BC%8F)，例如

```yaml
exp_action:
  type: exp
  value: '{level} * 3'
```

下面是一个结合了条件和动作的示例。在此示例中，如果您用空手与成熟的作物互动，它将被收获。如果您用种子与之互动，它将被重新种植。

![](/files/OpC7DDXHct5Rsl5ywNfJ)

```yaml
events:
  interact:
    action_1:
      type: conditional
      value:
        conditions:
          # 要求双手空着
          requirement_1:
            type: item-in-hand
            value:
              item: "AIR"
          requirement_2:
            type: item-in-hand
            value:
              hand: other
              item: "AIR"
        actions:
          action_1:
            type: break
            value: true
          action_2:
            type: swing-hand
            value: true
    action_2:
      type: conditional
      value:
        conditions:
          requirement_1:
            type: item-in-hand
            value:
              item: "customcrops:tomato_seeds"
              amount: 1
        actions:
          action_1:
            type: break
            value: true
          action_2:
            type: swing-hand
            value: true
          action_3:
            type: plant
            value:
              crop: tomato
              point: 0
          action_4:
            type: item-amount
            value: -1
```

## 动作库

> message (向玩家发送消息)

```yaml
messages_action:
  type: message
  value:
    - '<#FF4500>[1st] 恭喜！您获得了一等奖！'
```

> broadcast (向在线玩家发送消息)

```yaml
broadcast_action:
  type: broadcast
  value:
    - '你好！'
```

> command (执行控制台命令)

```yaml
command_action:
  type: command
  value:
    - 'money give {player} 200'
```

> player-command (以玩家身份执行命令)

```yaml
command_action:
  type: player-command
  value:
    - 'say 你好'
```

> random-command (从列表中随机执行一个控制台命令)

```yaml
command_action:
  type: random-command
  value:
    - 'money give {player} 200'
    - 'money give {player} 100'
    - 'money give {player} 50'
```

> close-inv (关闭玩家当前正在打开的物品栏)

```yaml
close_action:
   type: close-inv
```

> actionbar

```yaml
actionbar_action:
  type: actionbar
  value: '你好'
```

> random-actionbar

```yaml
actionbar_action:
  type: random-actionbar
  value: 
    - '嗨'
    - '你好'
    - '你妈'
```

> mending (给予玩家可以用于修复的经验)

```yaml
mending_action:
  type: mending
  value: 1
```

> force-tick

```yaml
tick_action:
  type: force-tick
```

> swing-hand

```yaml
swing_action:
  type: swing-hand
  value: true  # true = 主手 | false = 副手
```

> exp (直接给予玩家经验以提升等级)

```yaml
exp_action:
  type: exp
  value: 1
```

> chain (作为一组执行动作)

```yaml
chain_action:
  type: exp
  value: 
    action_1: ...
    action_2: ...
  chance: 0.5
```

> delay (延迟 x 个刻)

```yaml
delay_action:
  type: delay
  value: 
    delay: 20 # 以刻为单位
    async: false # 是否异步运行
    actions:
      action_1: ...
      action_2: ...
```

> timer

```yaml
timer_action:
  type: timer
  value: 
    async: false # 是否异步运行
    duration: 20 # 以刻为单位
    delay: 3 # 以刻为单位
    period: 2 # 以刻为单位
    actions:
      action_1: ...
      action_2: ...
```

> hologram (在一段时间内显示全息图)

```yaml
hologram_action:
  type: hologram
  value:
    duration: 20
    text: '{water_bar}'
    apply-correction: true # 对每株作物应用高度校正
    visible-to-all: false # 决定全息图是否能被所有玩家看到
    range: 32 # 决定可见范围
    y: 2
    x: 0
    z: 0
```

> fake-item (在一段时间内显示虚假物品)

```yaml
fake_item_action:
  type: fake-item
  value:
    duration: 25 # 刻
    position: other # other/player
    item: customcrops:water_animation
    use-item-display: false # 需要1.19.4+
    y: 0
    x: 0
    z: 0
    visible-to-all: true
    range: 32
```

> food

```yaml
https://zh.minecraft.wiki/w/%E9%A5%A5%E9%A5%BF

food_action:
  type: food
  value: 2
```

> saturation

```yaml
https://zh.minecraft.wiki/w/%E9%A5%A5%E9%A5%BF

saturation_action:
  type: saturation
  value: 1.5
```

> give-item

```yaml
item_action:
  type: give-item
  value:
    item: customcrops:tomato
    amount: 10
```

> item-amount

```yaml
item_amount_action:
  type: item-amount
  value: -1

item_amount_action:
  type: item-amount
  value:
    hand: main #main/off（这是一个可选参数）
    amount: -1
```

> durability

```yaml
durability_action:
  type: durability
  value: -1

durability_action:
  type: durability
  value:
    slot: OFF_HAND
    amount: -1
```

> variation (作物转变为另一种方块并停止生长)

```yaml
variation_action:
  type: variation
  value:
    gigantic:
      item: gigantic_tomato
      type: BLOCK # BLOCK / FURNITURE
      chance: 0.02
    xxx:
      item: xxx
      type: BLOCK
      chance: 0.07
```

> quality-crops

```yaml
crop_action:
  type: quality-crops
  value:
    to-inventory: false
    min: 1
    max: 4
    items:
      1: tomato
      2: tomato_silver_star
      3: tomato_golden_star
```

> drop-item

```yaml
drop_action:
  type: drop-item
  value:
    to-inventory: false
    ignore-fertilizer: true
    item: tomato_seeds
    min: 1
    max: 2
```

> plant

```yaml
plant_action:
  type: plant
  value:
    crop: tomato # 配置 ID
    point: 0
```

> break

```yaml
break_action:
  type: break
  value: true # 是否触发 "break" 事件
```

> particle

```yaml
particle_action:
  type: particle
  value:
    particle: FLAME
    x: 0.5
    y: 0.5
    z: 0.5
    count: 10
    offset-x: 0.5
    offset-y: 0.5
    offset-z: 0.5
    extra: 0.0
    # 仅当粒子为 ITEM_CRACK 时有效
    itemStack: customcrops:xxx
    # 仅当粒子为 REDSTONE/DUST_COLOR_TRANSITION 时有效
    color: 255,0,0
    scale: 1
    # 仅当粒子为 DUST_COLOR_TRANSITION 时有效
    to-color: 0,0,255
```

> give-money

```yaml
money_action:
  type: give-money
  value: 100.12
```

> take-money

```yaml
money_action:
  type: take-money
  value: 50.54
```

> title

```yaml
title_action:
  type: title
  value:
    title: '<green>你好！</green>'
    subtitle: '这是副标题！'
    fade-in: 20
    stay: 30
    fade-out: 10
```

> random-title

```yaml
title_action:
  type: random-title
  value:
    titles:
      - '<green>你好！</green>'
      - '<green>嗨！</green>'
    subtitles:
      - '副标题 1'
      - '副标题 2'
    fade-in: 20
    stay: 30
    fade-out: 10
```

> sound

```yaml
sound_action:
  type: sound
  value:
    key: 'minecraft:block.amethyst_block.place'
    source: 'player'
    volume: 1
    pitch: 1
```

> potion-effect

```yaml
potion_action:
  type: potion-effect
  value:
    type: 'blindness'
    duration: 20
    amplifier: 0
```

> plugin-exp (来自其他插件的经验，例如工作/技能插件)

```yaml
plugin_exp_action:
  type: plugin-exp
  value:
    plugin: AureliumSkills
    exp: 20
    target: FARMING
```

> conditional (只有在玩家满足条件时才能触发动作)

```yaml
conditional_action:
  type: conditional 
  value:
    conditions:
      requirement_1:
        ...
      requirement_2:
        ...   
    actions:
      action_1:
        ...
      action_2:
        ...
```

> priority (执行满足条件的第一个动作组。)

```yaml
priority_action:
  type: priority
  value:
    priority_1:
      conditions:
         ...
      actions:
         ...
    priority_2:
      conditions:
         ...
      actions:
         ...
    others:
      actions:
         ...   
```

> level

```yaml
money_action:
  type: level
  value: -10
```

> spawn-entity

```yaml
spawn_entity_action:
  type: spawn-entity
  value:
    id: MythicMobs:XXX_mob  # 对于原版实体，使用大写字母，例如"SHEEP"
    x: 0
    y: 0
    z: 0
    properties:
      level: 0
```


# ✅ 条件

插件提供了强大的条件系统。您可以同时使用简单条件和复杂条件。这里有一些例子供您学习条件。

> 简单的生物群系条件仅包含必要的参数

```yaml
biome:
  - minecraft:ocean
  - minecraft:deep_ocean
  - minecraft:cold_ocean
  - minecraft:deep_cold_ocean
  - minecraft:frozen_ocean
  - minecraft:deep_frozen_ocean
  - minecraft:lukewarm_ocean
  - minecraft:deep_lukewarm_ocean
  - minecraft:warm_ocean
```

> 复杂条件允许您使用相同类型的条件并添加`not-met-actions` 部分名称（本例中为“requirement\_permission\_1”）是完全可自定义的，只要它不与条件类型名称冲突即可。

```yaml
# 此示例使用了两个权限条件
requirement_permission_1:
  type: permission
  value:
    - xxx.1.xxx
requirement_permission_2:
  type: permission
  value:
    - xxx.2.xxx
  not-met-actions: #译者注：当以上所有条件未命中会执行此动作组
    action_1:
      type: xxx
      value: ...

# 错误用法（YAML 格式不允许这样做）
permission:
  - xxx.1.xxx
permission:
  - xxx.2.xxx
```

## 条件库

> time（游戏时间 0\~23999）

```yaml
time:
  - 0~1000
  - 2000~6000

advanced_requirement:
  type: time
  value:
  - 0~1000
  - 2000~6000
```

> ypos（玩家的 Y 坐标）

```yaml
ypos:
  - 0~43
  - -45~12
  
advanced_requirement:
  type: ypos
  value:
  - 0~43
  - -45~12
```

> biome（支持自定义生物群系）

```yaml
biome:
  - minecraft:plains  <- 白名单

'!biome':
  - minecraft:plains  <- 黑名单

advanced_requirement:
  type: biome
  value:
  - minecraft:plains

advanced_requirement:
  type: '!biome'
  value:
  - minecraft:plains
```

> world

```yaml
world:
  - world

'!world':
  - blacklist_world

advanced_requirement:
  type: world
  value:
  - world

advanced_requirement:
  type: '!world'
  value:
  - blacklist_world
```

> weather

```yaml
weather:
  - thunder
  - clear
  - rain

advanced_requirement:
  type: 'weather'
  value:
  - thunder
  - clear
  - rain
```

> date（现实世界日期）

```yaml
date:
  - 12/25
  - 6/1

advanced_requirement:
  type: 'date'
  value:
  - 12/25
  - 6/1
```

> permission

```yaml
permission: customfishing.admin

'!permission': blacklist.perm

advanced_requirement:
  type: 'permission'
  value: customfishing.admin
  
advanced_requirement:
  type: '!permission'
  value: blacklist.perm
```

> “>” “>=” “<” “<=” “=” “!=”

```yaml
'='
  value1: '20'
  value2: '%player_health%'

advanced_requirement:
  type: '='
  value:
    value1: '20'
    value2: '%player_health%'
```

> “startsWith” “endsWith” “equals” “contains” “in-list”

```yaml
'!startWith':
  value1: '%player_name%'
  value2: 'X'  <- 不以 "X" 开头的玩家名称

advanced_requirement:
  type: 'contains'
  value:
    value1: '%player_name%'
    value2: '_'  <- 包含 "_" 的玩家名称

advanced_requirement:
  type: '!equals'
  value:
    value1: '%player_name%'
    value2: 'XiaoMoMi'  <- 不等于 "XiaoMoMi" 的玩家名称

advanced_requirement:
  type: 'in-list'
  value:
    papi: '%player_name%'
    values: 
      - 'XiaoMoMi'
      - 'XIAOMOMI'
      - 'XlA0M0Ml'
```

> logic（创建复杂条件）

```yaml
advanced_requirement:
  type: '&&'
  value:
    in-lava: true
    requirement_time:
      type: time
      value:
        - 0~12000
    '||':
      world:
        - world_nether
      '&&':
        ypos:
          - -64~-32
        world:
          - world
```

> level（玩家经验等级）

```yaml
level: 10

advanced_requirement:
  type: 'level'
  value: 10
```

> random（0\~1）

```yaml
random: 0.3   <- 30% 的几率

advanced_requirement:
  type: 'random'
  value: 0.7   <- 70% 的几率
```

> cooldown

```yaml
cooldown:
  key: unique
  time: 1000 #毫秒

advanced_requirement:
  type: 'cooldown'
  value:
    key: A
    time: 100 #毫秒
```

> regex

```yaml
regex:
  papi: %xxx%
  regex: "[A-Z]"

advanced_requirement:
  type: 'regex'
  value:
    papi: %xxx%
    regex: "[A-Z]"
```

> environment

```yaml
environment:
  - normal
  - nether
  - the_end
  
advanced_requirement:
  type: '!environment'
  value:
    - nether
    - the_end
    - custom
```

> potion-effect

```yaml
potion-effect: "LUCK>=0"

advanced_requirement:
  type: 'potion-effect'
  value: "LUCK!=-1"

"-1": 玩家没有此药水效果
"值不低于0": 药水效果的等级

示例:
  LUCK==1
  LUCK<5
  LUCK>=0
```

> temperature

```yaml
temperature:
  - 0.15~0.85

advanced_requirement:
  type: "temperature"
  value:
  - 0.15~0.85
```

> sneak

```yaml
sneak: true

advanced_requirement:
  type: "sneak"
  value: true
```

> plugin-level

```yaml
plugin-level:
  plugin: AureliumSkills
  level: 10
  target: FARMING

advanced_requirement:
  type: plugin-level
  value:
    plugin: AureliumSkills
    level: 10
    target: FARMING
```

> season

```yaml
season:
  - Spring

advanced_requirement:
  type: season
  value:
    - Spring

condition_season:
  type: suitable-season
  value:
  - Spring

condition_season:
  type: unsuitable-season
  value:
  - Winter
```

> fertilizer

```yaml
fertilizer:
  has: true
  
fertilizer:
  has: false

advanced_requirement:
  type: fertilizer
  value:
    has: true

advanced_requirement:
  type: fertilizer
  value:
    has: true
    key:
      - speed_grow_1
      - speed_grow_2
```

> item-in-hand

```yaml
item-in-hand:
  item: "AIR"

item-in-hand:
  item: "*" # 任意物品

advanced_requirement:
  type: item-in-hand
  value:
    hand: other # 另一只手
    item: "PAPER"
    amount: 32
```

> light / natural-light

```yaml
light:
   - 0~7

natural-light:
   - 7~14

advanced_requirement:
  type: light
  value:
    - 0~1
    - 3~5

condition_light:
  type: natural-light-more-than
  value: 8

condition_light:
  type: natural-light-less-than
  value: 8

condition_light:
  type: light-less-than
  value: 8

condition_light:
  type: light-more-than
  value: 7
```

> gamemode

```yaml
gamemode:
   - creative

advanced_requirement:
  type: gamemode
  value:
    - creative
    - adventure
```

> crow attack

```yaml
condition_xxx:
  type: crow-attack
  value:
    chance: 0.005
    fly-model: crow_fly
    stand-model: crow_stand
```

> water more than （适用于自定义作物盆）

```yaml
condition_xxx:
  type: water-more-than
  value: 0

ondition_xxx:
  type: water-more-than
  value:
    y: -1  # 如果未设置，y 默认为 -1
    value: 0
```

> water less than （适用于自定义作物盆）

```yaml
condition_xxx:
  type: water-less-than
  value: 1

condition_xxx:
  type: water-less-than
  value:
    y: -1 # 如果未设置，y 默认为 -1
    value: 1
```

> point more than

```yaml
condition_xxx:
  type: point-more-than
  value: 1
```

> point less than

```yaml
condition_xxx:
  type: point-less-than
  value: 1
```

> moisture more than （适用于原版耕地）

```yaml
condition_xxx:
  type: moisture-more-than
  value: 0

condition_xxx:
  type: moisture-more-than
  value:
    y: -1 # 如果未设置，y 默认为 -1
    value: 0
```

> moisture less than （适用于原版耕地）

```yaml
condition_xxx:
  type: moisture-less-than
  value: 1

condition_xxx:
  type: moisture-less-than
  value:
    y: -1 # 如果未设置，y 默认为 -1
    value: 1
```

> pot

```yaml
condition_xxx:
  type: pot
  value:
    y: -1
    id:
      - default
```

> fertilizer

```yaml
condition_xxx:
  type: fertilizer
  value:
  - speed_grow_1

# 没有肥料
condition_xxx:
  type: fertilizer
  value:
    y: -1 # Y默认为0
    has: false 

# 黑名单id
condition_xxx:
  type: fertilizer
  value:
    y: -1
    has: false 
    type:
     - speed_grow_1
     - soil_retain_2

# 白名单id
condition_xxx:
  type: fertilizer
  value:
    y: 0
    has: true
    type:
     - speed_grow_1
     - speed_grow_2
     - speed_grow_3
```

> fertilizer类型

```yaml
condition_xxx:
  type: fertilizer-type
  value:
  - SPEED_GROW

# 没有肥料
condition_xxx:
  type: fertilizer
  value:
    has: false 

# 黑名单类型
condition_xxx:
  type: fertilizer
  value:
    has: false 
    type:
     - speed_grow
     - soil_retain

# 白名单类型
condition_xxx:
  type: fertilizer
  value:
    has: true
    type:
     - speed_grow
```

> region （需要WorldGuard）

```yaml
advanced_requirement:
  type: region
  value:
    mode: 1 # 1,2
    values:
      - a
      - b
region:
  mode: 2
  values:
    - a
    - b
```

<figure><img src="/files/StVkj9ddVwukMuksgfI6" alt=""><figcaption><p>模式 1</p></figcaption></figure>

<figure><img src="/files/4gjfreclxbTQRoU6kmkS" alt=""><figcaption><p>模式 2</p></figcaption></figure>

> hand

```yaml
condition_xxx:
  type: hand
  value: hand #off_hand
```


# 🅿️ 占位符和表达式

## 插件占位符

| 占位符                             | 值           |
| ------------------------------- | ----------- |
| %customcrops\_season%           | 获取玩家所在世界的季节 |
| %customcrops\_season\_\<world>% | 获取指定世界的季节   |
| %customcrops\_date%             | 获取玩家所在世界的日期 |
| %customcrops\_date\_\<world>%   | 获取指定世界的日期   |

## 内部占位符

| 占位符           | 值               |
| ------------- | --------------- |
| {player}      | 玩家名称            |
| {x}           | X坐标             |
| {y}           | Y坐标             |
| {z}           | Z坐标             |
| {world}       | 世界名称            |
| {water\_bar}  | 水栏图片            |
| {storage}     | 洒水器/洒水壶/种植盆的储水量 |
| {current}     | 当前剩余的储水量        |
| {near}        | 最近的玩家名称         |
| {max\_times}  | 肥料能存储的最大次数      |
| {left\_times} | 肥料存储的剩余次数       |

## 表达式

### 注册占位符 <a href="#register-placeholders" id="register-placeholders"></a>

插件不支持直接使用 PlaceholderAPI 占位符。但在 config.yml 文件中有一个部分，可用于自定义占位符的标识符，并几乎可在任何位置使用它

让我们尝试下面的示例。你需要将 `%levelplugin_farming%` 替换为当前等级提升工具的占位符

```yaml
placeholder-register:
  '{skill-level}': '%levelplugin_farming%'
```

现在你几乎可以在任何地方使用这个占位符

```yaml
# 采集时掉落更多物品
action_1:
  type: drop-item
  value:
    ignore-fertilizer: true
    item: tomato_seeds
    min: '1 + {skill-level}*0.1'
    max: '2 + {skill-level}*0.15'
  chance: 1
```


# 🗡️ 随机刻对比计划刻

### 随机刻是如何工作的？

> [区块](https://zh.minecraft.wiki/w/%E5%8C%BA%E5%9D%97)由每16个高度为16个块的子区块组成，每个子区块都是一个16×16×16=4096个方块的立方体。区块从最低的y级别开始垂直分布。每个区块刻，从区块中的每个部分中随机选择一些方块。在这些位置的方块会获得“随机刻”。
>
> ——Minecraft wiki

CustomCrops每秒为方块提供随机刻。随机刻速度的默认值是20，这意味着插件每秒从一个16x16x16的区块中选择20个随机方块进行刻。

![](/files/04PLdiNfW4ChXCD1DbAo)

<figure><img src="/files/4JpZlT8AxBjyNsTnYMaE" alt=""><figcaption><p>一部分的大小（F3+G）</p></figcaption></figure>

### 计划刻是如何工作的

计划刻是指每个刻都是提前规划好的，在每个刻周期内，插件可以保证所有区块都是随机分布的，虽然一个周期内各个区块的刻时间不一样，但是如果进行多次刻，那么它们的刻次数都是差不多的。

![](/files/QP2GlD3SoJdVcyCm0F28)

![](/files/wqUCeTRmHOSTG36rCmat)


# 🤝 兼容性


# MMOItems

https\://www\.spigotmc.org/resources/39267/

对于物品：

```yaml
MMOItems:类型:ID
```


# MythicMobs

https\://mythiccraft.io/index.php?resources/mythicmobs.1/

对于物品：

```yaml
MythicMobs:id
```


# Zaphkiel

对于物品：

```yaml
Zaphkiel:id
```


# ExecutableItems

对于物品:

```yaml
ExecutableItems:id
```


# NeigeItems

https\://github.com/ankhorg/NeigeItems-Kotlin/releases

对于物品：

```yaml
NeigeItems:id
```


# 支持的等级系统

* mcMMO <https://www.spigotmc.org/resources/official-mcmmo-original-author-returns.64348/>
* AureliumSkills AuraSkills <https://www.spigotmc.org/resources/aurelium-skills-advanced-skills-stats-abilities-and-more.81069/>
* Jobs Reborn <https://www.spigotmc.org/resources/jobs-reborn.4216/>
* EcoSkills <https://www.spigotmc.org/resources/ecoskills-%E2%AD%95-addictive-mmorpg-skills-%E2%9C%85-create-custom-skills-stats-effects-mana-%E2%9C%A8-plug-play.95541/>
* EcoJobs <https://www.spigotmc.org/resources/ecojobs-%E2%AD%95-powerful-employment-system-%E2%9C%85-create-custom-jobs-%E2%9C%A8-levelling-effects.105190/>
* MMOCore <https://www.spigotmc.org/resources/mmocore.70575/>


# BetonQuest 3.0

https\://betonquest.org/RELEASE/

<https://modrinth.com/plugin/betonquestaddon>


# BattlePass

https\://www\.spigotmc.org/resources/63076/

```yaml
quests:
  1: # 收获作物
    type: customcrops_harvest
    variable: tomato_stage_4
    name: '收获番茄'
    required-progress: 5
  2: # 种植作物
    type: customcrops_plant
    variable: tomato
    name: '种植番茄'
    required-progress: 5
```


# ClueScrolls

https\://www\.spigotmc.org/resources/30276/

```yaml
common_1:
   lore: '&a★ &f收获 %amount% 个番茄: %completed%'
   clueType: customcrops_harvest
   amount: 7-15
   objective: 收获 %amount% 个番茄
   clueName: 农夫
   data:
     id: customcrops:tomato_stage_4 <- 特定阶段ID

common_2:
   lore: '&a★ &f种植 %amount% 个番茄: %completed%'
   clueType: customcrops_plant
   amount: 7-15
   objective: 种植 %amount% 个番茄
   clueName: 农夫
   data:
     id: tomato  <- 特定作物ID
```


# TypeWriter

https\://modrinth.com/plugin/typewriter

{% embed url="<https://github.com/Xiao-MoMi/CustomCropsTypeWriterExtension>" %}


# ⚡️ 不安全命令

该插件具有三个不安全的命令，您只在极少数情况下需要它们。

## delete

此命令将永远删除该区块的作物数据，请谨慎操作。

## restore

此命令会根据 customcrops记录的数据将这些方块恢复到真实世界。这个命令仅对一个区域有效，也就是一个16x16x16 的区域。

## fix

此命令将根据真实世界中的方块和实体状态重新记录数据到插件中。同时，数据中的错误信息也会被移除。这个命令仅对一个区域有效，也就是一个16x16x16 的区域。


# ⌨️ 应用程序编程接口

在使用 CustomCrops API 之前，请确保您已导入 Paper API。

{% embed url="<https://docs.papermc.io/paper/dev/project-setup>" %}

然后，您可以将 CustomCrops API 依赖项添加到您的项目中

### **📌 存储库**

```kotlin
repositories {
    maven("https://repo.momirealms.net/releases/")
    // 如果你的网络环境受限可以尝试下面的存储库地址
    // maven("https://repo-momi.gtemc.cn/releases/")
}
```

### **📌 依赖**

```kotlin
dependencies {
    compileOnly("net.momirealms:custom-crops:{version}")
}
```

最后，不要忘记将 CustomCrops 添加到 plugin.yml

```yaml
depend:
  - CustomCrops
```


# 基础操作

## 调整 Bukkit 位置 <a href="#adapt-bukkit-location" id="adapt-bukkit-location"></a>

```java
Pos3 pos3 = Pos3.from(location);
```

## 获取 CustomCrops 世界 <a href="#get-customcrops-world" id="get-customcrops-world"></a>

```java
BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(Bukkit.getWorld("world"));
```

## 获取/删除 Blockstate <a href="#get-remove-blockstate" id="get-remove-blockstate"></a>

```java
CustomCropsWorld<?> world = ...;
world.getBlockState(pos3);
world.removeBlockState(pos3);
```

## 添加 Blockstate <a href="#add-blockstate" id="add-blockstate"></a>

```java
CropBlock cropBlock = (CropBlock) BuiltInBlockMechanics.CROP.mechanic();
CustomCropsBlockState blockState = cropBlock.createBlockState();
cropBlock.id(blockState, "tomato");
cropBlock.point(blockState, 0);
world.addBlockState(pos3, blockState);
```

## 在 Blockstate 中设置/删除/获取自定义数据 <a href="#set-remove-get-custom-data-in-blockstate" id="set-remove-get-custom-data-in-blockstate"></a>

```java
SynchronizedCompoundMap compoundMap = blockState.compoundMap();
compoundMap.remove("key");
compoundMap.put("key", new StringTag("key", "test"));
compoundMap.get("key");
```

## 从 Blockstate 获取方块类型 <a href="#get-the-block-type-from-blockstate" id="get-the-block-type-from-blockstate"></a>

```java
CustomCropsBlock block = blockState.type();
if (block instanceof CropBlock cropBlock) {
    CropConfig cropConfig = cropBlock.config(blockState);
}
```

## 从注册表获取内置方块/物品类型 <a href="#get-built-in-block-item-type-from-registry" id="get-built-in-block-item-type-from-registry"></a>

```java
PotBlock potBlock = (PotBlock) BuiltInBlockMechanics.POT.mechanic();

SeedItem seedItem = (SeedItem) BuiltInItemMechanics.SEED.mechanic();
```

## 在 Bukkit 世界上放置/删除方块 <a href="#place-remove-blocks-on-bukkit-worlds" id="place-remove-blocks-on-bukkit-worlds"></a>

```javascript
ItemManager itemManager = BukkitCustomCropsPlugin.getInstance().getItemManager();
itemManager.placeFurniture(location, "id", FurnitureRotation.NONE);
itemManager.placeBlock(location, "id");
itemManager.removeFurniture(location);
itemManager.removeBlock(location);
```

## 获取ID <a href="#get-ids" id="get-ids"></a>

```java
ItemManager itemManager = BukkitCustomCropsPlugin.getInstance().getItemManager();
String blockID = itemManager.blockID(block);
String furnitureID = itemManager.furnitureID(entity);
String itemID = itemManager.id(itemStack);
```

## 获取内置物品的配置 <a href="#get-configs-of-the-built-in-items" id="get-configs-of-the-built-in-items"></a>

```java
CropConfig cropConfig = Registries.CROP.get("tomato");
SprinklerConfig sprinklerConfig = Registries.SPRINKLER.get("sprinkler");
PotConfig potConfig = Registries.POT.get("default");
WateringCanConfig wateringCanConfig = Registries.WATERING_CAN.get("watering_can_1");
FertilizerConfig fertilizerConfig = Registries.FERTILIZER.get("quality_1");
```


# 自定义机制

本页将以甘蔗为例，大致实现一个类似于原版甘蔗的机制。

首先为item和block创建两个类

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.core.item.AbstractCustomCropsItem;
import net.momirealms.customcrops.common.util.Key;

public class SugarCaneItem extends AbstractCustomCropsItem {
    
    private static SugarCaneItem instance;

    public SugarCaneItem() {
        super(Key.key("customcrops", "sugarcane_item"));
    }

    public static SugarCaneItem instance() {
        if (instance == null) {
            instance = new SugarCaneItem();
        }
        return instance;
    }
}
```

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.core.block.AbstractCustomCropsBlock;
import net.momirealms.customcrops.common.util.Key;

public class SugarCaneBlock extends AbstractCustomCropsBlock {

    private static SugarCaneBlock instance;

    private SugarCaneBlock() {
        super(Key.key("customcrops", "sugarcane_block"));
    }

    // 此方法用于验证一个方块是否属于此机制
    // id 将是来自自定义物品插件（例如 Oraxen）的物品 ID
    @Override
    public boolean isBlockInstance(String id) {
        return id.equals("customcrops:sugarcane_block_id");
    }
    
    public static SugarCaneBlock instance() {
        if (instance == null) {
            instance = new SugarCaneBlock();
        }
        return instance;
    }
    
    @Override
    public NamedTextColor insightColor() {
        return NamedTextColor.YELLOW;
    }
}
```

然后在`onEnable()`方法中注册

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.core.Registries;
import net.momirealms.customcrops.api.core.RegistryAccess;
import net.momirealms.customcrops.api.event.CustomCropsReloadEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.List;

public class YourPlugin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        RegistryAccess access = BukkitCustomCropsPlugin.getInstance().getRegistryAccess();
        access.registerBlockMechanic(SugarCaneBlock.instance());
        access.registerItemMechanic(SugarCaneItem.instance());
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onPluginReload(CustomCropsReloadEvent event) {
        // ITEMS 和 BLOCKS 是临时映射，用于将物品 ID 与机制类型关联起来
        // 例如，如果你有多个具有相同机制的方块，比如红色羊毛、绿色羊毛和灰色羊毛，你需要在这个注册表中注册它们。
        // 当插件重新加载以应用配置文件的更改时，这个注册表会被清空
        // 注意：绝不要使用标注了 @DONOTUSE 的注册表
        for (String sugarcaneItem : List.of("customcrops:sugarcane_item_id")) {
            Registries.ITEMS.register(sugarcaneItem, SugarCaneItem.instance());
        }
        for (String sugarcaneBlock : List.of("customcrops:sugarcane_block_id")) {
            Registries.BLOCKS.register(sugarcaneBlock, SugarCaneBlock.instance());
        }
    }
}
```

然后我们可以创建一些基本逻辑，例如放置甘蔗方块

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.core.ExistenceForm;
import net.momirealms.customcrops.api.core.InteractionResult;
import net.momirealms.customcrops.api.core.item.AbstractCustomCropsItem;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.common.util.Key;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;

import java.util.Collection;
import java.util.List;

public class SugarCaneItem extends AbstractCustomCropsItem {

    private static SugarCaneItem instance;

    public SugarCaneItem() {
        super(Key.key("customcrops", "sugarcane_item"));
    }

    public static SugarCaneItem instance() {
        if (instance == null) {
            instance = new SugarCaneItem();
        }
        return instance;
    }

    @Override
    public InteractionResult interactAt(WrappedInteractEvent wrapped) {
        // 甘蔗应该种植在方块上
        if (wrapped.existenceForm() != ExistenceForm.BLOCK)
            return InteractionResult.PASS;
        // 甘蔗应该种植在方块的上表面
        if (wrapped.clickedBlockFace() != BlockFace.UP)
            return InteractionResult.PASS;
        // 获取被点击方块的位置
        Location location = wrapped.location();

        Block block = location.getBlock();
        // 应该种植在沙子或泥土上
        if (block.getType() != Material.SAND && block.getType() != Material.RED_SAND && block.getType() != Material.DIRT) {
            return InteractionResult.PASS;
        }

        // 应该种植在水附近
        outer: {
            for (BlockFace face : List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST)) {
                if (block.getRelative(face).getType() == Material.WATER) {
                    break outer;
                }
            }
            return InteractionResult.PASS;
        }

        // 检查这个地方是否适合种植
        Location sugarcaneLocation = location.clone().add(0,1,0);
        if (!suitableForPlant(sugarcaneLocation)) {
            return InteractionResult.PASS;
        }

        // 减少物品的数量
        wrapped.itemInHand().setAmount(wrapped.itemInHand().getAmount() - 1);


        // 获取 CustomCrops 世界并添加方块状态
        CustomCropsWorld<?> world = wrapped.world();
        CustomCropsBlockState newBlockState = SugarCaneBlock.instance().createBlockState();
        world.addBlockState(Pos3.from(sugarcaneLocation), newBlockState);

        // 放置方块
        BukkitCustomCropsPlugin.getInstance().getItemManager().placeBlock(sugarcaneLocation, "customcrops:sugarcane_block_id");

        return InteractionResult.COMPLETE;
    }

    private boolean suitableForPlant(Location location) {
        Block block = location.getBlock();
        if (block.getType() != Material.AIR) return false;
        Location center = LocationUtils.toBlockCenterLocation(location);
        Collection<Entity> entities = center.getWorld().getNearbyEntities(center, 0.5,0.5,0.5);
        entities.removeIf(entity -> (entity instanceof Player || entity instanceof Item));
        return entities.isEmpty();
    }
}
```

现在你应该可以种植甘蔗了（我在 gif 中使用菠萝作为替代品，因为我还没有准备甘蔗模型）

<figure><img src="/files/q4GwmSJcsanP8VlNL799" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/JNsmtFjUOVkjOAltysfx" alt=""><figcaption><p>洞察模式</p></figcaption></figure>

然后我们可以配置甘蔗的生长/破坏逻辑

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.core.block.AbstractCustomCropsBlock;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.misc.NamedTextColor;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.common.util.Key;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

import java.util.Collection;
import java.util.Optional;

public class SugarCaneBlock extends AbstractCustomCropsBlock {

    private static SugarCaneBlock instance;

    private SugarCaneBlock() {
        super(Key.key("customcrops", "sugarcane_block"));
    }

    @Override
    public boolean isBlockInstance(String id) {
        return id.equals("customcrops:sugarcane_block_id");
    }

    public static SugarCaneBlock instance() {
        if (instance == null) {
            instance = new SugarCaneBlock();
        }
        return instance;
    }

    @Override
    public void randomTick(CustomCropsBlockState state, CustomCropsWorld<?> world, Pos3 location, boolean offlineTick) {
        // 首先检查是否是顶层方块
        Pos3 upper = location.add(0,1,0);
        Optional<CustomCropsBlockState> upperState = world.getBlockState(upper);
        if (upperState.isPresent() && upperState.get().type() instanceof SugarCaneBlock) {
            return;
        }

        // 获取当前高度
        int height = 1;
        for (int i = 1; i < 4; i++) {
            Pos3 under = location.add(0,-i,0);
            Optional<CustomCropsBlockState> optionalState = world.getBlockState(under);
            if (optionalState.isPresent() && optionalState.get().type() instanceof SugarCaneBlock) {
                height++;
            } else {
                break;
            }
        }
        if (height >= 4) return;

        // 检查是否有足够的空间生长
        Location upperBukkitLocation = upper.toLocation(world.bukkitWorld());
        // 切换到主线程
        BukkitCustomCropsPlugin.getInstance().getScheduler().sync().run(() -> {
            if (!suitableForGrow(upperBukkitLocation)) {
                return;
            }
            // 放置上层方块
            BukkitCustomCropsPlugin.getInstance().getItemManager().placeBlock(upperBukkitLocation, "customcrops:sugarcane_block_id");
            world.addBlockState(upper, createBlockState());
        }, upperBukkitLocation);
    }

    private boolean suitableForGrow(Location location) {
        Block block = location.getBlock();
        if (block.getType() != Material.AIR) return false;
        Location center = LocationUtils.toBlockCenterLocation(location);
        Collection<Entity> entities = center.getWorld().getNearbyEntities(center, 0.5,0.5,0.5);
        entities.removeIf(entity -> (entity instanceof Player || entity instanceof Item));
        return entities.isEmpty();
    }

    @Override
    public void onBreak(WrappedBreakEvent event) {
        Location location = event.location();
        Pos3 pos3 = Pos3.from(location);
        CustomCropsWorld<?> world = event.world();

        // 构建物品
        ItemStack itemToDrop = BukkitCustomCropsPlugin.getInstance().getItemManager().build(null, "customcrops:sugarcane_item_id");

        // 破坏上层方块
        for (int i = 0; i < 4; i++) {
            Pos3 upper = pos3.add(0, i,0);
            Optional<CustomCropsBlockState> optionalState = world.getBlockState(upper);
            if (optionalState.isPresent() && optionalState.get().type() instanceof SugarCaneBlock) {
                world.removeBlockState(upper);
                Location temp = upper.toLocation(world.bukkitWorld());
                BukkitCustomCropsPlugin.getInstance().getItemManager().removeBlock(temp);
                temp.getWorld().dropItemNaturally(temp, itemToDrop);
            } else {
                break;
            }
        }
    }

    @Override
    public NamedTextColor insightColor() {
        return NamedTextColor.YELLOW;
    }
}

```

<figure><img src="/files/DJIZafp3RG5bdvezKtfn" alt=""><figcaption></figcaption></figure>


# 插件事件

可用的事件可以在下面找到

{% embed url="<https://github.com/Xiao-MoMi/Custom-Crops/tree/main/api/src/main/java/net/momirealms/customcrops/api/event>" %}


# 其他方块系统

除了插件提供的oraxen和ItemsAdder兼容性之外，你还可以将customcrops适配到自己的服务器上，特别是对于一些具有独立开发能力的大型服务器。

要使您自己的插件适应自定义作物，您只需要实现两个类： `AbstractCustomEventListener`和`CustomItemProvider`

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.core.AbstractCustomEventListener;
import net.momirealms.customcrops.api.core.AbstractItemManager;
import org.bukkit.event.EventHandler;

public class MyCustomListener extends AbstractCustomEventListener {

    public MyCustomListener(AbstractItemManager itemManager) {
        super(itemManager);
    }

    @EventHandler(ignoreCancelled = true)
    public void onInteractFurniture(FurnitureInteractEvent event) {
        itemManager.handlePlayerInteractFurniture(...);
    }

    @EventHandler(ignoreCancelled = true)
    public void onInteractCustomBlock(CustomBlockInteractEvent event) {
        itemManager.handlePlayerInteractBlock(...);
    }

    @EventHandler(ignoreCancelled = true)
    public void onBreakFurniture(FurnitureBreakEvent event) {
        itemManager.handlePlayerBreak(...);
    }

    @EventHandler(ignoreCancelled = true)
    public void onBreakCustomBlock(CustomBlockBreakEvent event) {
        itemManager.handlePlayerBreak(..);
    }
    
    @EventHandler(ignoreCancelled = true)
    public void onPlaceFurniture(FurniturePlaceEvent event) {
        itemManager.handlePlayerPlace(...);
    }
    
    @EventHandler(ignoreCancelled = true)
    public void onPlaceCustomBlock(CustomBlockPlaceEvent event) {
        itemManager.handlePlayerPlace(...);
    }
}
```

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.core.CustomItemProvider;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.Nullable;

public class MyCustomItemProvider implements CustomItemProvider {

    @Override
    public boolean removeCustomBlock(Location location) {
        return ...;
    }

    @Override
    public boolean placeCustomBlock(Location location, String id) {
        return ...;
    }

    @Override
    public @Nullable Entity placeFurniture(Location location, String id) {
        return ...;
    }

    @Override
    public boolean removeFurniture(Entity entity) {
        return ...;
    }

    @Override
    public @Nullable String blockID(Block block) {
        return ...;
    }

    @Override
    public @Nullable String itemID(ItemStack itemStack) {
        return ...;
    }

    @Override
    public @Nullable ItemStack itemStack(Player player, String id) {
        return ...;
    }

    @Override
    public @Nullable String furnitureID(Entity entity) {
        return ...;
    }

    @Override
    public boolean isFurniture(Entity entity) {
        return ...;
    }
}
```

最后，在插件启用上注册它们

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.core.AbstractItemManager;
import org.bukkit.plugin.java.JavaPlugin;

public class MyPlugin extends JavaPlugin {

    @Override
    public void onEnable() {
        register();
    }

    public void register() {
        AbstractItemManager itemManager = BukkitCustomCropsPlugin.getInstance().getItemManager();
        MyCustomListener listener = new MyCustomListener(itemManager);
        MyCustomItemProvider provider = new MyCustomItemProvider();
        itemManager.setCustomEventListener(listener);
        itemManager.setCustomItemProvider(provider);
    }
}

```


# 自定义季节提供

创建一个实现`SeasonProvider`的类，然后在插件启用上注册它

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.core.world.Season;
import net.momirealms.customcrops.api.integration.SeasonProvider;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;

public class MySeasonProvider implements SeasonProvider {
    
    @Override
    public @NotNull Season getSeason(@NotNull World world) {
        return ...;
    }

    @Override
    public String identifier() {
        return "MySeasonPlugin";
    }
}
```

```java
package net.momirealms.customcrops.api.example;

import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import org.bukkit.plugin.java.JavaPlugin;

public class MyPlugin extends JavaPlugin {

    @Override
    public void onEnable() {
        register();
    }

    public void register() {
        BukkitCustomCropsPlugin.getInstance().getIntegrationManager().registerSeasonProvider(new MySeasonProvider());
    }
}

```


# 🎣 CustomFishing


# 🧭 如何配置每个文件

供快速参考的文章

## loot/game-conditions.yml

{% content-ref url="/pages/rJYbUhnsOXXc0j1Rn23Y" %}
[⚖️ 权重系统 \[必读\]](/customfishing/cha-jian-wiki/customfishing/quan-zhong-xi-tong-bi-du)
{% endcontent-ref %}

## /contents

## &#x20;     /item

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

{% content-ref url="/pages/x6s9CHdxd4MrNDrz6y3E" %}
[🏆 战利品](/customfishing/cha-jian-wiki/customfishing/ge-shi/zhan-li-pin)
{% endcontent-ref %}

```yaml
rubbish:
  # 物品部分
  material: cod
  display:
    name: <#00BFFF>福岛鱼</#00BFFF>
    lore:
      - <gray>请保护环境，不要污染大海...
  custom-model-data: 50000
  

  # 战利品部分
  nick: <#00BFFF>福岛鱼</#00BFFF>
  show-in-fishfinder: false
  disable-stat: true
  disable-game: true
  instant-game: false
  prevent-grabbing: false
```

## &#x20;     /entity

{% content-ref url="/pages/YzZXqJUQaya86qxuO8lv" %}
[🦖 实体](/customfishing/cha-jian-wiki/customfishing/ge-shi/shi-ti)
{% endcontent-ref %}

{% content-ref url="/pages/x6s9CHdxd4MrNDrz6y3E" %}
[🏆 战利品](/customfishing/cha-jian-wiki/customfishing/ge-shi/zhan-li-pin)
{% endcontent-ref %}

```yaml
magma_cube:
  # 战利品部分
  show-in-fishfinder: false
  disable-stat: true
  disable-game: true
  nick: <red>岩浆怪</black>
  
  # 实体部分
  entity: magma_cube
  velocity:
    horizontal: 1.1
    vertical: 1.3
```

## &#x20;     /enchant

{% content-ref url="/pages/dY9J9ZYPDP6CGbQYCIuv" %}
[✨ 效果](/customfishing/cha-jian-wiki/customfishing/ge-shi/xiao-guo)
{% endcontent-ref %}

```yaml
# 命名空间:附魔:等级
minecraft:luck_of_the_sea:1:
  requirements: {}
  effects:
    group:
      type: group-mod
      value:
        - silver_star:+2
        - golden_star:+1
```

## &#x20;     /hook

{% content-ref url="/pages/dY9J9ZYPDP6CGbQYCIuv" %}
[✨ 效果](/customfishing/cha-jian-wiki/customfishing/ge-shi/xiao-guo)
{% endcontent-ref %}

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

```yaml
delicate_hook:
  # 物品部分
  material: SHEARS
  display:
    name: '<#1E90FF>精致的鱼钩'
    lore:
      - ''
      - '<#7FFFD4>描述:'
      - '<gray> - 精心设计，具有吸引力，这个鱼钩'
      - '<gray> - 不是您普通的钓具。经过打磨精细设计'
      - '<gray> - 它在水中闪闪发光，不可抗拒地吸引着高质量'
      - '<gray> - 的鱼儿靠近。'
      - ''
      - '<#FFD700>效果:'
      - '<gray> - 增加获得高质量鱼儿的几率'
  max-durability: 16  <- 这个属性是鱼钩工作所必需的
  
  # 效果部分
  effects:
    group:
      type: group-mod
      value:
        - silver_star:+1
        - golden_star:+1
 
  # 鱼钩的唯一属性
  # 决定了鱼竿上的描述
  lore-on-rod:
    - ''
    - '<#7FFFAA>已装备的鱼钩:'
    - '<gray> - 精致的鱼钩: 剩余 <white>{dur}<white> 次'
```

## &#x20;     /util

{% content-ref url="/pages/dY9J9ZYPDP6CGbQYCIuv" %}
[✨ 效果](/customfishing/cha-jian-wiki/customfishing/ge-shi/xiao-guo)
{% endcontent-ref %}

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

```yaml
fishfinder:
  # 物品部分
  material: PAPER
  display:
    name: '<#1E90FF>鱼类探测器'
    lore:
      - ''
      - '<#7FFFD4>描述:'
      - '<gray> - 麻雀虽小五脏俱全，它可以精确扫描水下'
      - '<gray> - 的水域，揭示隐藏在水面下的各种'
      - '<gray> - 鱼类。无论您是在未知的领域还是'
      - '<gray> - 熟悉的水域，这个设备都能确保您'
      - '<gray> - 始终了解您的水下邻居。'
      - ''
  custom-model-data: 50000
```

## &#x20;     /rod

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

{% content-ref url="/pages/dY9J9ZYPDP6CGbQYCIuv" %}
[✨ 效果](/customfishing/cha-jian-wiki/customfishing/ge-shi/xiao-guo)
{% endcontent-ref %}

```yaml
beginner_rod:
  # 物品部分
  material: fishing_rod
  display:
    name: "<b><#EEE9E9>初学者的钓鱼竿"
    lore:
      - ''
      - '<#7FFFD4>描述:'
      - '<gray> - 专为初学者设计的钓鱼竿，初学者的'
      - '<gray> - 最佳伙伴。'
      - ''
      - '<#FFD700>效果:'
      - '<gray> - 增加钩子时间'
      - '<gray> - 减少钓鱼的挑战'
  custom-model-data: 50001
  max-durability: 64
  
  # 效果部分
  effects:
    time_effect:
      type: hook-time
      value: 1.8
    difficulty:
      type: difficulty
      value: -8
```

## &#x20;     /bait

{% content-ref url="/pages/dY9J9ZYPDP6CGbQYCIuv" %}
[✨ 效果](/customfishing/cha-jian-wiki/customfishing/ge-shi/xiao-guo)
{% endcontent-ref %}

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

```yaml
magnetic_bait:
  # 物品部分
  material: paper
  display:
    name: '<b><red>磁<blue>性<gray>鱼饵'
    lore:
      - ''
      - '<#7FFFD4>描述:'
      - '<gray>它的明亮光泽和独特的能量脉冲'
      - '<gray>对好奇的鱼类具有不可抗拒的吸引力，'
      - '<gray>以前所未有的速度将它们吸引过来。这不'
      - '<gray>仅是一种鱼饵，它是一场鱼类无法抗拒'
      - '<gray>的奇观。'
      - ''
      - '<#FFD700>效果:'
      - '<gray> - 减少钩子时间'
      - '<gray> - 增加钓鱼时间'
      - ''
  custom-model-data: 50002
  
  # 效果部分
  effects:
    hooktime:
      type: hook-time
      value: 0.9
    gametime:
      type: game-time
      value: 2
```

## &#x20;     /block

{% content-ref url="/pages/vRXfUFreSRgD3qFn7m65" %}
[🧊 方块](/customfishing/cha-jian-wiki/customfishing/ge-shi/fang-kuai)
{% endcontent-ref %}

{% content-ref url="/pages/x6s9CHdxd4MrNDrz6y3E" %}
[🏆 战利品](/customfishing/cha-jian-wiki/customfishing/ge-shi/zhan-li-pin)
{% endcontent-ref %}

```yaml
carrot_crate:
  # 战利品部分
  show-in-fishfinder: false
  disable-stat: true
  nick: 胡萝卜箱子
  
  # 方块部分
  block: barrel
  velocity:
    horizontal: 1.07
    vertical: 1.5
  properties:
    directional: true
    storage:
      carrot_1:
        item: Carrot
        amount: 1~2
        chance: 0.8
      carrot_2:
        item: Carrot
        amount: 1~2
        chance: 0.8
```

## &#x20;     /competition

{% content-ref url="/pages/arpAlpWlRwL68U0oOWln" %}
[🏅 比赛](/customfishing/cha-jian-wiki/customfishing/ge-shi/bi-sai)
{% endcontent-ref %}

## &#x20;     /totem

{% content-ref url="/pages/XbqbwWGYqJnFdX0JjbOn" %}
[🗿 图腾](/customfishing/cha-jian-wiki/customfishing/ge-shi/tu-teng)
{% endcontent-ref %}

## &#x20;     /minigame

{% content-ref url="/pages/EX43TNI5UCEkFA8Jce5h" %}
[🕹️ 迷你游戏](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi)
{% endcontent-ref %}


# ❓️ 常见问题

## 问题 1: 如何从其他插件导入物品

手持物品并执行命令 `/cfishing items import test_item` ，您将在 `CustomFishing/imported_items.yml` 中找到导出的物品，然后您可以将导出的数据复制并粘贴到所需的位置。

## 问题 2: 如何使用原版 1.20.5+ 自定义耐久度？

首先，删除插件提供的 `max-durability`，以避免冲突。然后使用组件部分将 `max_damage` 属性添加到物品中。您可以阅读此页面了解示例。

{% content-ref url="/pages/u91FP9jbjwBtvdEk3Tux" %}
[🎁 物品](/customfishing/cha-jian-wiki/customfishing/ge-shi/wu-pin)
{% endcontent-ref %}

## 问题 3: 如何使用其他插件中的物品/方块？

config.yml有一个这样的部分，让我们以物品为例

```yaml
# CustomFishing 支持使用其他插件的物品/方块
# 如果物品共享相同的 ID，它们将继承效果
item-detection-order:
  - CustomFishing
  - vanilla
block-detection-order:
  - vanilla
```

例如，如果您安装了 ItemsAdder，并且希望 CustomFishing 检查 ItemsAdder 的 ID，您可以将 ItemsAdder 添加到顺序中：

```yaml
item-detection-order:
  - ItemsAdder
  - CustomFishing
  - vanilla
```

然而，ItemsAdder 中的物品都有命名空间，因此为了确保 ID 对应，您需要修改 Custom Fishing 的鱼竿配置。

```yaml
namespace:beginner_rod:
  material: ItemsAdder:namespace:beginner_rod
  effects:
    effect_1:
      type: wait-time-multiplier
      value: 1.5
    effect_2:
      type: difficulty
      value: -8
```

如果您安装了 MMOItems，您可以这样配置（这里使用大写是因为 MMOItems 会将所有 ID 转换为大写）

```yaml
item-detection-order:
  - MMOItems
  - CustomFishing
  - vanilla
```

```yaml
BEGINNER_ROD:
  material: MMOItems:TOOL:BEGINNER_ROD
  effects:
    effect_1:
      type: wait-time-multiplier
      value: 1.5
    effect_2:
      type: difficulty
      value: -8
```

如果您安装了 Nexo，您可以这样配置

```yaml
item-detection-order:
  - Nexo
  - CustomFishing
  - vanilla
```

```yaml
beginner_rod:
  material: Nexo:beginner_rod
  effects:
    effect_1:
      type: wait-time-multiplier
      value: 1.5
    effect_2:
      type: difficulty
      value: -8
```

## 问题 4: 如何将我的等级插件与 CustomFishing 集成？

一些等级插件可能会提供技能修改钓鱼机制，在这方面，除非两个开发者合作，否则 Custom Fishing 无能为力。但在大多数情况下，只要这些插件提供相应的属性变量和技能等级变量，这些属性增益就可以应用于 Custom Fishing。您可以参考此页面了解一些示例。

{% content-ref url="/pages/zPj5RRRV3Qd5YoQ4ayGK" %}
[支持的等级系统](/customfishing/cha-jian-wiki/customfishing/jian-rong-xing/zhi-chi-de-deng-ji-xi-tong)
{% endcontent-ref %}

{% content-ref url="/pages/GG5RweHHPoWKYjnlH8GR" %}
[🅿️ 占位符和表达式](/customfishing/cha-jian-wiki/customfishing/zhan-wei-fu-he-biao-da-shi)
{% endcontent-ref %}

## 问题 5: 为什么我不能玩迷你游戏？

如果您安装了 MMOCore，那么您的钓鱼机制将如下面的图片所示。解决这个问题的方法是通过删除 YAML 配置文件来删除 MMOCore 提供的钓鱼职业。

<div align="left"><figure><img src="/files/CkZw4cvjBwSzhrYgrfHJ" alt="" width="375"><figcaption></figcaption></figure></div>

## 问题 6: 如何启用虚空钓鱼机制？

虚空钓鱼是由 CustomFishing API 注册的一种特殊机制。如果您对编码有一定了解，它允许您注册任何您想要的钓钩机制。 首先，在 loot-conditions.yml 中为虚空配置战利品，例如：

```yaml
global-group:
  list: []
  conditions: {}
  sub-groups:
    loots_in_void:
      conditions:
        in-void: true
        environment:
          - the_end
      list:
        - rubbish:+5
```

然后在您想要的地方创建一个允许虚空钓鱼的效果。在这种情况下，我在 config.yml 中使用 `global-effects`。

```yaml
mechanics:
  global-effects:
    void_fishing:
      type: void-fishing
```

现在您可以在虚空中钓鱼了！

<figure><img src="/files/lYguvKMrqyZ3kqujKe19" alt=""><figcaption><p>虚空钓鱼</p></figcaption></figure>

## 问题 7: 为什么 TOTAL\_SCORE 比赛无法进行？ <a href="#wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen" id="wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen"></a>

要使该功能正常运作，您需要为每条鱼设置得分。

[🏆 战利品](/customfishing/cha-jian-wiki/customfishing/ge-shi/zhan-li-pin) (查看本页的竞争得分部分)

## 问题 8: 如何使用 AureSkills 或 mcMMO 的钓鱼掉落表 <a href="#wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen" id="wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen"></a>

{% content-ref url="/pages/NY4W1yxUvotYDvi6D1Ho" %}
[mcMMO 宝藏](/customfishing/cha-jian-wiki/customfishing/jian-rong-xing/mcmmo-bao-zang)
{% endcontent-ref %}

{% content-ref url="/pages/eznMf2aR3p3tTDR45xYa" %}
[AuraSkills](/customfishing/cha-jian-wiki/customfishing/jian-rong-xing/auraskills)
{% endcontent-ref %}

### 问题 9: 如何解决与钩爪插件的兼容性问题 <a href="#wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen-1" id="wen-ti-1-ru-he-shi-yong-yuan-ban-geng-di-zuo-wei-zhong-zhi-pen-1"></a>

以 ExecuteableItems 为例，首先将其添加到 config.yml 中的 `item-detection-order` 配置项中，然后在 config.yml 中为其添加鱼竿黑名单要求。

```yaml
  item-detection-order:
    - ExecutableItems
    - CustomFishing
    - vanilla
```

```yaml
mechanics:
  mechanic-requirements:
    rod_requirement:
      type: "!rod"
      value:
        - YourGrapplingHook
```


# ⚖️ 权重系统 \[必读]

## 简介

整个插件的概率系统由权重控制。什么是权重？权重表示获得特定物品的相对机会。例如，如果物品 A 的权重为 10，物品 B 的权重为 30，则获得物品 A 的概率为 25%，而获得物品 B 的概率为 75%。这是计算概率的最科学方法。

## 哪些地方可以使用权重？

权重可以在哪些地方使用？实际上，权重应用于插件的许多部分。例如，根据战利品的条件调整权重，在迷你游戏中使用权重，以及提供权重修改功能的物品效果（如钓鱼竿）。它们通常以列表格式配置，并遵循这种特定的配置格式。

通过权重修改，我们可以实现许多其他钓鱼插件无法实现的功能。例如，海洋中垃圾较少，但在河流中频繁出现。使用金色钓鱼竿的玩家有更高的机会捕获金质战利品。或者，要捕获一条凶猛的鲨鱼，玩家必须使用鲨鱼饵料。所有这些功能都可以通过权重系统实现。

## 权重操作

权重操作包括 +（加法）、-（减法）、\*（乘法）、/（除法）、%（取模）和 =（自定义表达式）。

### 基本操作

我们先来看一些基本的权重操作表达式。\
对于操作符 `+`、`-`、`*`、`/` 和 `%`，只需在冒号后写上对应的操作符，然后在其后指定对应的值。这个值可以是一个已注册的占位符，也可以是一个固定的数字。

```
rubbish:+10
rubbish:-5.5
rubbish:/2
rubbish:%6
rubbish:*{placeholder}
```

### 自定义操作

对于 `=` 运算符，插件提供了更高级的表达式系统。

你可以自由使用插件提供的表达式。例如，这个简单的数学公式：

```yaml
rubbish:=100+sin(pi)
```

```yaml
内置函数:
    abs: 绝对值
    acos: 反余弦
    asin: 反正弦
    atan: 反正切
    cbrt: 立方根
    ceil: 向上取整
    cos: 余弦
    cosh: 双曲余弦
    exp: 自然对数的底 e 的幂次方 (e^x)
    floor: 向下取整
    log: 自然对数 (以 e 为底)
    log10: 对数 (以 10 为底)
    log2: 对数 (以 2 为底)
    sin: 正弦
    sinh: 双曲正弦
    sqrt: 平方根
    tan: 正切
    tanh: 双曲正切
    signum: 正负号函数
```

你还可以使用 `{0}` 表示在计算此表达式时当前条目的权重，或使用 `{1}` 表示在计算此表达式时所有条目权重的总和（不包括权重小于或等于 0 的条目）。

在此示例中，“垃圾”的权重将相对于其之前的值翻倍。

```
rubbish:={0}*2
```

在此示例中，“垃圾”的权重将变为所有战利品总权重的 1%。

```
rubbish:={1}*0.01
```

## 配置 loot-conditions.yml 和 game-conditions.yml 文件

一些用户打开这个文件后可能会感到非常困惑。Custom Fishing 使用了一种其他插件从未尝试过的配置文件格式。与其他钓鱼插件不同，Custom Fishing 提供了一个树状的概率池，可以根据条件自由调整权重。现在我们将带您了解默认的配置文件，以便理解这个系统的工作原理。

### 组

请注意：这里的“组”（group）与物品中的组没有任何关系。这个“组”只是一个随机名称，用于帮助用户组织文件结构。

首先，我们看到一个名为“global group”的部分。

```yaml
global-group:
  list: []
  conditions: {}
  sub-groups: {}
```

`global-group` 只是一个可以自由修改的随机名称，您可以随意添加任何您想要的组，例如：

```yaml
river-group:
  list: []
  conditions: {}
  sub-groups: {}
ocean-group:
  list: []
  conditions: {}
  sub-groups: {}
nether-group:
  list: []
  conditions: {}
  sub-groups: {}
the-end-group:
  list: []
  conditions: {}
  sub-groups: {}
```

通过仔细观察，您会发现一个组由三个部分组成：list、conditions 和 sub-groups。

### 添加条目到列表

如果您希望某个战利品出现，只需将其添加到列表中，使用 `=` 或 `+`。\
如果文件是 loot-conditions.yml，您可以添加来自 `item/entity/block` 文件夹中的任何战利品 ID。\
如果文件是 game-conditions.yml，您只能添加来自 `minigame` 文件夹中的游戏 ID。

```yaml
global-group:
  list:
    - my_fish:+1 # 将 my_fish 添加到战利品表中。
  conditions: {}
  sub-groups: {}
```

在这个奇怪的配置中，my\_fish 的最终权重是 ((0+6-4)\*10/5)%3=1。有趣的是，它的权重兜兜转转了一圈之后又回到了 1。

```yaml
global-group:
  list:
    - my_fish:=0   # 设定权重
    - my_fish:+6   # 加
    - my_fish:-4   # 减
    - my_fish:*10  # 乘
    - my_fish:/5   # 除
    - my_fish:%3   # 取模
  conditions: {}
  sub-groups: {}
```

### 条件

现在让我们继续看看条件部分。该部分影响列表中权重操作符是否执行。您可以使用条件系统提供的大多数条件。如果您仍然不知道什么是条件系统，请阅读

{% content-ref url="/spaces/n2ogeAAIntzmG4ra344J/pages/cU1Ng7sIlaYCtxhthNwz" %}
[✅ 条件](/customfishing/cha-jian-wiki/customfishing/tiao-jian)
{% endcontent-ref %}

例如，如果我现在希望这条鱼出现在我的自定义生物群系中，我可以这样配置

```yaml
global-group:
  list:
    - my_fish:+1
  conditions: 
    in-water: true
    biome:
      - my_namespace:my_custom_biome
  sub-groups: {}
```

非常好！您现在已经了解了条件系统的工作原理，我们接着来看子组是如何工作的。

在此示例中，我创建了两个子组，其中一个无法执行，因为它违反了一个重要原则：\
`子组的条件不能与父组的条件冲突`。\
如果玩家很可爱的，那么最终他只能得到 `cute_fish`，因为我将 `my_fish` 的权重设置为 0。

```yaml
global-group:
  list:
    - my_fish:+1
  conditions: 
    in-water: true
    biome:
      - my_namespace:my_custom_biome
  sub-groups:
    impossible_group:  # 这个组无法生效，因为在进入内部
      list:            # 子组部分之前，生物群系必须是
        - my_fish:+1   # my_namespace:my_custom_biome
      conditions:
        biome:
          - minecraft:plains 
    possible_group:
      list:
        - cute_fish:+1
        - my_fish:=0   
      conditions:
        equals:
          value1: '%cute_player%'  # 这只是一个虚构的占位符
          value2: 'true'
```

假设您有一个需求，无论战利品列表如何变化，获得箱子的概率始终应保持在约 2%。在这种情况下，您可以按以下方式配置：

```yaml
global-group:
  list: []
  conditions:  {}
  sub-groups: 
    fishs:
      list: 
       - a:+5
       - b:+7
       - c:+19
      conditions:  {}
      sub-groups: {}
    chest:
      list: 
       - chest:={1}*0.02
      conditions:  {}
      sub-groups: {}
```

请记住，`loot-conditions.yml` 是从上到下、从外到内解析的。因此，您需要将箱子条件放在文件的末尾。

这里的示例不够现实，因为玩家持有的渔具通常会影响之后其他物品的权重，这可能导致 2% 的概率失效。因此，您可以使用 `global-effects` 并对单个战利品项目应用权重调整，因为 `global-effects` 总是最后处理。

不过，这个示例提供了足够的思路，并且在某些场景下可能会派上用场。

### 调试战利品表

权重对我来说不太直观。我如何将权重转换为百分比形式？ 插件已经考虑到了这一点。您只需要使用命令 `/customfishing debug loot <`surroundings`>`。它将基于您当前持有的钓鱼竿、鱼饵和其他可能影响钓鱼结果的因素，计算所有潜在战利品的概率。

<figure><img src="/files/tpEWKKyTxe5oO0cOVxkx" alt=""><figcaption></figcaption></figure>

## 进阶教程

### 附加权重函数

除了基本的 `id:操作` 格式外，插件还提供了许多其他操作限定符。接下来，我将根据示例逐一解释每个功能。

#### **group\_for\_each** `group_for_each` 操作将对组内的每个成员应用权重操作。

```yaml
global-group:
  list:
    - group_for_each:river:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/VWXnI6ULyuU5LlMmeKRT" alt=""><figcaption></figcaption></figure>

除了使用单个组（如 `river`）外，您还可以组合多个组。例如，`river&silver_star` 表示同时属于 `river` 和 `silver_star` 组的战利品。类似地，`river|ocean` 表示属于 `river` 或 `ocean` 组的战利品。

```yaml
global-group:
  list:
    - 'group_for_each:river&silver_star:+10'
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/sRfzjS690T65PeONW09U" alt=""><figcaption></figcaption></figure>

#### group\_available\_for\_each

与 `group_for_each` 不同，`group_available_for_each` 影响的对象必须已经在之前出现过。

```yaml
global-group:
  list:
    - gold_fish:=10
    - group_available_for_each:river:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/ce9HxfCyZBH5jKQIZzTU" alt=""><figcaption></figcaption></figure>

#### group\_total

`group_total` 操作将把权重均匀分配给组内的每个成员，以确保组的总权重保持一致。

```yaml
global-group:
  list:
    - group_total:ocean:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/bz6lR4PXyMIIJtajQAsR" alt=""><figcaption></figcaption></figure>

```yaml
global-group:
  list:
    - 'group_total:ocean&golden_star:+10'
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/uzjW5l9jYneQclr9A6Ha" alt=""><figcaption></figcaption></figure>

#### group\_available\_total

`group_available_total` 与 `group_total` 的区别在于，`group_available_total` 仅影响之前已出现过的条目。

由于 2.x 架构的限制以及性能方面的考虑，插件不会动态追踪或计算已出现的条目。这可能导致在使用 `group_available_total` 时出现总权重不一致的问题。该问题将在 3.0 重构版本中得到解决。

```yaml
global-group:
  list:
    - tuna_fish:+10
    - group_available_total:ocean:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/WtenEPyRhMVrZl93Kb3m" alt=""><figcaption></figcaption></figure>

#### loot\_available

与常规的权重操作不同，这个操作只针对那些已经在之前出现过的条目。

```yaml
global-group:
  list:
    - tuna_fish:+10
    - loot_available:tuna_fish:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/Sq6GozIOenn4YzOjxp0p" alt=""><figcaption></figcaption></figure>

```yaml
global-group:
  list:
    - gold_fish:+10
    - loot_available:tuna_fish:+10
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/x75Pc3eFeVirkDptJpsJ" alt=""><figcaption></figcaption></figure>

### 附加占位符

在 `=` 表达式中，您可以使用 `{entry_xxx}` 来获取之前出现的特定条目的权重，并使用 `{group_xxx}` 来获取所有符合组条件的条目权重的总和。

在此示例中，我首先为所有河流鱼类添加了 +10 的权重，然后将所有河流鱼类的总权重平均分配给所有海洋鱼类。

```yaml
global-group:
  list:
    - group_for_each:ocean:+10
    - group_total:river:={group_ocean}
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/zSBDeFqTqMLJj646vTul" alt=""><figcaption></figcaption></figure>

在此示例中，我将 `golden_star` 和 `silver_star` 的权重分别设置为没有星级状态时的 10% 和 30%。

```yaml
global-group:
  list:
    - tuna_fish:+10
    - 'tuna_fish_silver_star:={entry_tuna_fish}*0.3'
    - 'tuna_fish_golden_star:={entry_tuna_fish}*0.1'
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/9MrEPTcwLQiEHkLbyqg4" alt=""><figcaption></figcaption></figure>

对于组，您还可以使用前面提到的 `&` 和 `|` 操作符。`&` 操作符表示组的交集（属于两个组的物品），而 `|` 操作符表示组的并集（属于任意一个组的物品）。

```yaml
global-group:
  list:
    - group_for_each:ocean:+10
    - 'rainbow_fish:={group_ocean&silver_star}*0.3'
  conditions:  {}
  sub-groups: {}
```

<figure><img src="/files/cMXuB2H1FBUqiTcHOULV" alt=""><figcaption></figcaption></figure>


# 📄 格式


# 🛒 市场

**启用功能:**

* `enable: true`\
  这个选项用于启用或禁用整个功能。

```yaml
enable: true
```

**容器标题:**

* `title: '<gradient:#A52A2A:#800000:#A52A2A>鱼市</gradient>'`\
  这指定了容器的标题。标题 "鱼市" 会以三种给定的十六进制颜色代码渐变显示。

```yaml
title: '<gradient:#A52A2A:#800000:#A52A2A>鱼市</gradient>'
```

**限制:**

* `limitation:`\
  这部分定义了与从鱼市赚取的收入相关的限制。
  * `enable: true` 表示启用了限制功能。
  * `earnings: 10000` 指定了收入上限为 10,000 个单位的钱。

```yaml
limitation:
  enable: true
  earnings: 10000
  # 支持表达式和占位符
  earnings: '1000 + 50 * {level}'
```

**市场菜单布局:**

* `layout:`\
  布局部分确定市场菜单中物品/图标的视觉排列方式。符号 'A'、'I' 和 'B' 分别代表特定的物品或图标。

```yaml
layout:
  - 'AAAAAAAAA'
  - 'AIIIIIIIA'
  - 'AIIIIIIIA'
  - 'AIIIIIIIA'
  - 'AAAABAAAA'
```

**价格公式:**

* `price-formula: '{base} + {bonus} * {size}'`\
  这提供了一个公式，用于计算“CustomFishing”中战利品的价格。

```yaml
price-formula: '{base} + {bonus} * {size}'
```

**物品价格:**

* `item-price:`\
  这一部分为物品分配了固定的价格。例如，“COD”定价为 10 单位。另外，具有 `CustomModelData` 的物品如 "PAPER"，其数据为 "999"，定价为 5 单位。

```yaml
item-price:
  COD: 10
  PUFFERFISH: 10
  SALMON: 10
  TROPICAL_FISH: 10
  PAPER:999: 5
```

**物品槽位:**

* `item-slot:`\
  指定了放置要出售物品的槽位。如果 `allow-items-with-no-price` 设置为 true，则即使物品没有指定价格，也可以放置在槽位上。

```yaml
item-slot:
  symbol: 'I'
  allow-items-with-no-price: true
```

**动态图标: (sell-icons / sell-all-icons)** 这一部分管理交互式图标。这些图标具有多种功能：

* `allow-icon`: 表示允许的交易。
* `deny-icon`: 表示因缺少要出售的物品而被拒绝的交易。
* `limit-icon`: 当物品价值超过当天可赚取金额时出现。每个图标都进一步配置了显示设置和触发动作，如声音、消息或命令。

```yaml
sell-icons:
  symbol: 'B'
  allow-icon:
    material: IRON_BLOCK
    display:
      name: '<#00CED1><b>● <!b>出售鱼类'
      lore:
        - '<font:uniform><gradient:#E6E6FA:#48D1CC:#E6E6FA>您将赚取 <green>{money}$</green> 的鱼类销售收入</gradient></font>'
        - '<dark_gray>您可以赚取 {rest}'
    action:
      sound_action:
        type: sound
        value:
          key: 'minecraft:block.amethyst_block.place'
          source: 'player'
          volume: 1
          pitch: 1
      message_action:
        type: message
        value: '您通过出售鱼类赚取了 {money}$！您今天还可以从市场赚取 {rest}$'
      command_action:
        type: command
        value: 'money give {player} {money}'
  deny-icon:
    material: REDSTONE_BLOCK
    display:
      name: '<red><b>● <!b>交易被拒绝'
      lore:
        - '<font:uniform><gradient:#E6E6FA:red:#E6E6FA>没有要出售的物品！</gradient></font>'
    action:
      sound_action:
        type: sound
        value:
          key: 'minecraft:entity.villager.no'
          source: 'player'
          volume: 1
          pitch: 1
  limit-icon:
    material: REDSTONE_BLOCK
    display:
      name: '<red><b>● <!b>交易被拒绝'
      lore:
        - '<font:uniform><gradient:#E6E6FA:red:#E6E6FA>物品价值超过了今天剩余可赚取的金额！</gradient></font>'
    action:
      sound_action:
        type: sound
        value:
          key: 'minecraft:block.anvil.land'
          source: 'player'
          volume: 1
          pitch: 1
```

**装饰性图标:**

* `decorative-icons:`\
  这些图标纯粹是为了好看。它们不具有功能属性。在这种情况下，一个 `glass-pane` 被赋予符号 'A'，材质为 `BLACK_STAINED_GLASS_PANE`。

```yaml
decorative-icons:
  glass-pane:
    symbol: 'A'
    material: BLACK_STAINED_GLASS_PANE
    display:
      name: ' '
```


# ✨ 效果

## 介绍

钓鱼效果是一种临时增益，为玩家的单次钓鱼尝试提供加成。这种加成可以来自钓鱼竿、鱼饵，甚至是附魔和图腾！钓鱼效果遵循特定的配置格式。以下是所有效果的设置方式。

所有效果都遵循以下格式：

```yaml
star_fishing_rod:
  requirements: # 使用此物品的要求
    ...
  effects: 
    effect_0: # 效果名称可以自定义
      type: weight-mod
      # 参数
      value:
      - rubbish:-10
      - golden_star_fish:+10
      # 需执行的其他动作（可选）
      actions:
        action_1:
          type: xxx
          value: xxx
```

## 鱼饵

要使用鱼饵，需要将其放在副手或者钓鱼袋中。每次投掷钓竿时，鱼钩都会与钩子一起抛出。

## 钩子

要在钓竿上装备钩子，请确保你处于生存模式。将钩子拖动到你的钓竿上即可应用。要从钓竿上取下钩子，只需右键单击钓竿，钩子就会出现在你的鼠标上。

<figure><img src="/files/WNusFoQBQ5SbO7xRJOnZ" alt=""><figcaption><p>鱼钩和鱼饵</p></figcaption></figure>

## 效果库

> weight-mod（weight-mod 提供了一种调整单个战利品权重或几率的方式，可以快速改变获得特定物品的概率。如果没有可用的战利品，效果将不会生效。）

```yaml
xxx_effect:
  type: weight-mod
  value:
  - rubbish:-10
  - golden_star_fish:+10
```

> weight-mod-ignore-conditions（区别在于，即使没有这样的战利品可用，效果仍然会生效。）

```yaml
xxx_effect:
  type: weight-mod-ignore-conditions
  value:
  - enchantmentbook:+1
```

> group-mod（与 weight-mod 不同，group-mod 允许同时修改多个战利品的权重。当然，一个物品可以属于多个组，例如“金质”组和“海洋”组。有关如何将战利品分配给组的指导，请参考战利品系统。）

```yaml
xxx_effect:
  type: group-mod
  value:
  - gold:+20
  - normal:-6
xxx_effect:
  type: group-mod
  value:
  - gold:+20
  - normal:-6
```

> weight-group-ignore-conditions

```yaml
xxx_effect:
  type: group-mod-ignore-conditions
  value:
  - enchantment:+10  
```

> wait-time（调整鱼儿上钩的等待时间）

```yaml
xxx_effect:
  type: wait-time
  value: -20          <- 减少 20 个刻
```

> wait-time-multiplier（调整鱼儿上钩的等待时间）\
> ~~（在旧版本中也称为“hook-time”）~~

```yaml
xxx_effect:
  type: wait-time-multiplier
  value: 0.8          <- "大于1"使时间更长；"<1"相反
                      <- 减少 20% 等待时间
```

> difficulty（调整游戏难度）

```yaml
xxx_effect:
  type: difficulty
  value: -17         <- 减少 17 难度
```

> difficulty-multiplier（调整游戏难度）

```yaml
xxx_effect:
  type: difficulty-multiplier
  value: 0.7         <- 减少 30% 难度
```

> multiple-loot（玩家可以在一次钓鱼尝试中获得多个物品。每 0.01 代表 1% 的机会。如果值超过 1，玩家保证可以获得双倍物品，但有小概率获得三倍。如果值超过 2，他们保证可以获得三倍物品，但有小概率获得四倍。）

```yaml
xxx_effect:
  type: multiple-loot
  value: 0.05
```

> lava-fishing（允许玩家在岩浆中钓鱼）

```yaml
xxx_effect:
  type: lava-fishing
```

> size（size 为战利品提供大小加成，最终战利品的大小增加了这个值。此选项影响在鱼的大小决定分数的比赛中的得分。）

```yaml
xxx_effect:
  type: size
  value: 10.5      <- 增加 10.5 鱼的大小
```

> size-multiplier（size-bonus 为战利品提供大小加成，最终战利品的大小将乘以此值。此选项影响在鱼的大小决定分数的比赛中的得分。）
>
> ~~（在旧版本中也称为“size-bonus”）~~

```yaml
xxx_effect:
  type: size-multiplier
  value: 1.3         <- 增加 30% 鱼的大小
```

> score（score 在比赛中提供得分加成，最终战利品的得分增加了这个值。注意：这仅在 TOTAL\_SCORE 模式下起作用。）

```yaml
xxx_effect:
  type: score
  value: 20         <- 增加 20 得分
```

> score-multiplier（score-bonus 在比赛中提供得分加成，最终战利品的得分将乘以此值。注意：这仅在 TOTAL\_SCORE 模式下起作用。）\
> ~~（在旧版本中也称为“score-bonus”）~~

```yaml
xxx_effect:
  type: score-multiplier
  value: 1.5        <- 增加 50% 得分
```

> game-time（game-time 允许调整小游戏的持续时间，使玩家有更多的时间做出反应并获得更多成功的机会。）

```yaml
xxx_effect:
  type: game-time
  value: 10           <- 增加 10 秒
```

> game-time-multiplier（game-time 允许调整小游戏的持续时间，使玩家有更多的时间做出反应并获得更多成功的机会。）

```yaml
xxx_effect:
  type: game-time-multiplier
  value: 1.3          <- 增加 30% 秒
```

> conditional （将条件系统应用于某些效果）

```yaml
xxx_effect:
  type: conditional
  conditions:
    ...
  effects:
    ...
```

## 全局效果 <a href="#global-effects" id="global-effects"></a>

全局效果位于 config.yml。它允许您为玩家创建全局效果。这是默认配置，可在比赛进行时加快钓鱼速度。

```yaml
mechanics:
  global-effects:
    effect_1:
      type: conditional
      conditions:
        competition:
          ongoing: true
          id:
            - weekend_competition
      effects:
        effect_1:
          type: wait-time-multiplier
          value: 0.85
```


# 🎉 事件

## 介绍

事件是触发动作的先决条件。本文将详细介绍所有可以应用事件的配置区域。\
这是一个简单的示例，玩家在成功钓鱼后会获得经验球

```yaml
#contents/item/default.yml
tuna_fish:
  events:
    success:  # 触发器
      action_mending:  # 动作
        type: mending
        value: 5
        chance: 1.0
```

所有可用的动作类型都可以在这里找到

{% content-ref url="/pages/lEtyEYYh1czo6Vtd5Hy2" %}
[💪 动作](/customfishing/cha-jian-wiki/customfishing/dong-zuo)
{% endcontent-ref %}

以下是适用于不同机制的可用触发器

## 战利品

```yaml
events:
  success:   <- 成功捕获战利品
   ...
  failure:   <- 捕获战利品失败
   ...
  hook:      <- 鱼儿被钓住（需要收杆）
   ...
  success-times:
    1:       <- 成功捕获战利品的次数
     ...
    2:
     ...
    999:
     ...
  consume:   <- 被玩家吃掉
    ...
  bite:      <- 鱼儿试图吞食鱼钩
    ...
  new_size_record:   <- 捕获的鱼的大小超过了个人记录
    ... 
  interact:   <- 与手中物品交互
    ...
```

## 鱼竿

```yaml
events:
  success:   <- 成功捕获战利品
   ...
  failure:   <- 捕获战利品失败
   ...
  hook:      <- 鱼儿被钓住
   ...
  cast:      <- 抛出鱼竿
    ...
  land:      <- 鱼钩落入水中
    ...
  bite:      <- 鱼儿试图吞食鱼钩
    ...
  escape:    <- 鱼儿逃脱
    ...
  reel:      <- 收回鱼竿
    ...
```

## 鱼饵

```yaml
events:
  success:   <- 成功捕获战利品
    ... 
  failure:   <- 捕获战利品失败
   ...
  cast:      <- 抛出鱼竿
    ...
  land:      <- 鱼钩落入水中
    ...
  hook:      <- 鱼儿被钓住
    ...
  bite:      <- 鱼儿试图吞食鱼钩
    ...
  interact:  <- 与手中物品交互
    ...
  escape:    <- 鱼儿逃脱
    ...
  reel:      <- 收回鱼竿
    ...
```

## 工具

```yaml
events:
  land:      <- 鱼钩落入水中
    ...
  cast:      <- 抛出鱼竿
    ...
  success:   <- 成功捕获战利品
    ... 
  failure:   <- 捕获战利品失败
   ...
  interact:  <- 使用手中物品
    ...
  escape:    <- 鱼儿逃脱
    ...     
  reel:      <- 收回鱼竿
    ...  
  hook:      <- 鱼儿被钓住（需要收竿）
    ...
```

## 图腾

```yaml
events:
  activate:   <- 激活图腾
    ...
  timer:      <- 定时器动作
    ...
  end:        <- 时间结束
    ...
```


# ✏️ 文本

文本的格式

该插件采用 `MiniMessage` (<https://docs.advntr.dev/minimessage/format.html>) 格式来表示文本。该系统提供了丰富而灵活的文本格式化方式，包括颜色、样式和其他特性。不过，如果您更习惯或需要旧的颜色格式（使用 '&' 符号），插件仍然支持。

#### 旧版颜色代码支持:

以下是在 `config.yml` 中的设置示例：

要启用对旧版颜色格式的支持：

```yaml
other-settings:
  legacy-color-code-support: true
```


# 🎁 物品

物品的格式

## 介绍

物品配置格式是一个标准化的系统。考虑到其多功能性，该格式可在需要物品的任何上下文中使用。该格式的常见应用包括钓鱼战利品、钓鱼竿、钓鱼饵料，甚至市场GUI中也可以使用。

配置中的物品结构是围绕键值展开的。每个键值包含一组参数，这些参数确定了物品的特性和行为。给出的示例"common\_bait"说明了一个典型物品的结构。

```yaml
common_bait:
  material: paper
  display:
    name: '<b><#00BFFF>普通鱼饵'
    lore:
      - ''
      - '<#7FFFD4>描述：'
      - '<gray>由天然成分制成，以稳定而平静的方式吸引'
      - '<gray>鱼类。对于那些喜欢简单可靠的钓鱼体验'
      - '<gray>的人来说，这是首选。'
      - ''
      - '<#FFD700>效果：'
      - '<gray> - 减少钓鱼难度'
      - ''
  custom-model-data: 50001
```

**键值:**

物品的标识符。在提供的示例中，键值是"common\_bait"。

**材质: (1.17-最新)**

定义物品的基本材料或类型。对于"common\_bait"，材质设置为"paper"。

* **示例** :

  ```yaml
  material: paper
  ```

**展示: (1.17-最新)**

此部分提供物品的视觉和描述方面的信息。

* **名称：** 确定物品的显示名称。在这种情况下，名称为"普通鱼饵"，并使用颜色代码和文本格式设置样式。
  * 示例：
  * ```yaml
    display:
      name: '<b><#00BFFF>普通鱼饵'
    ```
  *

<figure><img src="/files/4QR7XVvkRPdWn5LL6WV9" alt=""><figcaption></figcaption></figure>

* **描述：** 这是一系列描述性文本行，提供有关物品的更多信息。每行都可以像名称一样进行格式化和着色。
  * **示例：**
  * ```yaml
    display:
      lore:
        - ''
        - '<#7FFFD4>描述：'
        - '<gray>由天然成分制成...'
        - '...'
    ```
  *

<figure><img src="/files/L71vbER5DnDaqGL0SRAK" alt=""><figcaption></figcaption></figure>

**自定义模型数据: (1.17-最新)**

此参数用于为物品分配唯一的模型数据。当开发人员希望在游戏中提供自定义物品纹理或模型时，这可能特别有用。

* **示例** :

  ```yaml
  custom-model-data: 50001
  ```

**数量: (1.17-最新)**

正在定义的物品的数量。

* **示例** :

  ```yaml
  amount: 1
  ```

**标签: (1.17-最新)**

允许向物品添加 Custom Fishing 标签。这个标签对于插件识别 CustomFishing 中的物品非常重要。禁用此功能可能会导致一些问题。

<figure><img src="/files/hu2wMlADoUrzcTG6ZMii" alt=""><figcaption></figcaption></figure>

* **示例** :

  ```yaml
  tag: false
  ```

**无法破坏: (1.17-最新)**

指定物品是否无法破坏。

* **示例** :

  ```yaml
  unbreakable: false
  ```

**物品标志: (1.17-1.20.4)**

列出了修改物品外观或行为的特定标志。 <https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/ItemFlag.html>

* 示例:

  ```yaml
  item-flags:
     - HIDE_DYE
  ```

**最大耐久度: (1.17-最新)**

设置物品的自定义耐久度。此选项会将物品变为自定义耐久物品。如果你倾向于使用在1.20.5中引入的新自定义耐久度系统，请查看下面的组件部分。

* 示例:

  ```yaml
  max-durability: 100
  ```

**随机耐久度: (1.17-最新)**

决定物品在获得时是否会随机设置耐久度。这适用于原版耐久度和插件的自定义耐久度。

* 示例:

  ```yaml
  random-durability: false
  ```

**NBT: (1.17-最新)**

允许使用二进制命名标签进行进一步自定义。 如果未指定标签值类型，则在极少数情况下可能会引发错误。

<figure><img src="/files/FbwuR4cwmIDr02kg0lA4" alt=""><figcaption></figcaption></figure>

您可以手动添加类型来修复它，例如：

```yaml
minecraft:custom_name: '(String) {"color":"white","italic":false,"text":"鱼骨"}'
```

可用值类型： (Int) (Byte) (String) (Float) (String) (Double) (Short) (Long) (UUID) (Boolean) (IntArray) (ByteArray)

* **示例** :
* ```yaml
  nbt:
    int_value: 10
    double_value: 1.0
    byte_array: (ByteArray) [0, 1, 2]
    expression: (Int) 1 + 2 * 3 + 4
  ```
* ```yaml
  nbt:
    itemsadder:
      namespace: '(String) momirealms'
      id: 'rainbow_fish'
  ```
* ```yaml
  nbt:
    PublicBukkitValues:
      oraxen:id: alchemist
  ```

**组件: (1.20.5-最新)**

这是自2.2.0以来插件最令人震惊的更新之一。这个部分允许你使用Minecraft提供的任何组件类型。以下是一些示例，帮助你了解如何在CustomFishing配置中设置组件。\
[https://zh.minecraft.wiki/w/物品格式](https://zh.minecraft.wiki/w/%E7%89%A9%E5%93%81%E6%A0%BC%E5%BC%8F)

* 示例1：

<figure><img src="/files/SdIaE8LOr1LwXzxSHwjg" alt=""><figcaption><p>我的世界WIKI</p></figcaption></figure>

```yaml
components:
  minecraft:food:
    nutrition: 4
    saturation: 1.5
    can_always_eat: true
    eat_seconds: 3
    effects:
      - effect: 
          id: minecraft:luck
          amplifier: 0
          duration: 30
        probability: 0.5
```

* 示例2：

<figure><img src="/files/fn0QOaJ6rwzdsO5Qs3Md" alt=""><figcaption><p>我的世界WIKI</p></figcaption></figure>

```yaml
components:
  minecraft:tool:
    rules:
      - blocks: "#minecraft:mineable/axe"
        speed: 300.0
        correct_for_drops: true
```

* **示例 3**：（1.20.5 中引入的官方自定义耐久度系统）

<figure><img src="/files/79VAudZm4RKACOHXWoM1" alt=""><figcaption><p>我的世界WIKI</p></figcaption></figure>

```yaml
components:
  minecraft:max_damage: 100
```

**价格: (1.17-最新)**

* **Description** ：确定物品的价格。
  * **Base** ：物品的初始价格。
  * **Bonus** ：基于大小应用的乘数。
* **示例** ：

  ```yaml
  price:
    base: 50
    bonus: 2.5
  ```

**可堆叠: (1.17-最新)**

指示物品是否可以与相似物品堆叠。

* **示例** :

  ```yaml
  stackable: true
  ```

**防止拾取: (1.17-最新)**

如果设置为true，则其他玩家无法拾取物品。

* **示例** :

  ```yaml
  prevent-grabbing: true
  ```

**可放置: (1.17-最新)**

允许放置物品（玩家头颅）

* 示例 :

  ```yaml
  placeable: true
  ```

**头颅: (1.17-最新)**

指向一个Base64编码的字符串，通常用于自定义玩家头部纹理。 <https://minecraft-heads.com/custom-heads/>

* **示例** :

  ```yaml
  head64: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ1Nzk4NzA1Yjc1YjUzY2VmNzExNjE5OGFiNWQzOGNjZGY5YjM2ODYxNzg0MjdmYjcxMDg5NmI1MjMwZDQ2MyJ9fX0=
  ```

**(存储的) 附魔: (1.17-最新)**

详细说明直接应用于物品的附魔。

* **示例** :

  ```yaml
  enchantments:                 <- 用于装备
    minecraft:sharpness: 1

  stored-enchantments:          <- 用于附魔书
    minecraft:sharpness: 1
  ```

**随机的（存储的）附魔: (1.17-最新)**

列举了在物品获得时可能随机应用的可能附魔。每个潜在的附魔都与一个等级和一个应用几率相关联。

* **示例** :

  ```yaml
  random-enchantments:
    lv3:
      enchant: minecraft:unbreaking
      level: 3
      chance: 0.2
    lv2:
      enchant: minecraft:unbreaking
      level: 2
      chance: 0.5
    lv1:
      enchant: minecraft:unbreaking
      level: 1
      chance: 1
  random-stored-enchantments:
    ...
  ```

**(存储的) 附魔池: (1.17-最新)**

附魔池提供了控制一个物品上附魔数量的能力，而不是通过概率尝试应用每个配置的附魔。插件不会允许冲突的附魔同时存在，并且EcoEnchants完全兼容。

```yaml
enchantment-pool:
  # 物品上的最大附魔数
  amount:
    1: 6
    2: 3
    3: 1
  pool:
    'minecraft:unbreaking:1': 6
    'minecraft:unbreaking:2': 3
    'minecraft:unbreaking:3': 1
    'minecraft:sharpness:1': 6
    'minecraft:sharpness:2': 3
    'minecraft:sharpness:3': 1
    'minecraft:efficiency:1': 12
    'minecraft:efficiency:2': 6
    'minecraft:efficiency:3': 2
```

从示例中，我们可以推断出玩家有60%的几率获得1个附魔，30%的几率获得2个，10%的几率获得3个。

| 数量 | 权重 | 几率  |
| -- | -- | --- |
| 1  | 6  | 60% |
| 2  | 3  | 30% |
| 3  | 1  | 10% |

现在假设玩家可以获得2个附魔。

**第一个附魔**

| 附魔 | 等级 | 权重 | 几率   |
| -- | -- | -- | ---- |
| 耐久 | 3  | 1  | 2.5% |
| 耐久 | 2  | 3  | 7.5% |
| 耐久 | 1  | 6  | 15%  |
| 锋利 | 3  | 1  | 2.5% |
| 锋利 | 2  | 3  | 7.5% |
| 锋利 | 1  | 6  | 15%  |
| 效率 | 3  | 2  | 5%   |
| 效率 | 2  | 6  | 15%  |
| 效率 | 1  | 12 | 30%  |

**第二个附魔（假设第一个附魔是锋利）**

| 附魔     | 等级    | 权重    | 几率     |
| ------ | ----- | ----- | ------ |
| 耐久     | 3     | 1     | 3.33%  |
| 耐久     | 2     | 3     | 10%    |
| 耐久     | 1     | 6     | 20%    |
| ~~锋利~~ | ~~3~~ | ~~1~~ | ~~0%~~ |
| ~~锋利~~ | ~~2~~ | ~~3~~ | ~~0%~~ |
| ~~锋利~~ | ~~1~~ | ~~6~~ | ~~0%~~ |
| 效率     | 3     | 2     | 6.67%  |
| 效率     | 2     | 6     | 20%    |
| 效率     | 1     | 12    | 40%    |


# 🦖 实体

实体的格式

生物实体的配置非常简单。它只需要一个ID和一个速度设置。根据你使用的实体，一些插件允许使用属性。

{% content-ref url="/pages/yMVF3zrKN25wAqD6dizH" %}
[ItemsAdder](/customfishing/cha-jian-wiki/customfishing/jian-rong-xing/itemsadder)
{% endcontent-ref %}

{% content-ref url="/pages/VdOJlEdB2PBDtU2oshBf" %}
[MythicMobs](/customfishing/cha-jian-wiki/customfishing/jian-rong-xing/mythicmobs)
{% endcontent-ref %}

```yaml
skeleton:
  entity: skeleton
  velocity:
    horizontal: 1
    vertical: 1.3
  properties: {}
```

**实体ID：** 每个实体的唯一标识符。这确保了游戏或插件能够识别和区分各种实体。

**速度：** 这指的是实体从水面出来时的运动速度。

**属性：** 这些是额外的设置，可以定义实体的行为、外观或其他特性。可用的属性可以根据实体类型和使用的特定插件而变化。


# 🧊 方块

方块的格式

钓鱼插件引入了一个独特的功能，使玩家可以钓取方块！这不仅限于原版方块或默认的钓鱼战利品。该插件与其他插件无缝集成，允许用户设置自定义方块。这一功能的亮点之一是可以钓到装满随机物品的箱子，使每次捕获都可能是一个惊喜！

```yaml
apple_crate:
  block: barrel
  velocity:
    horizontal: 1.07
    vertical: 1.5
  properties:
    directional: true
    storage:
      apple_1:
        item: APPLE
        amount: 1~2
        chance: 0.8
      apple_2:
        item: APPLE
        amount: 1~2
        chance: 0.8
```

**方块类型:** 定义方块的类型。在这种情况下，它是一个木桶。

**速度:** 这指的是方块从水面出来时的运动速度。

**属性:** 配置方块的行为和特性。

**可用属性:**

```yaml
directional-4: true

directional-6: true

moisture: 4

campfire: true

rotatable: true

noteblock:
  instrument: PIANO
  note: 7

age: 4

turtle-eggs: 3

storage:
  apple_1:
    # 提示：要使用自定义钓鱼物品，只需输入"CustomFishing:type:id"
    item: APPLE
    amount: 1~2
    chance: 0.8
```


# 🏆 战利品

战利品配置与物品/方块/实体配置密切相关。这种整合对于确保物品/方块/实体被正确注册为战利品并且可以在条件系统中调用是至关重要的。

**战利品的唯一键名:**

每个战利品都应该有一个唯一的键名。任何两个战利品项目都不能有相同的键名，以防止任何潜在的冲突。

**与其他配置的整合:**

要将物品/方块/实体注册为战利品，必须将其与相应的配置结合起来。这确保了系统识别战利品及其关联属性。

**条件系统的调用:**

一旦注册，就可以在条件系统中调用战利品。这允许更复杂的游戏机制，例如在特定条件或场景下生成特定的战利品。

**别名:**

决定战利品在鱼群探测器中显示的样子和{nick}的返回值。每个战利品都应该有一个别名，但大多数情况下你不必手动设置它。如果战利品是物品类型，如果未设置别名，则别名将使用“display.name”，否则别名将是战利品ID。

* **例子**：

  ```yaml
  nick: "<gold>这是一个别名</gold>"
  ```

**在鱼群探测器中显示:**

确定在使用鱼群探测器工具时，战利品是否可见或可检测。

* **例子**：

  ```yaml
  show-in-fishfinder: true
  ```

**禁用统计信息:**

如果启用，将不会跟踪或显示与此特定战利品相关的统计信息。

* **例子**：

  ```yaml
  disable-stat: true
  ```

**禁用全局事件:**

如果启用，则在 config.yml 中配置的那些事件将不再对此战利品产生影响。

* **例子**：

  ```yaml
  disable-global-event: true
  ```

**禁用迷你游戏:**

指示是否禁用与此战利品相关的迷你游戏。一些物品可能太不值钱，因此最好跳过迷你游戏阶段。

* **例子**：

  ```yaml
  disable-game: true
  ```

**立即开始迷你游戏:**

如果设置为 true，在遇到战利品时，相关的迷你游戏将立即开始，不会有任何延迟。

* **例子**：

  ```yaml
  instant-game: true
  ```

**防止抢夺:**

防止玩家抢夺掉落的战利品

* **例子**：

  ```yaml
  prevent-grabbing: true
  ```

**放入背包:**

直接将战利品添加到玩家的背包中

* **例子**：

  ```yaml
  to-inventory: true
  ```

**竞争得分:**

表示在竞赛中使用时的战利品分数或价值。

* **例子**：

  ```yaml
  score: 10.5
  ```

**战利品组:**

战利品的组，使其更容易修改权重。如果你不知道权重是什么，请阅读下面的文章

{% content-ref url="/pages/rJYbUhnsOXXc0j1Rn23Y" %}
[⚖️ 权重系统 \[必读\]](/customfishing/cha-jian-wiki/customfishing/quan-zhong-xi-tong-bi-du)
{% endcontent-ref %}

* **例子**：

  ```yaml
  group: golden_star

  group:
    - golden_star
    - ocean
  ```

**统计信息键:**

如果你希望不同的战利品共享相同的统计信息，你可以将统计信息键添加到战利品中。例如，你有“金枪鱼”、“银星金枪鱼”和“金星金枪鱼”，如果你希望 %fishingstats\_size-record\_tuna% 返回三者的最大尺寸，你可以将以下部分添加到三个战利品中：

```yaml
statistics:
  # 捕获的鱼的数量
  amount: tuna
  # 最佳尺寸记录
  size: tuna
```

**基础效果：**

设置战利品的初始效果。

```yaml
base-effects:
  difficulty-adder: 10
  difficulty-multiplier: 0.9
  game-time-adder: 10
  game-time-multiplier: 0.9
  wait-time-adder: 10
  wait-time-multiplier: 0.9
```

**自定义数据: （2.2.20及以上）**

自定义数据允许您为战利品自定义一些特殊数据，并使用内部占位符 {data\_xxx} 进行使用，例如 {data\_max\_weight}。这使您可以做很多很酷的事情，例如为物品创建重量属性。以下是一个示例：

```yaml
#contents/item/default.yml

test:
  material: cod
  display:
    name: "一条有重量的鱼！"
    lore:
      - "重量: {data_weight}千克"
  nbt:
    Weight: "(Double) {data_weight}"
  price:
    base: 50
  custom-data:
    max_weight: 10
    min_weight: 5
    weight: "{weight}"
    some_text: "ABC"
```

```yaml
#config.yml

placeholder-register:
  '{weight}': "%math_2:_{random}*({data_max_weight}-{data_min_weight})+{data_min_weight}%"
  
# 您还可以在价格公式和大多数地方使用这些数据
price-formula: "{base} + {size} * {bonus} + {data_weight} * 10"
```


# 🗿 图腾

### 图腾模式

![](/files/hno3vWMjk8IqzVwQzAKk)

&#x20;             北 (-z)\
&#x20;              ↑\
(-x) 西 ←┼→ 东 (+x)\
&#x20;              ↓\
&#x20;              南 (+z)

```yaml
pattern:
  core: 4,2,2 # 层:4 行:2 索引:2 -> DAYLIGHT_DETECTOR
  layer:
    1:
      - 'AIR        GOLD_BLOCK        AIR'
      - 'GOLD_BLOCK GOLD_BLOCK GOLD_BLOCK'
      - 'AIR        GOLD_BLOCK        AIR'
    2:
      - 'AIR    AIR     AIR'
      - 'AIR GOLD_BLOCK AIR'
      - 'AIR    AIR     AIR'
    3:
      - 'AIR      AIR      AIR'
      - 'AIR LIGHTNING_ROD AIR'
      - 'AIR      AIR      AIR'
    4:
      - 'AIR        AIR        AIR'
      - 'AIR DAYLIGHT_DETECTOR AIR'
      - 'AIR        AIR        AIR'
```

```yaml
pattern:
  core: 3,1,2
  layer:
    4:
      - '*_STAIRS{face=east} OBSERVER{face=south} *_STAIRS{face=west}' 
    3:
      - 'AIR CRYING_OBSIDIAN AIR'
    2:
      - 'AIR *_LOG{axis=y}||*_PILLAR{axis=y} AIR'
    1:
      - 'AIR ANVIL AIR'
```

**核心**

指定图腾模式中的核心块。数字依次对应层、行、索引。在这种情况下，核心块位于第3层、第1行、第2个索引位置。在下面的层部分引用时，此核心指向 CRYING\_OBSIDIAN 块。

**层**

描述结构的逐层构建。

**方块类型**

\*\_XXX: 任何以 XXX 结尾的方块 ID\
XXX\_\*: 任何以 XXX 开头的方块 ID\
XXX: 原版方块 ID（大写字母）\
xxx: 自定义方块 ID （ItemsAdder/Oraxen）

注意：如果使用 ItemsAdder，请去除命名空间\
namespace:block\_id（X） block\_id（√）

**方块数据**

可用的数据类型：\
axis: x/y/z\
face: west/east/north/south/up/down\
half: bottom/up

要一起使用更多的块数据，只需按照示例操作：\
XXX{data\_1=value\_1;data\_2=value\_2;data\_3=value\_3}

**||**

代表 OR 的意思

<img src="/files/kkUBq9o1ltIIiyJ8UjLY" alt="" width="183">

### 图腾属性

```yaml
totem_key:
  duration: 300  <- 单位：秒
  radius: 10     <- 有效范围
  particles:
    ...
  pattern:
    ...
  effects:
    ...
  requirements:
    ...
  events:
    activate:
      ...
```

### 默认图腾

![金星图腾](/files/6uvznbHCC9NH10AKQd8s)

![双倍战利品图腾](/files/9gMCuJDDbNFGbkI5pLTl)

### 粒子

* **`type: REDSTONE`**：表示要使用的粒子类型。在这种情况下，选择了 `REDSTONE` 粒子类型。\
  <https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html>
* **`polar-coordinates-formula:`** 此部分决定了粒子在极坐标系中的位置或移动方式。
  * **`horizontal: '{radius}'`**：在水平方向上距图腾核心的径向距离。
  * **`vertical: '-1.5'`**：粒子的垂直位置，相对于图腾核心。
* **`theta:`** Theta 在极坐标中通常用于表示旋转角度。
  * **`draw-interval: 0.2`**：指定角度变化的频率，或粒子旋转的精细程度。较小的值可以导致更平滑的过渡。
  * **`range:`** 指定 theta 的范围。
    * **`0~360`**：粒子将在从 0 到 360 度的完整圆周内绘制。
* **`task:`** 描述与粒子渲染相关的任务或动作。
  * **`period: 4`**：指示粒子效果应该更新或重新渲染的频率。
  * **`delay: 0`**：粒子效果开始之前的延迟。在这里，它立即开始，没有延迟。
* **`options:`**

```yaml
# REDSTONE
options:
    color: 186,85,211
    scale: 0.8  (0.1~4)
# DUST_COLOR_TRANSITION
options:
    from: 255,255,255
    to: 0,0,0
    scale: 0.8
```

示例：

```yaml
particles:
  particle_0:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '{radius}'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 0~360
    task:
      period: 4
      delay: 0
  particle_1:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '{radius}/(2*cos({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 0~60
        - 120~180
    task:
      period: 4
      delay: 0
  particle_2:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '-{radius}/(2*cos({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 0~60
        - 120~180
    task:
      period: 4
      delay: 0
  particle_3:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '({radius})/(cos({theta}) + sqrt(3) * sin({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 0~120
    task:
      period: 4
      delay: 0
  particle_4:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '-({radius})/(cos({theta}) + sqrt(3) * sin({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 0~120
    task:
      period: 4
      delay: 0
  particle_5:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '-({radius})/(cos({theta}) - sqrt(3) * sin({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 60~180
    task:
      period: 4
      delay: 0
  particle_6:
    type: REDSTONE
    options:
      color: 178,34,34
      scale: 1
    polar-coordinates-formula:
      horizontal: '({radius})/(cos({theta}) - sqrt(3) * sin({theta}))'
      vertical: '-1.5'
    theta:
      draw-interval: 0.2
      range:
        - 60~180
    task:
      period: 4
      delay: 0
```

![](/files/uekQVwOwYjD04wYoB8sL)


# 🕹️ 迷你游戏

迷你游戏配置具有以下两个属性，适用于所有游戏类型：**difficulty和time**

```yaml
# 游戏难度（1~100）（默认值：“20~80”）
difficulty: 15~30
difficulty: 50

# 允许的最大游戏时间（秒）（默认值：15）
time: 15~25
time: 15
```

迷你游戏为钓鱼提供了乐趣，并在一定程度上防止玩家使用自动钓鱼。以下是内置的游戏类型：

{% content-ref url="/pages/ZWs09XuX8n5rJVU2XBxl" %}
[精准点击](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi/jing-zhun-dian-ji)
{% endcontent-ref %}

{% content-ref url="/pages/RoAdfQMcHuOTwXLqWtYf" %}
[抓住](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi/zhua-zhu)
{% endcontent-ref %}

{% content-ref url="/pages/0BlazVXZsWg4H3UL8HDf" %}
[拉紧](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi/la-jin)
{% endcontent-ref %}

{% content-ref url="/pages/N6y0R28P5A4Y0DvRduvW" %}
[点击](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi/dian-ji)
{% endcontent-ref %}

{% content-ref url="/pages/IzlZ11LnBTLw5Pyu58NV" %}
[舞蹈](/customfishing/cha-jian-wiki/customfishing/ge-shi/mi-ni-you-xi/wu-dao)
{% endcontent-ref %}


# 精准点击

你需要集中注意力，在最关键的时刻收杆

![](/files/MiaZIDWHuDbn0q1qCGh4)

![](/files/6QHSROBKx3OyCTjNOLy8)

```yaml
rainbow_1:
  game-type: accurate_click
  title: '<#fd4036>红色！'
  subtitle:
    font: 'customfishing:default'
    bar: '뀋'
    pointer: '뀁'
  arguments:
    pointer-offset: -119
    pointer-width: 5
    width-per-section: 16
    max-speed: 150
    min-speed: 15
  success-rate-sections:
    1: 1
    2: 0
    3: 0
    4: 0
    5: 0
    6: 0
    7: 0
```

```yaml
accurate_click_bar_1_easy:
  game-type: accurate_click
  difficulty: 15~30
  time: 15
  title:
    - '就差一点，保持冷静！'
    - '鱼已上钩，专心应对！'
    - '坚持住！胜利就在眼前！'
  subtitle:
    font: 'customfishing:default'
    bar: '뀂'
    pointer: '뀁'
  arguments:
    pointer-offset: -183
    pointer-width: 5
    width-per-section: 16
    max-speed: 150
    min-speed: 15
  success-rate-sections:
    1: 0
    2: 0
    3: 0
    4: 0.2
    5: 0.6
    6: 1
    7: 0.6
    8: 0.2
    9: 0
    10: 0
    11: 0
```


# 精准点击 v2

你需要集中注意力，在最关键的时刻收杆

![](/files/tJcHruClgAb3I4h1GCY2)

```yaml
accurate_click_game:
  game-type: accurate_click_v2
  difficulty: 30~80
  time: 15
  title:
    total-width: 10~12
    success-width: 1~3
    body: "<white>-</white>"
    target: "<green>-</green>"
    pointer: "<red>-</red>"
  subtitle: '<gray>在最关键的时刻收杆'
```


# 精准点击 v3

你需要集中注意力，在最关键的时刻收杆。成功区域将随机出现。

![](/files/FNE20hF1sBxam9gqfatS)

```yaml
accurate_click_game:
  game-type: accurate_click_v3
  difficulty: 40~60
  time: 150
  title: <grat>在最关键的时刻收杆
  subtitle:
    font: 'customfishing:default'
    bar: '뀌'
    judgment-area: '뀔'
    pointer: '뀁'
  arguments:
    bar-effective-area-width: 155
    judgment-area-offset: -160
    judgment-area-width: 27
    pointer-icon-width: 5
    pointer-offset: -158
    max-speed: 150
    min-speed: 15
```


# 抓住

你需要在特定区域内控制指针一段时间。

![](/files/4BfJWKZqB9at8Y75CFD4)

![](/files/jPI1tW4jYeq9cqi0ObdR)

```yaml
hold_game_easy:
  game-type: hold
  difficulty: 15~35
  time: 15
  title: '{progress}'
  # 提示将显示在标题上，指导玩家如何进行游戏
  tip: '<gray>按住 <red><key:key.sneak> <gray>开始'
  subtitle:
    font: 'customfishing:default'
    bar: '뀌'
    judgment-area: '뀒'
    pointer: '뀁'
  arguments:
    punishment: 0.2
    bar-effective-area-width: 155
    judgment-area-offset: -160
    judgment-area-width: 45
    pointer-icon-width: 5
    water-resistance: 0.15
    pulling-strength: 0.35
    loosening-strength-loss: 0.25
  hold-time-requirements:
    - 3
    - 3
    - 4
  progress:
    - '<font:customfishing:icons>뀁</font>'
    - '<font:customfishing:icons>뀂</font>'
    - '<font:customfishing:icons>뀃</font>'
    - '<font:customfishing:icons>뀄</font>'
    - '<font:customfishing:icons>뀅</font>'
    - '<font:customfishing:icons>뀆</font>'
    - '<font:customfishing:icons>뀇</font>'
    - '<font:customfishing:icons>뀈</font>'
    - '<font:customfishing:icons>뀉</font>'
```


# 抓住 v2

你需要在特定区域内控制指针一段时间。

![](/files/GLtpniT45bp06rfOsmcu)

```yaml
hold_game_easy:
  game-type: hold_v2
  difficulty: 100
  time: 15
  title: '{progress}'
  left-click: true # true = 左键点击 / false = 右键点击
  # 提示将显示在标题上，指导玩家如何进行游戏
  tip: '<gray>按住 <red><key:key.mouse.left> <gray>开始'
  subtitle:
    font: 'customfishing:default'
    bar: '뀌'
    judgment-area: '뀒'
    pointer: '뀁'
  arguments:
    punishment: 0.2
    bar-effective-area-width: 155
    judgment-area-offset: -160
    judgment-area-width: 45
    pointer-icon-width: 5
    water-resistance: 0.15
    pulling-strength: 3
    loosening-strength-loss: 0.5
    elasticity: false
    elasticity-power: 0.7
  hold-time-requirements:
    - 3
    - 3
    - 4
  progress:
    - '<font:customfishing:icons>뀁</font>'
    - '<font:customfishing:icons>뀂</font>'
    - '<font:customfishing:icons>뀃</font>'
    - '<font:customfishing:icons>뀄</font>'
    - '<font:customfishing:icons>뀅</font>'
    - '<font:customfishing:icons>뀆</font>'
    - '<font:customfishing:icons>뀇</font>'
    - '<font:customfishing:icons>뀈</font>'
    - '<font:customfishing:icons>뀉</font>'
```


# 拉紧

鱼会挣扎。在挣扎期间，鱼线的张力会急剧增加。如果鱼线的张力达到峰值，钓鱼将失败。

![](/files/hqLIOfvdnNX9qPyzBIUl)

![](/files/e6Be4YyAynprpsbhLs4R)

```yaml
tension_game_easy:
  game-type: tension
  difficulty: 20~35
  time: 15
  title: '{tension}'
  # 提示将显示在标题上，指导玩家如何进行游戏
  tip: '<gray>按住 <red><key:key.sneak> <gray>开始'
  subtitle:
    font: 'customfishing:default'
    bar: '뀑'
    fish: '뀍'
    struggling-fish:
      - 뀎
      - 뀏
      - 뀎
      - 뀐
  arguments:
    bar-effective-area-width: 218
    fish-offset: -221
    fish-start-position: 165
    fish-icon-width: 8
    success-position: 21
    ultimate-tension: 50
    normal-pull-tension-increase: 1
    struggling-tension-increase: 2
    loosening-tension-loss: 2
  tension:
    - '<font:customfishing:icons>뀑</font>'
    - '<font:customfishing:icons>뀒</font>'
    - '<font:customfishing:icons>뀓</font>'
    - '<font:customfishing:icons>뀔</font>'
    - '<font:customfishing:icons>뀕</font>'
    - '<font:customfishing:icons>뀖</font>'
    - '<font:customfishing:icons>뀗</font>'
    - '<font:customfishing:icons>뀘</font>'
    - '<font:customfishing:icons>뀙</font>'
```


# 点击

在有限的时间内快速点击

![](/files/rLCHFKgVC85bgW3KFucB)

```yaml
click_game:
  game-type: click
  difficulty: 40~60  # 点击次数
  time: 15
  left-click: true # true = 左键点击 / false = 右键点击
  title: '<red>{click}'
  subtitle: "<gray>左键点击 <white>{clicks} <gray>次以获胜。剩余时间 <white>{time}秒"
```


# 点击 v2

在有限的时间内快速点击

<figure><img src="/files/YpzVA76LXiHVgQ6zkU0Z" alt=""><figcaption></figcaption></figure>

```yaml
click_v2:
  game-type: click_v2
  title: "{progress}"
  subtitle: "<gray>左键点击 {clicked}/{clicks} | 剩余时间 {time_left}秒"
  arguments:
    required-progress: 30
    initial-progress: 10
    decrease-interval: 15
    base-decrease-rate: 1.0
    # 这决定了每个难度点每个间隔会额外减少多少进度
    extra-decrease-rate: 0.0
    zero-progress-failure: true
  left-click: true
  progress:
    - '<font:customfishing:icons>뀑</font>'
    - '<font:customfishing:icons>뀒</font>'
    - '<font:customfishing:icons>뀓</font>'
    - '<font:customfishing:icons>뀔</font>'
    - '<font:customfishing:icons>뀕</font>'
    - '<font:customfishing:icons>뀖</font>'
    - '<font:customfishing:icons>뀗</font>'
    - '<font:customfishing:icons>뀘</font>'
    - '<font:customfishing:icons>뀙</font>'
```


# 舞蹈

让我们跳舞吧！！

![](/files/1EJbBDkIss4zqletZs1u)

```yaml
dance_game:
  game-type: dance
  difficulty: 40~60 #（按钮数量为难度值的四分之一）
  time: 15
  easy: true #（true = ←→ / false = ←→↑↓）
  tip: '<gray>↑: 跳跃 | ↓: 潜行 | ←: 左键点击 | →: 右键点击</gray>'
  title: 
    left-button: '<gray>← </gray>'
    left-button-correct: '<green>← </green>'
    left-button-wrong: '<red>← </red>'
    left-button-current: '<gold>← </gold>'
    right-button: '<gray>→ </gray>'
    right-button-correct: '<green>→ </green>'
    right-button-wrong: '<red>→ </red>'
    right-button-current: '<gold>→ </gold>'
    up-button: '<gray>↑ </gray>'
    up-button-correct: '<green>↑ </green>'
    up-button-wrong: '<red>↑ </red>'
    up-button-current: '<gold>↑ </gold>'
    down-button: '<gray>↓ </gray>'
    down-button-correct: '<green>↓ </green>'
    down-button-wrong: '<red>↓ </red>'
    down-button-current: '<gold>↓ </gold>'
    display-amount: 7 #（同时显示的按钮的最大数量）
  subtitle: "<gray>跳舞以获胜。剩余时间 <white>{time}s"
  sound:
    correct: "minecraft:block.amethyst_block.hit"
    wrong: "minecraft:block.anvil.land"
```


# 🏅 比赛

**目标**：确定比赛的目标。例如，`CATCH_AMOUNT` 表示抓到最多鱼的玩家获胜。

```yaml
# TOTAL_SCORE
# CATCH_AMOUNT
# MAX_SIZE
# MIN_SIZE
# TOTAL_SIZE
# RANDOM
goal: CATCH_AMOUNT
```

**开始星期**：指定比赛开始的星期。

```yaml
start-weekday:
  - 6
  - 7
```

**开始时间**：确定比赛在一天内开始的时间。

```yaml
start-time:
  - '9:30'
  - '14:30'
  - '20:00'
```

**持续时间**：定义比赛持续的时间，单位为秒。

```yaml
duration: 300
```

**最低玩家数**：比赛开始所需的最低玩家人数。

```yaml
min-players: 2
```

**跳过动作**：如果未达到最低玩家人数，执行的操作。

```yaml
skip-actions:
  broadcast:
    type: broadcast
    value:
      - '玩家人数不足，无法按计划开始钓鱼比赛。'
```

**Boss栏**：与比赛期间Boss栏显示相关的设置。向玩家提供信息。

```yaml
bossbar:
  enable: true
  color: WHITE
  overlay: PROGRESS
  text:
    - '<gray>[<#87CEFA>🎣<gray>] <gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{seconds}s <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>你的排名: <#E6E6FA>{rank} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>第一名玩家: <#E6E6FA>{1_player}'
    - '<gray>[<#87CEFA>🎣<gray>] <gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{minute}{second} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>你的得分: <#E6E6FA>{score} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>第一名得分: <#E6E6FA>{1_score}'
    - '<gray>[<#87CEFA>🎣<gray>] <gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{minute}{second} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>获胜条件: <#E6E6FA>{goal}'
  refresh-rate: 20
  switch-interval: 200
  only-show-to-participants: true
```

**动作栏**：Boss栏的替代 UI。在动作栏中提供信息。

```yaml
actionbar:
  enable: false
  text:
    - '<gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{seconds}s <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>你的排名: <#E6E6FA>{rank} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>第一名玩家: <#E6E6FA>{1_player}'
    - '<gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{minute}{second} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>你的得分: <#E6E6FA>{score} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>第一名得分: <#E6E6FA>{1_score}'
    - '<gradient:#F0F8FF:#87CEFA:#F0F8FF>剩余时间: <#E6E6FA>{minute}{second} <gray>| <gradient:#F0F8FF:#87CEFA:#F0F8FF>获胜条件: <#E6E6FA>{goal}'
  refresh-rate: 5
  switch-interval: 200
  only-show-to-participants: true
```

**开始和结束动作**：定义比赛开始和结束时要执行的动作。

```yaml
start-actions:
  ...
end-actions:
  ...
```

**加入动作**：玩家加入比赛时要执行的动作。

```yaml
participate-actions:
  ...
```

**奖励**：根据玩家的排名或参与情况确定奖励。

```yaml
rewards:
  1:
    command_action:
      type: command
      value:
        - 'money give {player} 200'
    messages_action:
      type: message
      value:
        - '<#FF4500>[第1名] 恭喜你！你获得了第一名奖励！'
  2:
    command_action:
      type: command
      value:
        - 'money give {player} 100'
    messages_action:
      type: message
      value:
        - '<#FF4500>[第2名] 机会稍纵即逝，下次再试吧！'
  3:
    command_action:
      type: command
      value:
        - 'money give {player} 100'
    messages_action:
      type: message
      value:
        - '<#FF4500>[第3名] 机会稍纵即逝，下次再试吧！'
      
#   <-- 4,5,6...
      
  participation:
    command_action:
      type: command
      value:
        - 'money give {player} 10'
    messages_action:
      type: message
      value:
        - '<#FF4500>感谢您的参与！'
```

## Redis 排名

为了在多个服务器之间设置同步的钓鱼比赛，插件提供了与 Redis 的集成，用于实时排名更新。这确保了不同服务器上的玩家可以参加同一活动并查看实时排名。

**启用 Redis 排名**

按照以下步骤激活 Redis 排名机制：

1. 找到你的 `config.yml` 文件。
2. 找到 `mechanics` 部分。
3. 在 `competition` 子部分内部，找到 `redis-ranking`。
4. 将 `redis-ranking` 的值设置为 `true`。

```yaml
mechanics:
  competition:
    redis-ranking: true
```

**Redis 设置**

要设置 Redis，请按照以下步骤操作：

1. 打开 `database.yml` 文件。
2. 滚动查找 `Redis` 部分。
3. 根据你的 Redis 设置更新配置设置：

```yaml
Redis:
  enable: true               # 设置为 true 以启用 Redis 集成
  host: [你的_Redis_主机]     # 用你的 Redis 服务器地址替换
  #password: [你的密码]       # 如果需要，请取消注释并替换为你的 Redis 密码
  port: [你的_Redis_端口]     # 用你的 Redis 服务器端口替换
  use-ssl: [true/false]      # 如果使用 SSL 进行 Redis 连接，请设置为 true
  MaxTotal: 10               # 池可分配的最大资源数
  MaxIdle: 10                # 池中空闲资源的最大数量
  MinIdle: 1                 # 池中空闲资源的最小数量
  MaxWaitMillis: 30000       # borrowObject 方法在抛出异常之前应阻塞的最长时间
  MinEvictableIdleTimeMillis: 1800000  # 对象在池中空闲可被逐出之前可待的最短时间
```

保存并重新加载插件。

## 占位符限制

钓鱼插件使用缓存机制优化性能，特别是通过 Redis 在多个服务器之间同步数据时。出于性能考虑，默认情况下，该插件仅同步前三名竞争者的实时数据变量。如果您希望实时显示更多竞争者的数据，您需要调整 `placeholder-limit` 设置。

1. 找到你的 `config.yml` 文件。
2. 找到 `mechanics` 部分。
3. 找到 `competition` 部分。
4. 找到 `placeholder-limit` 设置。如果不存在，您可能需要手动添加它。
5. 将其值设置为您希望显示的前几名竞争者的实时数据。例如，如果您想显示前 5 名竞争者的数据，请将其设置为 5：

```yaml
mechanics:
  competition:
    placeholder-limit: 5
```


# ✅ 条件

## 介绍

插件提供了一个强大的条件系统。您可以同时使用简单条件和复杂条件。以下是一些条件示例供您学习。

注意：在某些情况下，“条件”和“要求”可以互换使用；这取决于具体情况。例如，我们可能会说一个物品出现的“条件”，但当谈论使用钓鱼竿的先决条件时，我们会说“要求”。

> 简单生物群系条件

```yaml
biome:
  - minecraft:ocean
  - minecraft:deep_ocean
  - minecraft:cold_ocean
  - minecraft:deep_cold_ocean
  - minecraft:frozen_ocean
  - minecraft:deep_frozen_ocean
  - minecraft:lukewarm_ocean
  - minecraft:deep_lukewarm_ocean
  - minecraft:warm_ocean
```

> 复杂生物群系条件

```yaml
requirement_biome:
  type: biome
  value:
    - minecraft:ocean
    - minecraft:deep_ocean
    - minecraft:cold_ocean
    - minecraft:deep_cold_ocean
    - minecraft:frozen_ocean
    - minecraft:deep_frozen_ocean
    - minecraft:lukewarm_ocean
    - minecraft:deep_lukewarm_ocean
    - minecraft:warm_ocean
```

您一定想知道为什么有两种写条件的方式。这是因为有些条件需要在不满足条件时提供反馈。例如，如果您想要向钓鱼竿添加一个权限节点，并在玩家不能使用它时通知他们，那么单独的简单条件就不能满足配置文件的要求。

以下是钓鱼竿的示例

```yaml
star_fishing_rod:
  material: fishing_rod
  requirements:
    requirement_1:
      type: permission
      value: star_fishing_rod.use
      not-met-actions:             <- 可选部分
        action_1:
          type: message
          value: '您不能使用这根钓竿！'  <- 反馈
```

{% content-ref url="/spaces/n2ogeAAIntzmG4ra344J/pages/lEtyEYYh1czo6Vtd5Hy2" %}
[💪 动作](/customfishing/cha-jian-wiki/customfishing/dong-zuo)
{% endcontent-ref %}

## 条件库

> time（Minecraft 游戏时间 0\~23999）

```yaml
time:
  - 0~1000
  - 2000~6000

advanced_requirement:
  type: time
  value:
  - 0~1000
  - 2000~6000
```

> ypos（玩家 Y 坐标）

```yaml
ypos:
  - 0~43
  - -45~12
  
advanced_requirement:
  type: ypos
  value:
  - 0~43
  - -45~12
```

> in-lava （如果鱼钩在熔岩中）

```yaml
in-lava: true

advanced_requirement:
  type: in-lava
  value: true
```

> in-water （如果鱼钩在水中）

```yaml
in-water: true

advanced_requirement:
  type: in-water
  value: true
```

> in-void （如果鱼钩在虚空）

```yaml
in-void: true

advanced_requirement:
  type: in-void
  value: true
```

> ice-fishing（如果鱼钩在冻结的河流中）

```yaml
ice-fishing: true

advanced_requirement:
  type: ice-fishing
  value: true
```

> open-water（如果鱼钩在开放水域中）

```yaml
open-water: true

advanced_requirement:
  type: open-water
  value: true
```

> biome（支持自定义生物群系）

```yaml
biome:
  - minecraft:plains  <- 白名单

'!biome':
  - minecraft:plains  <- 黑名单

advanced_requirement:
  type: biome
  value:
  - minecraft:plains

advanced_requirement:
  type: '!biome'
  value:
  - minecraft:plains
```

> world

```yaml
world:
  - world

'!world':
  - blacklist_world

advanced_requirement:
  type: world
  value:
  - world

advanced_requirement:
  type: '!world'
  value:
  - blacklist_world
```

> region （2.2.10及以上版本）

```yaml
advanced_requirement:
  type: region
  value:
    position: other # other/player （大多数情况下，‘other’=hook 的位置）
    mode: 1 # 1,2
    values:
      - a
      - b
region:
  position: other
  mode: 2
  values:
    - a
    - b
```

<figure><img src="/files/StVkj9ddVwukMuksgfI6" alt=""><figcaption><p>模式 1</p></figcaption></figure>

<figure><img src="/files/4gjfreclxbTQRoU6kmkS" alt=""><figcaption><p>模式 2</p></figcaption></figure>

> weather

```yaml
weather:
  - thunder
  - clear
  - rain

advanced_requirement:
  type: 'weather'
  value:
  - thunder
  - clear
  - rain
```

> date（现实生活日期）

```yaml
date:
  - 12/25
  - 6/1

advanced_requirement:
  type: 'date'
  value:
  - 12/25
  - 6/1
```

> permission

```yaml
permission: customfishing.admin

'!permission': blacklist.perm

advanced_requirement:
  type: 'permission'
  value: customfishing.admin
  
advanced_requirement:
  type: '!permission'
  value: blacklist.perm
```

> season（需要 RealisticSeasons/CustomCrops）

```yaml
season:
  - summer
  - spring
  - autumn
  - winter

advanced_requirement:
  type: 'season'
  value:
  - summer
  - spring
  - autumn
  - winter
```

> “>” “>=” “<” “<=” “==” “!=”（用于数字）

```yaml
'==':
  value1: '20'
  value2: '%player_health%'

advanced_requirement:
  type: '=='
  value:
    value1: '20'
    value2: '%player_health%'
```

> “startsWith” “endsWith” “equals” “contains” “in-list”

```yaml
'!startWith':
  value1: '%player_name%'
  value2: 'X'  <- 不以 "X" 开头的玩家名称

advanced_requirement:
  type: 'contains'
  value:
    value1: '%player_name%'
    value2: '_'  <- 包含 "_" 的玩家名称

advanced_requirement:
  type: '!equals'
  value:
    value1: '%player_name%'
    value2: 'XiaoMoMi'  <- 玩家名称不等于 "XiaoMoMi"

advanced_requirement:
  type: 'in-list'
  value:
    papi: '%player_name%'
    values: 
      - 'XiaoMoMi'
      - 'XIAOMOMI'
      - 'XlA0M0Ml'
```

> rod

```yaml
rod:
  - starter_rod

'!rod':
  - FISHING_ROD  <- 原版鱼竿

advanced_requirement:
  type: 'rod'
  value:
    - starter_rod
```

> hook

```yaml
hook:
  - delicate_hook

has-hook: false

advanced_requirement:
  type: '!hook'
  value:
    - bad_hook

advanced_requirement:
  type: 'has-hook'
  value: true
```

> bait

```yaml
bait:
  - starter_bait

has-bait: true

advanced_requirement:
  type: '!bait'
  value:
    - shark_bait

advanced_requirement:
  type: 'has-bait'
  value: true
```

> loot（这可以用于游戏条件）

```yaml
loot:
  - tuna_fish

advanced_requirement:
  type: '!loot'
  value:
    - shark
```

> plugin-level

```yaml
plugin-level:
  plugin: mcMMO
  level: 10
  target: FISHING
```

> logic（创建复杂条件）

```yaml
advanced_requirement:
  type: '&&'
  value:
    in-lava: true
    requirement_time:
      type: time
      value:
        - 0~12000
    '||':
      world:
        - world_nether
      '&&':
        ypos:
          - -64~-32
        world:
          - world
```

> level（玩家经验等级）

```yaml
level: 10

advanced_requirement:
  type: 'level'
  value: 10
```

> random（0\~1）

```yaml
random: 0.3   <- 30% 的概率

advanced_requirement:
  type: 'random'
  value: 0.7   <- 70% 的概率
```

> cooldown

```yaml
cooldown:
  key: unique
  time: 1000 #ms

advanced_requirement:
  type: 'cooldown'
  value:
    key: A
    time: 100 #ms
```

> regex

```yaml
regex:
  papi: %xxx%
  regex: "[A-Z]"

advanced_requirement:
  type: 'regex'
  value:
    papi: %xxx%
    regex: "[A-Z]"
```

> item-in-hand

```yaml
item-in-hand:
   amount: 1
   hand: main
   item:
   - APPLE
   - star_rod

advanced_requirement:
  type: 'item-in-hand'
  value:
    hand: off
    amount: 1
    item:
      - APPLE
      - star_rod
```

> money

```yaml
money: 100

advanced_requirement:
  type: 'money'
  value: 100
```

> in-bag（物品是否在钓鱼包中）

```yaml
in-bag: false

advanced_requirement:
  type: 'in-bag'
  value: true
```

> competition（如果正在进行比赛）

```yaml
competition:
  ongoing: true
  id:  <- 可选
    - example_competition

advanced_requirement:
  type: 'competition'
  value:
    ongoing: false
```

> environment

```yaml
environment:
  - normal
  - nether
  - the_end
  
advanced_requirement:
  type: '!environment'
  value:
    - nether
    - the_end
    - custom
```

> potion-effect

```yaml
potion-effect: "LUCK>=0"

advanced_requirement:
  type: 'potion-effect'
  value: "LUCK!=-1"

"-1": 玩家没有这种药水效果
"值不低于 0": 药水效果的放大器

示例:
  LUCK==1
  LUCK<5
  LUCK>=0
```

> has-stats（如果战利品的统计数据已启用）

```yaml
has-stats: true

advanced_requirement:
  type: 'has-stats'
  value: "true
```

> has-size（如果战利品是物品类型且具有大小属性）

```yaml
has-size: true

advanced_requirement:
  type: 'has-size'
  value: "true
```

> loot-type

```yaml
loot-type:
  - item

'!loot-type':
  - entity
  - block

advanced_requirement:
  type: 'loot-type'
  value: item
```

> moon-phase

```yaml
moon-phase:
  - "full_moon"
  - "waning_gibbous"
  - "last_quarter"
  - "waning_crescent"
  - "new_moon"
  - "waxing_crescent"
  - "first_quarter"
  - "waxing_gibbous"

advanced_requirement:
  type: 'moon-phase'
  value:
    - full_moon
```

> impossible

```yaml
impossible: true

advanced_requirement:
  type: 'impossible'
```

> equipment

```yaml
advanced_requirement:
  type: 'equipment'
  value:
    # CHEST, LEGS, HEAD, FEET
    slot: HEAD
    item:
      - LEATHER_HELMET # 原版物品
      - custom_helmet  # CustomFishing 物品
      - ItemsAdder:namespace:helmet # 来自其他插件的物品
      - Oraxen:helmet
```

> liquid-depth

```yaml
liquid-depth: 1~10

advanced_requirement:
  type: 'liquid-depth'
  value: 5~30
```

> loot-order (若玩家拥有多个战利品效果，则显示获得的战利品数量)

```yaml
loot-order: 1

advanced_requirement:
  type: 'loot-order'
  value: 2
```

> is-first-loot (若玩家拥有多个战利品效果，则该战利品为首个生效的战利品)

```yaml
is-first-loot: true
```

> 如果上下文包含 player 参数 (当没有玩家存在时，这有助于禁用某些检查)

```yaml
has-player: true

advanced_requirement:
  type: 'has-player'
  value: false
```

> is-bedrock-player (需要 Geyser 或 FloodGate)

```yaml
is-bedrock-player: true
```

> new-size-record (检查是否触发新尺寸记录)

```yaml
new-size-record: true
```

> group (检查战利品是否属于特定组)

```yaml
group: 
  - golden_star
  - silver_star

group_requirement:
  type: 'group'
  value:
    - golden_star
    - silver_star
```


# 💪 动作

动作系统提供了由插件提供的预设效果。但是，您也可以使用API添加自己的动作。此系统可应用于触发动作的任何地方，例如当您成功捕捉到鱼时，比赛结束并发放奖励时，或者出售鱼时。

动作由三部分组成

```yaml
type: 动作类型
value: 动作的参数
chance: 可选（0~1 默认: 1）
```

如果值是整数或双精度值，则可以使用表达式，例如

```yaml
exp_action:
  type: exp
  value: '{level} * 3'
```

## 动作库

> message（向玩家发送消息）

```yaml
messages_action:
  type: message
  value:
    - '<#FF4500>[1st] 恭喜！您获得了一等奖！'
```

> random-message（从列表中随机发送消息）

```yaml
message:
  type: random-message
  value:
    - '消息1'
    - '消息2'
    - '消息3'
```

> broadcast（向在线玩家发送消息）

```yaml
broadcast_action:
  type: broadcast
  value:
    - '<#D4F2E7>◤─────────────────────────◥'
    - ''
    - '             <gray>[<#87CEFA>🎣<gray>]  <gradient:#F0F8FF:#87CEFA:#F0F8FF>钓鱼比赛'
    - ''
    - '      <#E1FFFF>目标:'
    - '         <#B0C4DE>尽可能多地捕捉鱼'
    - '           <#B0C4DE>开始钓鱼以参加比赛！'
    - ''
    - '<#D4F2E7>◣─────────────────────────◢'
```

> command（执行控制台命令）

```yaml
command_action:
  type: command
  value:
    - 'money give {player} 200'
```

> player-command （以玩家身份执行命令）

```yaml
command_action:
  type: player-command
  value:
    - 'say hello'
```

> random-command（从列表中随机执行控制台命令）

```yaml
command_action:
  type: random-command
  value:
    - 'money give {player} 200'
    - 'money give {player} 100'
    - 'money give {player} 50'
```

> close-inv（关闭玩家当前打开的物品栏）

```yaml
close_action:
   type: close-inv
```

> actionbar

```yaml
actionbar_action:
  type: actionbar
  value: '您好'
```

> random-actionbar

```yaml
actionbar_action:
  type: random-actionbar
  value: 
    - 'Hi'
    - '你好'
    - 'Hola'
```

> mending（给予玩家应用于修复的经验值）

```yaml
mending_action:
  type: mending
  value: 1
```

> exp（直接给玩家经验值以升级）

```yaml
exp_action:
  type: exp
  value: 1
```

> chain（作为一组执行动作）

```yaml
chain_action:
  type: chain
  value: 
    action_1: ...
    action_2: ...
  chance: 0.5
```

> delay（延迟 x 个tick）

```yaml
delay_action:
  type: delay
  value: 
    delay: 20
    async: false
    actions:
      action_1: ...
      action_2: ...
```

> timer

```yaml
timer_action:
  type: timer
  value: 
    delay: 3
    async: false
    duration: 20
    period: 2
    actions:
      action_1: ...
      action_2: ...
```

> title

```yaml
title_action:
  type: title
  value:
    title: '<green>GG!</green>'
    subtitle: '您捕捉到了一条 {nick}'
    fade-in: 20
    stay: 30
    fade-out: 10
```

> random-title

```yaml
title_action:
  type: random-title
  value:
    titles:
      - '<green>GG!</green>'
      - '<green>干得好！</green>'
    subtitles:
      - '您捕捉到了一个 {loot}'
      - '哇！好的捕获！'
      - '哦，{loot}，我们来了！'
      - '让我们看看是什么！'
    fade-in: 20
    stay: 30
    fade-out: 10
```

> sound

```yaml
sound_action:
  type: sound
  value:
    key: 'minecraft:block.amethyst_block.place'
    source: 'player'
    volume: 1
    pitch: 1
```

> potion-effect

```yaml
potion_action:
  type: potion-effect
  value:
    type: 'blindness'
    duration: 20
    amplifier: 0
```

> plugin-exp（来自其他插件的经验，例如工作/技能插件）

```yaml
plugin_exp_action:
  type: plugin-exp
  value:
    plugin: mcMMO
    exp: 20
    target: FISHING
```

> conditional（仅当玩家满足条件时才触发动作）

```yaml
conditional_action:
  type: conditional 
  value:
    conditions:
       ...
    actions:
       ...
```

> priority（执行满足条件的第一个动作组。）

```yaml
priority_action:
  type: priority
  value:
    priority_1:
      conditions:
         ...
      actions:
         ...
    priority_2:
      conditions:
         ...
      actions:
         ...
    others:
      actions:
         ...   
```

> fake-item（显示一段时间的虚假物品）\
> 注意："opposite-yaw" 和 "yaw" 不能同时使用

```yaml
fake_item_action:
  type: fake-item
  value:
    duration: 25     <- ticks
    position: other  <- other/player
    item: water_effect
    use-item-display: true # 是否使用文本展示实体（1.19.4+）
    y: 0             <- y 偏移
    x: 0             <- x 偏移
    z: 0             <- z 偏移 
    yaw: 0
    opposite-yaw: true
    range: 0        # 如果 range = 0，只有一个玩家能看到全息图
```

> hologram（显示一段时间的全息图）

```yaml
hologram_action:
  type: hologram
  value:
    duration: 20     <- ticks
    text: '{player} 捕捉到了一个 {loot}！'
    position: player <- other/player
    use-text-display: true # 是否使用文本展示实体（1.19.4+）
    rgba: 0,0,0,0
    range: 16       # 如果 range = 0，只有一个玩家能看到全息图
    y: 2             <- y 偏移
    x: 0             <- x 偏移
    z: 0             <- z 偏移 
```

> fish-finder

```yaml
finder_action:
  type: fish-finder
  value:
    surrounding: water  # water / lava/ void
    ignore-gears: true
```

> message-nearby

```yaml
message_action:
  type: message-nearby
  value: 
    message: 
      - '您好 {near}。此消息由 {player} 发送'
    range: 32
```

> command-nearby

```yaml
command_action:
  type: command-nearby
  value: 
    command: 
      - 'give {near} apple'
    range: 32
```

> actionbar-nearby

```yaml
actionbar_action:
  type: actionbar-nearby
  value: 
    actionbar: '这是一个动作栏'
    range: 32
```

> title-nearby

```yaml
title_action:
  type: title-nearby
  value: 
    title: '<green>标题</green>'
    subtitle: '副标题'
    fade-in: 20
    stay: 30
    fade-out: 10
    range: 32
```

> food

```yaml
https://zh.minecraft.wiki/w/饥饿

food_action:
  type: food
  value: 2
```

> saturation

```yaml
https://zh.minecraft.wiki/w/饥饿

saturation_action:
  type: saturation
  value: 1.5
```

> item-amount

```yaml
item_amount_action:
  type: item-amount
  value:
    # main / off
    hand: main
    amount: -1
```

> durability

```yaml
durability_action:
  type: durability
  value:
    # hand / offhand / feet / head / chest /legs
    slot: hand
    amount: -1
```

> give-item

```yaml
item_action:
  type: give-item
  value:
    item: CustomFishing:rod:star_rod
    amount: 1
    to-inventory: false # 是掉落该物品还是直接放入背包
```

> give-money

```yaml
money_action:
  type: give-money
  value: 100.12
```

> take-money

```yaml
money_action:
  type: take-money
  value: 50.54
```

> level

```yaml
money_action:
  type: level
  value: -10
```

> context-arg

```yaml
argument_action:
  type: context-arg
  value:
    test: custom
    another: another
```

> drop-random-items (根据当前条件随机掉落物品)

```yaml
drop_random_loots_action:
  type: drop-random-loots
  value:
    amount: 10
    extra-attempts: 5 # 如果战利品不是物品，插件应该尝试多少次？
    to-inventory: false
```


# 🅿️ 占位符和表达式

## 插件占位符

| 占位符                                                                                                                        | 值                                   |
| -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
| %cfcompetition\_goingon%                                                                                                   | <p>true: 当前有比赛正在进行<br>false: 相反</p> |
| %cfcompetition\_nextseconds%                                                                                               | 获取即将到来比赛的倒计时（原始数值）                  |
| <p>%cfcompetition\_nextsecond%<br>%cfcompetition\_nextminute%<br>%cfcompetition\_nexthour%<br>%cfcompetition\_nextday%</p> | 获取即将举行的比赛的倒计时。（以天、小时、分钟和秒为单位）（格式化）  |
| %cfcompetition\_rank%                                                                                                      | 获取当前比赛的排名                           |
| %cfcompetition\_score%                                                                                                     | 获取当前比赛的得分                           |
| %cfcompetition\_score\_\<rank>%                                                                                            | 获取指定排名的玩家的得分                        |
| %cfcompetition\_player\_\<rank>%                                                                                           | 获取指定排名的玩家的名字                        |
| %cfcompetition\_goal%                                                                                                      | 获取比赛的目标                             |
| %cfcompetition\_seconds%                                                                                                   | 获取当前比赛的倒计时（原始数值）                    |
| <p>%cfcompetition\_second%<br>%cfcompetition\_minute%<br>%cfcompetition\_hour%</p>                                         | 获取当前比赛的倒计时，以小时、分钟和秒的格式显示（已格式化）      |

| 占位符                                       | 值                                                             |
| ----------------------------------------- | ------------------------------------------------------------- |
| %fishingstats\_total%                     | 获取捕获的鱼的总数。这个值可能与基础统计数据不同，因为在 CustomFishing 中，您可以禁用某些战利品的统计数据。 |
| %fishingstats\_amount\_\<id>%             | 获取捕获的特定战利品的总数                                                 |
| %fishingstats\_hascaught\_\<id>%          | 如果玩家捕获了特定的战利品，则返回 true；否则返回 false                             |
| %fishingstats\_category\_total\_\<id>%    | 获取指定类别中捕获的鱼的总数                                                |
| %fishingstats\_category\_progress\_\<id>% | 获取指定类别中战利品的解锁进度                                               |
| %fishingstats\_size-record\_\<id>%        | 获取指定战利品的大小记录                                                  |

| 占位符                               | 值                |
| --------------------------------- | ---------------- |
| %customfishing\_market\_limit%    | 获取市场的销售限制        |
| %customfishing\_market\_earnings% | 获取今天的收入          |
| %customfishing\_market\_canearn%  | 获取今天剩余可以赚取的金额    |
| %customfishing\_random%           | 获取 0-1 之间的随机双精度值 |

## 内部占位符

| 占位符                                   | 值                                                                                                           |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| <p>{second}<br>{minute}<br>{hour}</p> | 获取当前比赛的倒计时，以小时、分钟和秒的格式显示                                                                                    |
| {seconds}                             | 获取当前比赛的倒计时（原始数值）                                                                                            |
| {rank}                                | 获取当前比赛的排名                                                                                                   |
| {score}                               | 获取当前比赛的得分                                                                                                   |
| {\<rank>\_player}                     | 获取指定排名的玩家的名字                                                                                                |
| {\<rank>\_score}                      | 获取指定排名的玩家的得分                                                                                                |
| {goal}                                | 获取比赛的目标                                                                                                     |
| {loot}                                | 获取战利品的内部键                                                                                                   |
| {id}                                  | 获取内部 ID                                                                                                     |
| {record} {record\_formatted}          | 获取大小记录                                                                                                      |
| {clicks}                              | 获得点击游戏中所需的点击次数                                                                                              |
| {left\_clicks}                        | 获得点击游戏中的剩余点击次数                                                                                              |
| {total\_amount}                       | 获取捕获的鱼的数量                                                                                                   |
| {progress}                            | 获取游戏进度                                                                                                      |
| {nick}                                | 获取战利品的别名                                                                                                    |
| {score} {score\_formatted}            | <p>如果比赛目标是总得分，则返回鱼的得分。<br>如果比赛目标与大小相关，则返回鱼的大小。<br>如果比赛目标是捕获数量，则返回 "1"。</p><p>如果战利品没有得分或没有进行中的比赛，则返回“0”。</p> |
| {custom\_score}                       | 如果使用 API 方法修改了分数，则只能使用此值                                                                                    |
| {size} {size\_formatted}              | 捕获的鱼的大小                                                                                                     |
| {min\_size} {max\_size}               | 鱼的最小/最大大小                                                                                                   |
| {price} {price\_formatted}            | 捕获的鱼的最终价格                                                                                                   |
| {base}                                | 捕获的鱼的基本价格                                                                                                   |
| {bonus}                               | 基于鱼的大小增加的价格                                                                                                 |
| {x}                                   | X 坐标                                                                                                        |
| {y}                                   | Y 坐标                                                                                                        |
| {z}                                   | Z 坐标                                                                                                        |
| {other\_x}                            | 另一个 X 坐标                                                                                                    |
| {other\_y}                            | 另一个 Y 坐标                                                                                                    |
| {other\_z}                            | 另一个 Z 坐标                                                                                                    |
| {world}                               | 世界名称                                                                                                        |
| {player}                              | 玩家名称                                                                                                        |
| {near}                                | 附近玩家                                                                                                        |
| {money} {money\_formatted}            | 可以从此交易中获得的金额                                                                                                |
| {sold\_item\_amount}                  | 已出售物品的数量                                                                                                    |
| {rest} {rest\_formatted}              | 今天剩余可以赚取的金额                                                                                                 |
| {time\_left}                          | 图腾有效时间或剩余游戏时间                                                                                               |
| {0}                                   | 未修改的权重                                                                                                      |
| {rod}                                 | 获取钓竿 ID                                                                                                     |
| {bait}                                | 获取鱼饵 ID                                                                                                     |
| {hook}                                | 获取鱼钩 ID                                                                                                     |
| {surrounding}                         | 获取鱼钩所在的环境                                                                                                   |
| {random}                              | 获取 0-1 之间的随机双精度值                                                                                            |

## 注册占位符

插件不支持直接使用 PlaceholderAPI 占位符。但是，在配置文件中有一个部分，您可以自定义占位符的标识符，并几乎在任何地方使用它。

让我们尝试下面的示例。首先确保您已经安装了 PlaceholderAPI 和 Server 拓展。

```yaml
placeholder-register:
  '{date}': '%server_time_yyyy-MM-dd-HH:mm:ss%'
```

然后您可以在您的物品中使用 {date}

```yaml
rubbish:
  material: paper
  nick: <gray>Rubbish</gray>
  display:
    name: <gray>Rubbish</gray>
    lore:
      - '<gray>我们需要保护环境...'
      - '<white>于 {date} 被 {player} 抓获'
```

## 自定义表达式

一旦你注册了一个占位符，你几乎可以在插件的任何地方使用它。例如，物品属性、效果、NBT。

* **示例 1**

```yaml
# 首先在 config.yml 中注册我们需要的占位符
placeholder-register:
  '{skill-level}': '%xxxskill_fishing%'
```

① 获得多个战利品的概率增加

```yaml
#config.yml
mechanics:
  global-effects:
    skill_effect:
      type: multiple-loot
      value: '{skill-level} * 0.02'
```

② 鱼将掉落更多经验值

```yaml
#contents/item/default.yml
tuna_fish:
  events:
    success:
      action_mending:
        type: mending
        value: 5 + {skill-level} * {random} * 0.1
        chance: 1.0
```

③ 玩家每天可以通过钓鱼赚取更多收益

```yaml
# config.yml
mechanics:
  market:
    limitation:
      enable: true
      earnings: '10000 + {skill-level} * 100'
```

④ 玩家钓到垃圾的几率降低

```yaml
global-group:
  list: []
  conditions: {}
  sub-groups:
    loots_in_water:
      list:
        - 'rubbish:= 15 - ({skill-level} * 0.1)'
```

⑤ 玩家钓到优质鱼的几率增加

```yaml
#config.yml
mechanics:
  global-effects:
    skill_effect:
      type: group-mod
      value:
      - golden_star:+{skill-level} * 0.1
```

* **示例 2**

此示例要求您安装 <https://api.extendedclip.com/expansions/math/> 和 <https://api.extendedclip.com/expansions/vault/>

此示例将钱转换为整数格式，并显示玩家卖掉鱼后所能获得的钱。

```yaml
# 首先在 config.yml 中注册我们需要的占位符
placeholder-register:
  '{money_int}': "%math_0:_{money}%"
  '{money_after}': '%math_2:_{money}+{vault_eco_balance}%'
```

然后我们可以替换 config.yml 中的旧部分

```yaml
sell-icons:
  symbol: 'B'
  allow-icon:
    material: IRON_BLOCK
    display:
      name: '<#00CED1><b>● <!b>卖鱼'
      lore:
        - '<font:uniform><gradient:#E6E6FA:#48D1CC:#E6E6FA>你将从卖鱼中赚取 <green>{money_int} 硬币</green></gradient></font>'
        - '<font:uniform>卖出后你的硬币将变为 {money_after}'
    action:
      command_action:
        type: command
        value: 'money give {player} {money_int}'
```


# 🤝 兼容性


# ItemsAdder

https\://www\.spigotmc.org/resources/73355/

对于物品:

```yaml
material: ItemsAdder:namespace:id
```

对于方块:

```yaml
block: ItemsAdder:namespace:id
```

对于生物:

```yaml
mob: ItemsAdder:namespace:id
properties:
  frustumCulling: false  # 如果这个实体在玩家看不见时需要被冻结。
  noBase: false  # 如果这个自定义实体没有 Bukkit 真实实体作为基础。
  noHitbox: false  # 如果这个自定义实体的骨骼有装甲架的碰撞箱或者没有。
```


# MythicMobs

https\://mythiccraft.io/index.php?resources/mythicmobs.1/

对于物品:

```yaml
material: MythicMobs:id
```

对于生物:

```yaml
entity: MythicMobs:id
properties:
  level: 0
```


# Oraxen

https\://www\.spigotmc.org/resources/72448/

对于物品:

```yaml
material: Oraxen:id
```

对于方块:

```yaml
block: Oraxen:id
```


# EcoItems

https\://www\.spigotmc.org/resources/94601/

对于物品:

```yaml
material: EcoItems:id
```


# Nexo

需要 2.2.35+

对于物品:

```yaml
material: Nexo:id
```

对于方块:

```yaml
block: Nexo:id
```


# MMOItems

https\://www\.spigotmc.org/resources/39267/

对于物品:

```yaml
material: MMOItems:TYPE:ID
```


# NeigeItems

https\://github.com/ankhorg/NeigeItems-Kotlin/releases

对于物品:

```yaml
material: NeigeItems:id
```


# ExecutableItems

对于物品:

```yaml
ExecutableItems:id
```


# mcMMO 宝藏

https\://www\.spigotmc.org/resources/64348/

首先在 /item 文件夹中创建一个物品战利品

```yaml
mcmmo:
  material: mcMMO:treasure
  ... (战利品属性)
```

然后将其添加到 loot-conditions.yml 中

```yaml
 - mcmmo:+10
```


# 支持的等级系统

mcMMO <https://www.spigotmc.org/resources/official-mcmmo-original-author-returns.64348/>

AureliumSkills AuraSkills <https://www.spigotmc.org/resources/aurelium-skills-advanced-skills-stats-abilities-and-more.81069/>

Jobs Reborn <https://www.spigotmc.org/resources/jobs-reborn.4216/>

EcoSkills <https://www.spigotmc.org/resources/ecoskills-%E2%AD%95-addictive-mmorpg-skills-%E2%9C%85-create-custom-skills-stats-effects-mana-%E2%9C%A8-plug-play.95541/>

EcoJobs <https://www.spigotmc.org/resources/ecojobs-%E2%AD%95-powerful-employment-system-%E2%9C%85-create-custom-jobs-%E2%9C%A8-levelling-effects.105190/>

MMOCore <https://www.spigotmc.org/resources/mmocore.70575/>

用例：

```yaml
tuna_fish:
  material: cod
  display:
    name: <gradient:#F0FFFF:#4682B4:#F0FFFF>金枪鱼</gradient>
    lore:
      - <gray>金枪鱼是一种健康食品。
      - '<white>尺寸: {size_formatted}厘米'
  custom-model-data: 50001
  group:
    - ocean
    - no_star
  events:
    success:
      jobs_exp_action:
         type: plugin-exp
         value:
           plugin: JobsReborn
           exp: 15
           target: Fisherman
```


# AdvancedEnchantments

https\://www\.spigotmc.org/resources/43058/

对于附魔:

```yaml
AE:enchantment:level:
    ...
```


# EcoEnchants

https\://www\.spigotmc.org/resources/79573/

对于附魔:

```yaml
minecraft:enchantments:level:
    ...
```


# BattlePass

https\://www\.spigotmc.org/resources/63076/

```yaml
quests:
  1: # 任意战利品
    type: customfishing_loot
    variable: none
    name: '任意战利品'
    required-progress: 5
    points: 10
    item:
      material: FISHING_ROD
      name: '&e任意战利品'
      lore:
        - '&7完成此任务，你必须'
        - '&7捕获 5 条鱼。'
        - ''
        - '&7(&a%percentage_progress%&7)'
  2: # 特定战利品
    type: customfishing_loot
    variable: tuna_fish
    name: '金枪鱼'
    required-progress: 5
    points: 10
    item:
      material: FISHING_ROD
      name: '&b金枪鱼'
      lore:
        - '&7完成此任务，你必须'
        - '&7捕获 5 条金枪鱼。'
        - ''
        - '&7(&a%percentage_progress%&7)'
  3: # 战利品组
    type: customfishing_group
    variable: river
    name: '在河里捕鱼'
    required-progress: 5
    points: 10
    item:
      material: FISHING_ROD
      name: '&c在河里捕鱼'
      lore:
        - '&7完成此任务，你必须'
        - '&7在河里捕获 5 条鱼。'
        - ''
        - '&7(&a%percentage_progress%&7)'
```


# BetonQuest 3.0

https\://betonquest.org/RELEASE/

<https://modrinth.com/plugin/betonquestaddon>


# ClueScrolls

https\://www\.spigotmc.org/resources/30276/

```yaml
common_1:
   lore: '&a★ &f捕获 %amount% 条鱼: %completed%'
   clueType: customfishing_loot
   amount: 7-15
   objective: 捕获 %amount% 条金枪鱼
   clueName: 渔夫
   data:
     id: tuna_fish  <- 特定战利品
     id: any        <- 任意战利品

common_2:
   lore: '&a★ &f捕获 %amount% 条金星鱼: %completed%'
   clueType: customfishing_group
   amount: 7-15
   objective: 捕获 %amount% 条金星鱼
   clueName: 渔夫
   data:
     group: golden_star
```


# RealisticSeasons

https\://www\.spigotmc.org/resources/93275/

关于条件:

```yaml
season:
  - spring
  - autumn
  - summer
  - winter
```


# Quests

https\://www\.spigotmc.org/resources/3711/

<https://github.com/Xiao-MoMi/CustomFishingQuestsModule/releases/tag/1.0>

![安装](/files/wXxUT14ad8DPUimR8vZJ)

![选择模块](/files/40fqdFD4hhV38TavuJv6)

![选择目标](/files/g0NlUosICEbM2FkkHNsz)


# TypeWriter

https\://modrinth.com/plugin/typewriter

{% embed url="<https://github.com/Xiao-MoMi/CustomFishingTypeWriterExtension>" %}


# Zaphkiel

对于物品:

```yaml
material: Zaphkiel:id
```


# AuraSkills

需要CustomFishing 2.3.5+

要使用 AuraSkills 的战利品表，首先要在 /contents/items 文件夹下创建一个新的配置部分，如下所示：

```yaml
auraloots:
  tag: false
  material: "AuraSkills:loot"
  show-in-fishfinder: false
```

然后，您可以在 loot-conditions.yml 中使用 `auraloots`

```yaml
list:
  - 'auraloots:+15'
```

请注意，有了这种兼容性，您就不需要反复给玩家提供捕鱼经验了。插件将自动使用 AuraSkills 设置。


# 🐚 命令和权限

该插件的命令和相应的权限是完全可自定义的。您可以随意修改。默认的命令和权限可以在

{% embed url="<https://github.com/Xiao-MoMi/Custom-Fishing/blob/main/core/src/main/resources/commands.yml>" %}
commands.yml
{% endembed %}

唯一硬编码的权限是钓鱼袋行的权限节点

| 节点                   | 描述                          |
| -------------------- | --------------------------- |
| fishingbag.rows.1\~6 | 钓鱼袋行数权限示例：fishingbag.rows.2 |


# 📊 导入和导出数据

有时，您需要更改数据存储的方式，例如从 H2 切换到 MySQL。首先，您需要在 database.yml 文件中配置新的数据库。然后确保服务器上没有玩家，并从`控制台`执行命令 `/customfishing data export`。修改数据存储方式为 MySQL 后，重新加载插件。最后运行 `/customfishing data import file_name.json.gz`。


# ⌨️ 应用程序编程接口

在使用 CustomFishing API 之前，请确保您已导入 Paper API。

{% embed url="<https://docs.papermc.io/paper/dev/project-setup>" %}

然后，您可以将 CustomFishing API 依赖项添加到您的项目中

### **📌 存储库**

```kotlin
repositories {
    maven("https://repo.momirealms.net/releases/")
    // 如果你的网络环境受限可以尝试下面的存储库地址
    // maven("https://repo-momi.gtemc.cn/releases/")
}
```

### **📌 依赖**

```kotlin
dependencies {
    compileOnly("net.momirealms:custom-fishing:{version}")
}
```

最后，不要忘记将 CustomFishing 添加到 plugin.yml

```yaml
depend:
  - CustomFishing
```


# 事件

可用的事件可以在

{% embed url="<https://github.com/Xiao-MoMi/Custom-Fishing/tree/main/api/src/main/java/net/momirealms/customfishing/api/event>" %}


# 基础操作

## 创建上下文

```java
Player player = Bukkit.getPlayer("player");
Context<Player> context = Context.player(player);

// 可以用 null 创建，但注意不要在需要玩家的地方使用（如检查权限、发送消息）
Context<Player> context = Context.player(null);
```

## 获取插件实例

```java
BukkitCustomFishingPlugin api = BukkitCustomFishingPlugin.getInstance()
```

## 构建物品实例

```java
ItemStack itemStack = api.getItemManager().buildInternal(context, "rubbish");
```

## 获取效果修改器

```java
Optional<EffectModifier> optional = api.getEffectManager().getEffectModifier("beginner_rod", MechanicType.ROD);
if (optional.isPresent()) {
    EffectModifier modifier = optional.get();
}
```

## 创建新效果实例

```java
Effect effect = Effect.newInstance();
```

## 应用修改器

```java
// 总共有三个阶段
// CAST: 决定可用的钓鱼机制（如熔岩钓鱼）
// LOOT: 影响下一个战利品的权重
// FISHING: 决定战利品相关属性，如大小、分数和游戏难度
modifier.apply(effect, FishingEffectApplyEvent.Stage.CAST, context);
```

## 获取特定位置的战利品

```java
context.arg(ContextKeys.LOCATION, player.getLocation()); // 设置玩家位置
context.arg(ContextKeys.OTHER_LOCATION, custom_location); // 设置自定义位置，通常是鱼钩位置
context.arg(ContextKeys.SURROUNDING, "water");
Loot loot = api.getLootManager().getNextLoot(effect, context); 
```

## 将战利品转换为 itemStack

```java
if (loot.type() == LootType.ITEM) {
    ItemStack itemStack = api.getItemManager().buildInternal(context, loot.id());
}
```

## 从 FishingLootSpawnEvent 获取 itemStack

```java
@EventHandler
public void onLootSpawn(FishingLootSpawnEvent event) {
    if (event.getEntity() instanceof Item item) {
        ItemStack itemStack = item.getItemStack();
    }
}
```


# 集成提供器

您可以为物品、生物、附魔等注册提供器，供插件使用。您只需实现带有相应参数的接口，并最终重新加载插件以应用更改。

```java
BukkitCustomFishingPlugin api = BukkitCustomFishingPlugin.getInstance();
api.getIntegrationManager().registerBlockProvider(...);
api.getIntegrationManager().registerEnchantmentProvider(...);
api.getIntegrationManager().registerEntityProvider(...);
api.getIntegrationManager().registerSeasonProvider(...);
api.getIntegrationManager().registerLevelerProvider(...);
api.getIntegrationManager().registerItemProvider(...);
api.reload();
```


# 自定义鱼钩逻辑

要覆盖插件原生的系统，只需按照以下步骤操作：只要实现(`HookMechanic`)接口并添加到可用机制列表中，自定义逻辑即可生效（注意：添加顺序会影响机制判断的优先级）

```java
CustomFishingHook.mechanicProviders((h, c, e) -> {
    ArrayList<HookMechanic> mechanics = new ArrayList<>();
    mechanics.add(new VanillaMechanic(h, c));
    mechanics.add(new LavaFishingMechanic(h, e, c));
    return mechanics;
});
```

```java
package net.momirealms.customfishing.api.mechanic.fishing.hook;

import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.event.FishingHookStateEvent;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectProperties;
import net.momirealms.customfishing.api.util.EventUtils;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customfishing.common.util.RandomUtils;
import net.momirealms.sparrow.heart.SparrowHeart;
import net.momirealms.sparrow.heart.feature.fluid.FluidData;
import org.bukkit.*;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Vector;

import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

public class LavaFishingMechanic implements HookMechanic {

    private final FishHook hook;
    private final Effect gearsEffect;
    private final Context<Player> context;
    private ArmorStand tempEntity;
    private SchedulerTask task;
    private int timeUntilLured;
    private int timeUntilHooked;
    private int nibble;
    private boolean hooked;
    private float fishAngle;
    private int currentState;
    private int jumpTimer;
    private boolean firstTime = true;
    private boolean freeze = false;

    public LavaFishingMechanic(FishHook hook, Effect gearsEffect, Context<Player> context) {
        this.hook = hook;
        this.gearsEffect = gearsEffect;
        this.context = context;
    }

    @Override
    public boolean canStart() {
        if (!(boolean) gearsEffect.properties().getOrDefault(EffectProperties.LAVA_FISHING, false)) {
            return false;
        }
        if (hook.isInLava()) {
            return true;
        }
        float lavaHeight = 0F;
        Location location = this.hook.getLocation();
        FluidData fluidData = SparrowHeart.getInstance().getFluidData(location);
        if (fluidData.getFluidType() == Fluid.LAVA || fluidData.getFluidType() == Fluid.FLOWING_LAVA) {
            lavaHeight = (float) (fluidData.getLevel() * 0.125);
        }
        return lavaHeight > 0 && location.getY() % 1 <= lavaHeight;
    }

    @Override
    public boolean shouldStop() {
        if (hook.isInLava()) {
            return false;
        }
        return hook.isOnGround() || (hook.getLocation().getBlock().getType() != Material.LAVA && hook.getLocation().getBlock().getRelative(BlockFace.DOWN).getType() != Material.LAVA);
    }

    @Override
    public void preStart() {
        this.context.arg(ContextKeys.SURROUNDING, EffectProperties.LAVA_FISHING.key());
    }

    @Override
    public void start(Effect finalEffect) {
        EventUtils.fireAndForget(new FishingHookStateEvent(context.holder(), hook, FishingHookStateEvent.State.LAND));
        this.setWaitTime(finalEffect);
        this.task = BukkitCustomFishingPlugin.getInstance().getScheduler().sync().runRepeating(() -> {
            Location location = this.hook.getLocation();
            float lavaHeight = 0F;
            FluidData fluidData = SparrowHeart.getInstance().getFluidData(location);
            if (fluidData.getFluidType() == Fluid.LAVA || fluidData.getFluidType() == Fluid.FLOWING_LAVA) {
                lavaHeight = (float) (fluidData.getLevel() * 0.125);
            }
            if (this.nibble > 0) {
                --this.nibble;
                if (location.getY() % 1 <= lavaHeight) {
                    this.jumpTimer++;
                    if (this.jumpTimer >= 4) {
                        this.jumpTimer = 0;
                        this.hook.setVelocity(new Vector(0,0.24,0));
                    }
                }
                if (this.nibble <= 0) {
                    this.timeUntilLured = 0;
                    this.timeUntilHooked = 0;
                    this.hooked = false;
                    this.jumpTimer = 0;
                    this.currentState = 0;
                }
            } else {
                double hookY = location.getY();
                if (hookY < 0) {
                    hookY += Math.abs(Math.floor(hookY));
                }
                if (hookY % 1 <= lavaHeight || this.hook.isInLava()) {
                    Vector previousVector = this.hook.getVelocity();
                    this.hook.setVelocity(new Vector(previousVector.getX() * 0.6, Math.min(0.1, Math.max(-0.1, previousVector.getY() + 0.07)), previousVector.getZ() * 0.6));
                    this.currentState = 1;
                } else {
                    if (currentState == 1) {
                        this.currentState = 0;
                        // 设置临时实体
                        this.tempEntity = this.hook.getWorld().spawn(location.clone().subtract(0,1,0), ArmorStand.class);
                        this.setTempEntityProperties(this.tempEntity);
                        this.hook.setHookedEntity(this.tempEntity);
                        if (!firstTime) {
                            EventUtils.fireAndForget(new FishingHookStateEvent(context.holder(), hook, FishingHookStateEvent.State.ESCAPE));
                        }
                        firstTime = false;
                    }
                }
                float f;
                float f1;
                float f2;
                double d0;
                double d1;
                double d2;
                if (this.timeUntilHooked > 0) {
                    this.timeUntilHooked -= 1;
                    if (this.timeUntilHooked > 0) {
                        this.fishAngle += (float) RandomUtils.triangle(0.0D, 9.188D);
                        f = this.fishAngle * 0.017453292F;
                        f1 = (float) Math.sin(f);
                        f2 = (float) Math.cos(f);
                        d0 = location.getX() + (double) (f1 * (float) this.timeUntilHooked * 0.1F);
                        d1 = location.getY();
                        d2 = location.getZ() + (double) (f2 * (float) this.timeUntilHooked * 0.1F);
                        if (RandomUtils.generateRandomFloat(0,1) < 0.15F) {
                            hook.getWorld().spawnParticle(Particle.FLAME, d0, d1 - 0.10000000149011612D, d2, 1, f1, 0.1D, f2, 0.0D);
                        }
                        float f3 = f1 * 0.04F;
                        float f4 = f2 * 0.04F;
                        hook.getWorld().spawnParticle(Particle.FLAME, d0, d1, d2, 0, f4, 0.01D, -f3, 1.0D);
                    } else {
                        double d3 = location.getY() + 0.5D;
                        hook.getWorld().spawnParticle(Particle.FLAME, location.getX(), d3, location.getZ(), (int) (1.0F + 0.3 * 20.0F), 0.3, 0.0D, 0.3, 0.20000000298023224D);
                        this.nibble = RandomUtils.generateRandomInt(20, 40);
                        this.hooked = true;
                        hook.getWorld().playSound(location, Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 0.25F, 1.0F + (RandomUtils.generateRandomFloat(0,1)-RandomUtils.generateRandomFloat(0,1)) * 0.4F);
                        EventUtils.fireAndForget(new FishingHookStateEvent(context.holder(), hook, FishingHookStateEvent.State.BITE));
                        if (this.tempEntity != null && this.tempEntity.isValid()) {
                            this.tempEntity.remove();
                        }
                    }
                } else if (timeUntilLured > 0) {
                    if (!freeze) {
                        timeUntilLured--;
                    }
                    if (this.timeUntilLured <= 0) {
                        this.fishAngle = RandomUtils.generateRandomFloat(0F, 360F);
                        this.timeUntilHooked = RandomUtils.generateRandomInt(20, 80);
                        EventUtils.fireAndForget(new FishingHookStateEvent(context.holder(), hook, FishingHookStateEvent.State.LURE));
                    }
                } else {
                    setWaitTime(finalEffect);
                }
            }
        }, 1, 1, hook.getLocation());
    }

    @Override
    public boolean isHooked() {
        return hooked;
    }

    @Override
    public void destroy() {
        if (this.tempEntity != null && this.tempEntity.isValid()) {
            this.tempEntity.remove();
        }
        if (this.task != null) {
            this.task.cancel();
        }
        freeze = false;
    }

    @Override
    public void freeze() {
        freeze = true;
    }

    @Override
    public void unfreeze(Effect effect) {
        freeze = false;
    }

    private void setWaitTime(Effect effect) {
        int before = ThreadLocalRandom.current().nextInt(ConfigManager.lavaMaxTime() - ConfigManager.lavaMinTime() + 1) + ConfigManager.lavaMinTime();
        int after = Math.max(ConfigManager.lavaMinTime(), (int) (before * effect.waitTimeMultiplier() + effect.waitTimeAdder()));
        BukkitCustomFishingPlugin.getInstance().debug("等待时间: " + before + " -> " + after + " 刻");
        this.timeUntilLured = after;
    }

    private void setTempEntityProperties(ArmorStand entity) {
        entity.setInvisible(true);
        entity.setCollidable(false);
        entity.setInvulnerable(true);
        entity.setVisible(false);
        entity.setCustomNameVisible(false);
        entity.setSmall(true);
        entity.setGravity(false);
        entity.getPersistentDataContainer().set(
                Objects.requireNonNull(NamespacedKey.fromString("temp-entity", BukkitCustomFishingPlugin.getInstance().getBootstrap())),
                PersistentDataType.STRING,
                "lava"
        );
    }
}
```


# 自定义游戏

注册自定义游戏类型有两种方式：使用扩展jar包或插件。使用**扩展jar包**方式需要将构建好的jar文件放入"expansion"文件夹，类似 PlaceholderAPI 的工作机制。若通过**插件**方式注册自定义游戏类型，在添加自定义游戏工厂后，需要调用 **CustomFishing 的 reload 函数** 来应用更改。

## 使用插件

```java
BukkitCustomFishingPlugin.getInstance().getGameManager().registerGameType("accurate_click_v2", ((id, section) -> {
    GameBasics basics = getGameBasics(section);
    return new AbstractGame(id, basics) {

        private final String barWidth = section.getString("title.total-width", "15~20");
        private final String barSuccess = section.getString("title.success-width","3~4");
        private final String barBody = section.getString("title.body","");
        private final String left = section.getString("title.left","");
        private final String right = section.getString("title.right","");
        private final String barPointer = section.getString("title.pointer", "");
        private final String barTarget = section.getString("title.target","");
        private final String subtitle = section.getString("subtitle", "<gray>在最关键的时刻收线</gray>");

        @Override
        public BiFunction<CustomFishingHook, GameSetting, AbstractGamingPlayer> gamingPlayerProvider() {

            int minWidth = Integer.parseInt(barWidth.split("~")[0]);
            int maxWidth = Integer.parseInt(barWidth.split("~")[1]);
            int minSuccess = Integer.parseInt(barSuccess.split("~")[0]);
            int maxSuccess = Integer.parseInt(barSuccess.split("~")[1]);

            return (customFishingHook, gameSetting) -> new AbstractGamingPlayer(customFishingHook, gameSetting) {

                private final int totalWidth = RandomUtils.generateRandomInt(minWidth, maxWidth);
                private final int successWidth = RandomUtils.generateRandomInt(minSuccess, maxSuccess);
                private final int successPosition = ThreadLocalRandom.current().nextInt((totalWidth - successWidth + 1)) + 1;
                private int currentIndex = 0;
                private int timer = 0;
                private boolean face = true;

                @Override
                protected void tick() {
                    timer++;
                    if (timer % ((106 - (int) settings.difficulty()) / 5) == 0) {
                        movePointer();
                    }
                    showUI();
                }

                private void movePointer() {
                    if (face) {
                        currentIndex++;
                        if (currentIndex >= totalWidth - 1) {
                            face = false;
                        }
                    } else {
                        currentIndex--;
                        if (currentIndex <= 0) {
                            face = true;
                        }
                    }
                }

                private void showUI() {
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int i = 1; i <= totalWidth; i++) {
                        if (i == currentIndex + 1) {
                            stringBuilder.append(barPointer);
                            continue;
                        }
                        if (i >= successPosition && i <= successPosition + successWidth - 1) {
                            stringBuilder.append(barTarget);
                            continue;
                        }
                        stringBuilder.append(barBody);
                    }

                    SparrowHeart.getInstance().sendTitle(getPlayer(), AdventureHelper.miniMessageToJson(left + stringBuilder + right), AdventureHelper.miniMessageToJson(subtitle), 0, 20, 0);
                }

                @Override
                public boolean isSuccessful() {
                    if (isTimeOut) return false;
                    return currentIndex + 1 <= successPosition + successWidth - 1 && currentIndex + 1 >= successPosition;
                }
            };
        }
    };
}));
```

## 使用拓展jar

```java
package net.momirealms.customfishing.api;

import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.mechanic.fishing.CustomFishingHook;
import net.momirealms.customfishing.api.mechanic.game.*;
import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
import net.momirealms.customfishing.common.helper.AdventureHelper;
import net.momirealms.customfishing.common.util.RandomUtils;
import net.momirealms.sparrow.heart.SparrowHeart;

import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;

public class CustomGameFactory extends GameExpansion {
    @Override
    public String getVersion() {
        return "1.0";
    }

    @Override
    public String getAuthor() {
        return "XiaoMoMi";
    }

    @Override
    public String getGameType() {
        return "accurate_click_v2";
    }

    @Override
    public GameFactory getGameFactory() {
        return ((id, section) -> {
            GameBasics basics = getGameBasics(section);
            return new AbstractGame(id, basics) {

                private final String barWidth = section.getString("title.total-width", "15~20");
                private final String barSuccess = section.getString("title.success-width","3~4");
                private final String barBody = section.getString("title.body","");
                private final String left = section.getString("title.left","");
                private final String right = section.getString("title.right","");
                private final String barPointer = section.getString("title.pointer", "");
                private final String barTarget = section.getString("title.target","");
                private final String subtitle = section.getString("subtitle", "<gray>在最关键的时刻收线</gray>");

                @Override
                public BiFunction<CustomFishingHook, GameSetting, AbstractGamingPlayer> gamingPlayerProvider() {

                    int minWidth = Integer.parseInt(barWidth.split("~")[0]);
                    int maxWidth = Integer.parseInt(barWidth.split("~")[1]);
                    int minSuccess = Integer.parseInt(barSuccess.split("~")[0]);
                    int maxSuccess = Integer.parseInt(barSuccess.split("~")[1]);

                    return (customFishingHook, gameSetting) -> new AbstractGamingPlayer(customFishingHook, gameSetting) {

                        private final int totalWidth = RandomUtils.generateRandomInt(minWidth, maxWidth);
                        private final int successWidth = RandomUtils.generateRandomInt(minSuccess, maxSuccess);
                        private final int successPosition = ThreadLocalRandom.current().nextInt((totalWidth - successWidth + 1)) + 1;
                        private int currentIndex = 0;
                        private int timer = 0;
                        private boolean face = true;

                        @Override
                        protected void tick() {
                            timer++;
                            if (timer % ((106 - (int) settings.difficulty()) / 5) == 0) {
                                movePointer();
                            }
                            showUI();
                        }

                        private void movePointer() {
                            if (face) {
                                currentIndex++;
                                if (currentIndex >= totalWidth - 1) {
                                    face = false;
                                }
                            } else {
                                currentIndex--;
                                if (currentIndex <= 0) {
                                    face = true;
                                }
                            }
                        }

                        private void showUI() {
                            StringBuilder stringBuilder = new StringBuilder();
                            for (int i = 1; i <= totalWidth; i++) {
                                if (i == currentIndex + 1) {
                                    stringBuilder.append(barPointer);
                                    continue;
                                }
                                if (i >= successPosition && i <= successPosition + successWidth - 1) {
                                    stringBuilder.append(barTarget);
                                    continue;
                                }
                                stringBuilder.append(barBody);
                            }

                            SparrowHeart.getInstance().sendTitle(getPlayer(), AdventureHelper.miniMessageToJson(left + stringBuilder + right), AdventureHelper.miniMessageToJson(subtitle), 0, 20, 0);
                        }

                        @Override
                        public boolean isSuccessful() {
                            if (isTimeOut) return false;
                            return currentIndex + 1 <= successPosition + successWidth - 1 && currentIndex + 1 >= successPosition;
                        }
                    };
                }
            };
        });
    }

    private GameBasics getGameBasics(Section section) {
        return GameBasics.builder()
                .difficulty(MathValue.auto(section.get("difficulty", "20~80"), false))
                .time(MathValue.auto(section.get("time", 15), false))
                .build();
    }
}
```


# 🍀 CustomNameplates


# ✏️ 文本格式

## 旧版颜色代码（已过时）

```
&1 &2 &3 &a &b &c &m &l 等等
```

## MiniMessage 格式（推荐）

<https://docs.adventure.kyori.net/minimessage/format.html>


# ❓️ 常见问题

## 问题 1: 紫色的Boss栏

插件中默认的Boss栏应该是黄色的。如果您看到紫色的Boss栏，则是Lunar客户端中的一个错误。

## 问题 2: 如何使用 ItemsAdder/Oraxen 中的图像

您应该使用字体标签将图像包围起来，例如：

```yaml
<font:minecraft:default>%img_xxx%</font>  # 不要忘记关闭标签
```

## 问题 3: 背景与文本不匹配

这是因为插件不知道您自定义图像的宽度。如果您在 CustomNameplates 中注册了图像，只需在 YAML 文件中输入图像的宽度。如果您使用其他插件（例如 ItemsAdder）创建新图像，则应在 **/configs/font-width-data.yml** 中输入您图像的宽度。

![](/files/JewjphMYbuA1Y4UkByk2)

```yaml
minecraft:default:
  default: 8
  template-loading-sequence:
    - unifont
    - nonlatin_european
    - accented
    - ascii
    - space
  # 这里的值将覆盖模板中相同的字符
  values:
    默: 17               # 在此处输入字符
    "%placeholder%": 17   # 在此处输入占位符
```

## 问题 4: 我使用的是自定义位图字体

如果通过位图使用自定义字体，只需将其放入插件的 /font 文件夹并覆盖前一个即可。然后从插件文件夹中删除`/tmp`文件夹。最后，重新启动服务器。

![](/files/tYw7lngGrpS57bBqNkGl)

## 问题 5: 是什么造成了黑色方框？

这是由于 ItemsAdder 的 hud 造成的。只需在 ItemsAdder 的 config.yml 中禁用即可。

![](/files/zAzbki4DcYqxzuIHkRpO)

```yaml
huds:
  enabled: false
  force_color:
    enabled: false
    color: '#FFFFFF'
```

## 问题 6: 我想向下或向上移动图像

如果图像是由 CustomNameplates 注册的，只需编辑`ascent`选项即可。

如果您使用其他插件中的图像，则无法从 CustomNameplates 中实现向下或向上移动图像。实际上它很容易修复，因为在这些插件中它们提供了编辑图像上升的选项（在 ItemsAdder 中称为`y_position` ）

![](/files/S2Y8WB7mHOyPN4RrosLF)

## 问题 7: 玩家看不到boss栏 <a href="#q7-players-cant-see-bossbar" id="q7-players-cant-see-bossbar"></a>

您应该给予他们“bossbar.show”权限或从 bossbar 配置中删除权限条件。

```yaml
bossbar_1:
  conditions:
    condition_1:
      type: permission
      refresh-interval: 20
      value:
        - bossbar.show
```

## 问题 8: 气泡不起作用

这是因为任何聊天插件都会取消玩家聊天事件。要解决这个问题，首先检查 config.yml 中是否正式支持该插件，并启用集成（如果可用）

```yaml
integrations:
  # 某些聊天，例如管理员聊天或菜单输入，可能需要从捕获中排除。
  # 支持的聊天插件如下所示，允许黑名单频道和 /ignore 功能正常工作。
  chat:
    TrChat: false
    VentureChat: false
    HuskChat: false
    CarbonChat: false
    AdvancedChat: false
    Essentials: false
```

如果您使用不受支持的插件，您可以提出建议，但前提是该插件具有 API 存储库。最糟糕的解决方案是在 config.yml 中打开`unsafe-chat-event`

## 问题 9: Boss栏与HUD插件冲突

在 config.yml 中将`send-delay`设置为适当的值可以修复

## 问题 10: 着色器冲突

如果遇到着色器冲突，则需要合并着色器（这需要一些 GLSL 知识）或禁用 CustomNameplates 着色器。

## 问题 11: 超暗背景

如果您发现背景的颜色异常的暗，则意味着着色器尚未成功应用于您的客户端。这通常是由着色器冲突引起的，因为客户端一次只能应用一个着色器。如果您需要使用多个着色器，则必须手动合并它们。如果您无法解决该问题，可以考虑降低图像的不透明度作为替代解决方案。这有助于减轻着色器冲突的视觉影响。

（可以在此处下载替代图像。如要使用请替换 /contents/backgrounds/ 文件夹下的图像）

{% file src="/files/T2ouloUpIuNE3EBNve26" %}

<figure><img src="/files/zrEFhV13gkJaU9QSsPyI" alt=""><figcaption></figcaption></figure>

## 问题 12: 玩家名称显示为“□□□□”

出现此问题的原因是运行版本 1.19.4 到 1.20.3 的客户端无法读取**unifont\_jp** ，并且 1.19.4 客户端无法读取**unifont** 。这意味着某些字体和特定 Minecraft 版本之间的兼容性可能会导致显示问题。

如果您运行的是 1.20+ 服务器并且您确实不需要它，可以考虑删除**unifont\_jp** ，如下例所示：

```yaml
# config.yml
shift-fonts:
  shift_0:
    - space
    - nonlatin_european:7
    - accented:9
    - ascii:7
    #- unifont_jp
    - unifont
```

如果您运行的是 1.19.4 服务器，则可以按以下示例所示进行配置：

```yaml
# config.yml
shift-fonts:
  shift_0:
    - space
    - nonlatin_european:7
    - accented:9
    - ascii:7
    - unicode
```

<figure><img src="/files/twbQo7lwGyHpPlm8x7Xd" alt=""><figcaption></figcaption></figure>

## 问题 13: 如何使用TTF字体

取消注释 `config.yml` 中的 `ttf` 部分，并将 `example` 替换为你使用的字体名称。然后将你的 TTF 文件放在 `/CustomNameplates/font` 目录下，并重启服务器。

```yaml
ttf:
  example:
    generate: false               # 是否将此 TTF 文件包含在生成的资源包中
    file: example.ttf             # 定义加载字体的 TTF 文件
    size: 10.0                    # 设置字体大小
    oversample: 8.0               # TTF 渲染的过采样率
    skip: []                      # 以列表格式跳过的字符
```

然后你就可以在 shift-fonts 中使用 ttf 字体了

```yaml
shift_3:
  - space
  - example:3  # 这里的数字是 Y 轴偏移量
```

请注意，ttf 文字的前进量计算可能不准确。因此，目前不建议用于非常大的字体。如果你发现某个字符的前进量不正确，可以使用文本编辑器编辑 `/tmp/xxx.tmp` 中相应字符的前进量数据 `（需要重启服务器才能生效）`


# 📖 基本字体知识

## 试着用不同的字体发送文本

Minecraft的聊天组件包含许多装饰符，其中之一是字体。大多数字符存储在 `minecraft:default` 字体中。细字体字符存储在 `minecraft:uniform` 字体中，附魔台字符存储在 `minecraft:alt` 字体中。

你可以通过运行简单的命令发送带有字体的文本。很容易发现，不同字体中相同的文本具有不同的形状。

```TXT
/tellraw @p {"text":"Hello!","font":"minecraft:default"}
```

<div align="left"><img src="/files/85cjbHbHyqcfbqU8Lc4d" alt="" width="261"></div>

```TXT
/tellraw @p {"text":"Hello","font":"minecraft:uniform"}
```

<div align="left"><img src="/files/oBoiZRqr9oSUZREje5WV" alt="" width="269"></div>

```TXT
/tellraw @p {"text":"Hello","font":"minecraft:alt"}
```

<div align="left"><img src="/files/ZiNFzOWgjUwtP870Sk07" alt="" width="245"></div>

## **Minecraft wiki对“Bitmap provider”的解释**

> **Bitmap provider**
>
> `bitmap` 提供者定义简单的位图字形 - 来自纹理的字形。它引用单个PNG文件，适用于其中的字符列表，可选的高度和上升值。
>
> 纹理可以是任何尺寸，字形可以是任何颜色。白色字形可以在游戏中着任何其他颜色。其他颜色在重新着色时保留该色调。黑色字形始终显示为黑色。根据包含任何alpha值大于0的最右列像素自动确定字形的宽度。字形本身不能大于512×512像素。`chars` 字段是一个字符串列表。该列表中每个字符串条目中的字符映射到引用文件中的相应位置。根据列表中字符串的数量以及该列表中最长字符串的长度，纹理被均匀地划分。
>
> `height` 字段是生成字形的比例。该比例通常应与字形的单个高度匹配，或者是其幂。虽然允许在此推荐范围之外的高度，并且是有效的，但在游戏中渲染时，位于提供程序中声明的字形出现扭曲。`height` 字段是可选的。如果未定义，则默认为8，而不管底层纹理分辨率如何。
>
> `ascent` 字段是应用于字形的垂直偏移量。在排版学中，ascent 是基线到大写字母的高度（字形顶部）的距离。字形中的基线是下降部分开始的线。例如，在小写字母 y 中，y 的底部延伸到基线之外。在Vanilla中，当高度为8时，上升值大多为7，因为下降部分为1。

**在 CustomNameplates 中，你可以简单地理解为**

```yaml
image: bell # 图像文件
height: 10  # 图像的尺寸
ascent: 4   # 字符的Y位置（不得高于height）
```

## 与 minecraft:default 相比，使用其他字体的好处是什么？

我们可以很容易地看到，ItemsAdder 和 Oraxen 都使用该字体来注册自定义图像。问题是，“minecraft:default”字体是默认字体，因此玩家如果找到原始字符，就可以发送图像。因此，这些插件将尽力阻止玩家发送这些字符。如果你不将图像注册到 minecraft:default 字体中，你就不必担心玩家发送你的自定义图像。

## 如何在其他插件中使用 CustomNameplates 占位符

并非市场上所有的插件都支持自定义字体。如果你看到一个支持 "MiniMessage" 和 "PlaceholderAPI" 的插件，那么它有90%的机会支持它。有些插件开发者会将 MiniMessage 转换为旧版格式，并让 Spigot 处理旧版颜色代码，这真是遗憾。


# ⚙️ 配置


# config.yml

**模块设置:**

* 此部分控制哪些模块处于活动状态:
  * `nameplates`，`backgrounds`，`bubbles`，`bossbars`，`actionbars`，和 `images` 都设置为 true，表示这些功能已启用。修改这些设置可能会影响资源包的生成，因此如果遇到问题，可能需要重新安装资源包。

```yaml
modules:
  nameplates: true
  backgrounds: true
  bubbles: true
  bossbars: true
  actionbars: true
  images: true
```

**插件集成:**

* **resource-pack:** 在这里，您可以选择是否集成来自特定插件（如`ItemsAdder`和`Oraxen`）的资源包。
* **聊天集成:** 可以集成支持的聊天插件来实现黑名单频道和忽略功能等功能。

```yaml
integrations:
  resource-pack: ...
  chat: ...
```

**资源包生成设置:**

* **disable-generation-on-start:** 设置为 `false`，允许在服务器启动时生成资源包。
* **namespace:** 该字段定义资源包的命名空间，此处设置为 `"nameplates"`。
* **font:** 指定要使用的字体。默认字体设置为 `"default"`。
* **initial-char:** 定义自定义字体的起始字符。这里使用`뀁`，这不会影响聊天时的正常韩语字符。
* **image-path:** 指定各种资产（铭牌、背景、图像等）的 PNG 文件的生成位置。这些路径有助于维护有序的资源包结构。
* **transparent-bossbar:** 生成透明boss栏的设置
* **legacy-unicodes:** 在 Minecraft 1.20+ 客户端中启用对旧版 Unicode 字符的支持，为您的资源包大小增加约 900KB。

```yaml
resource-pack:
  disable-generation-on-start: false
  namespace: "nameplates"
  font: "default"
  initial-char: '뀁'
  image-path:
    nameplates: 'font/nameplates/'
    backgrounds: 'font/backgrounds/'
    images: 'font/images/'
    bubbles: 'font/bubbles/'
    space-split: 'font/base/'
  shader:
    enable: true
    hide-scoreboard-number: false # 1.19.4 - 1.20.3
    animated-text: false
    ItemsAdder-text-effects: false
  transparent-bossbar:
    color: YELLOW
    "1_20_2+": true
    "1_17-1_20_1": true
  legacy-unicodes: true
```

**其他设置:**

* **legacy-color-code-support:** 启用对旧版 Minecraft 颜色代码的支持（使用 `&`）。禁用此功能可以提高颜色格式化性能。
* **send-delay:** 指定 actionbar/bossbar 的延迟以确保与其他插件的兼容性。
* **catch-other-plugin-actionbar:** 设置为 `true` 以捕获来自其他插件的操作栏。
* **unsafe-chat-event:** 设置插件是否应该监听由未知插件取消的聊天事件。
* **refresh intervals:** 定义条件和占位符的默认刷新间隔。

```yaml
other-settings:
  legacy-color-code-support: true
  send-delay: 0
  catch-other-plugin-actionbar: true
  unsafe-chat-event: false
  default-condition-refresh-interval: 1
  default-placeholder-refresh-interval: 1
  placeholder-refresh-interval:
    "%player_name%": 100
    "%vault_prefix%": 1
```

**字体模板:**

* **font-templates:** 此部分定义系统如何​​加载不同的字体，例如`space`、`unihex`和`bitmap` 字体。您可以在此处添加新配置或替换现有字体模板。它管理 [Minecraft 字形提供器](https://zh.minecraft.wiki/w/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AD%97%E4%BD%93#%E5%AD%97%E5%BD%A2%E6%8F%90%E4%BE%9B%E5%99%A8) 提供的各种字符类型
* **字体配置选项:**
  * `file`: 指的是位于 `/CustomNameplates/font` 目录中的文件。
  * `custom`: 指定是否使用客户端提供的默认 PNG 位图字体。
  * `generate`: 指示是否在生成的资源包中包含此字体的副本。

```yaml
other-settings:
  font-templates:
    space:
      space:
        ' ': 4
        ‌: 0
    unihex:
      unifont:
        file: "unifont.zip"
        generate: false
        size_overrides:
        - from: "、"
          to: "ヿ"
          left: 0
          right: 15
        - from: "㈀"
          to: "鿿"
          left: 0
          right: 15
        - from: "ᄀ"
          to: "ᇿ"
          left: 0
          right: 15
        - from: "㄰"
          to: "㆏"
          left: 0
          right: 15
        - from: "ꥠ"
          to: "꥿"
          left: 0
          right: 15
        - from: "ힰ"
          to: "퟿"
          left: 0
          right: 15
        - from: "가"
          to: "힯"
          left: 1
          right: 15
        - from: "豈"
          to: "﫿"
          left: 0
          right: 15
        - from: "！"
          to: "～"
          left: 0
          right: 15
      unifont_jp:
        file: "unifont_jp.zip"
        generate: false
        filter:
          jp: true
        size_overrides:
        - from: "㈀"
          to: "鿿"
          left: 0
          right: 15
        - from: "豈"
          to: "﫿"
          left: 0
          right: 15
    bitmap:
      ascii:
        codepoints: "ascii"
        file: "ascii.png"
        height: 8
        custom: false # 这是非默认的 Minecraft 字体吗？如果启用，插件将在生成的资源包中创建新的字体图像
      ascii_sga:
        codepoints: "ascii_sga"
        file: "ascii_sga.png"
        height: 8
        custom: false
      asciillager:
        codepoints: "asciillager"
        file: "asciillager.png"
        height: 8
        custom: false
      nonlatin_european:
        codepoints: "nonlatin_european"
        file: "nonlatin_european.png"
        height: 8
        custom: false
      accented:
        codepoints: "accented"
        file: "accented.png"
        height: 12
        custom: false
    legacy_unicode:
      legacy_unicode:
        file: "unicode_page_%02x.png"
        height: 8
        custom: false
    unicode:
      unicode:
        file: "unicode_page_%02x.png"
        sizes: "glyph_sizes.bin"
    ttf:
      example:
        generate: false
        file: "example.ttf"
        size: 10.0
        oversample: 8.0
        skip: []
```

**下降字体:**

详见[下降文本](/customnameplates/cha-jian-wiki/customnameplates/zi-ding-yi-zhan-wei-fu/xia-jiang-wen-ben)

```yaml
other-settings:
  shift-fonts:
    shift_0:
      - space
      - nonlatin_european:7
      - accented:9
      - ascii:7
      - unifont_jp
      - unifont
    shift_1:
      - space
      - nonlatin_european:3
      - accented:6
      - ascii:3
      - legacy_unicode:3
    shift_2:
      - space
      - ascii:-15
```


# bossbar.yml

**Boss栏部分:** 您可以创建多个boss**栏**部分，每个部分都有自己的设置。在此示例中，我们有一个 `bossbar_1` 部分。但您可以创建更多部分，例如 `bossbar_2`

```yaml
# 你可以创建任意数量的boss栏部分
bossbar_1: ...

bossbar_2: ...
```

**Boss栏颜色:** 使用`color`字段选择boss栏的颜色。可用选项有：`BLUE`、`GREEN`、`PINK`、`PURPLE`、`RED`、`WHITE`和`YELLOW`。在本例中，颜色设置为`YELLOW`。

如果您需要隐藏特定的 boss栏，则需要修改 config.yml 中的配置

```yaml
bossbar_1:
  # BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW
  color: YELLOW
```

**进度条样式:** 使用`overlay`字段设置进度条的外观。选项包括`"progress"`、`"notched_6"`、`"notched_10"`、`"notched_12"`和`"notched_20"`。此处设置为 `PROGRESS`。

```yaml
bossbar_1:
  # "progress", "notched_6", "notched_10", "notched_12", "notched_20"
  overlay: PROGRESS
```

**条件:** 您可以定义显示boss栏所必须满足的条件。在`conditions`部分，每个条件都有一个类型（例如`permission`）和`refresh-interval`，以防止严重条件导致服务器滞后。`value`字段列出了所需的权限。例如，如果玩家拥有 `bossbar.show` 权限，则将显示boss栏。

您可以在此处查看所有支持的条件[条件系统](/customnameplates/cha-jian-wiki/customnameplates/tiao-jian)

```yaml
bossbar_1:
  conditions:
    condition_1:
      type: permission
      refresh-interval: 20  # 以刻位单位，多久检查一次玩家是否仍具有所需的权限
      value:
        - bossbar.show
```

**文本显示顺序:** boss栏可以显示一系列消息，这些消息在 `text-display-order` 下定义。每条消息都有`duration`（以刻为单位，20 刻 = 1 秒）和要显示的文本。例如：

* 第一条消息 (`text: '%np_background_hello%'`) 显示 100 刻（5 秒）。
* 第二条消息 (`text: '%np_background_time% %np_background_location% %np_background_weather%'`) 显示 200 刻（10 秒）。
* 第三条信息 (`text: '%np_background_update%'`) 显示 100 刻（5 秒）。

您可以为特定文本消息添加条件。在第三条消息中，定义了一个条件，即检查玩家是否具有 `nameplates.admin` 权限以及值 `%np_is-latest%` 是否等于 `false`。只有同时满足这两个条件时才会显示此消息。

```yaml
bossbar_1:
  # boss栏将按照这个顺序循环显示文本:
  text-display-order:
    1:
      duration: 100
      text: '%np_background_hello%'
    2:
      duration: 200
      text: '%np_background_time%  %np_background_location%  %np_background_weather%'
      refresh-frequency: 1
    3:
      duration: 100
      text: '%np_background_update%'
      conditions:
        permission: nameplates.admin
        equals:
          value1: '%np_is-latest%'
          value2: 'false'
```

如果不需要轮播的文字，那么就这么配置

```yaml
bossbar_1:
  text: '%np_background_hello%'
```


# actionbar.yml

**条件:** 您可以定义显示动作栏的特定条件。在本例中， `condition_1`检查玩家是否具有`actionbar.show`权限。 `refresh-interval`指定重新检查权限的频率（以刻为单位，20 刻 = 1 秒）。权限检查确保只有具有适当权限的玩家才能看到操作栏。

您可以在此处查看所有支持的条件[条件系统](/customnameplates/cha-jian-wiki/customnameplates/tiao-jian)

```yaml
actionbar:
  conditions:
    condition_1:
      type: permission
      refresh-interval: 20  # 刷新频率（以刻为单位）用于重新检查权限状态
      value:
        - actionbar.show
```

**文本显示顺序:** 此部分确定动作栏消息的显示顺序。每条消息都有:

* **持续时间:** 文本可见的时间，以刻为单位。例如，`duration: -1` 表示消息将无限期地停留在屏幕上，直到手动移除或替换。
* **文本:** 这定义了操作栏中将显示的消息。例如，`%np_conditional_actionbar%` 是显示的占位符文本。

```yaml
actionbar:
  text-display-order:
    1:
      duration: -1
      text: '%np_conditional_actionbar%'
      conditions: {}
```

在只有一个轮播文本的情况下，此配置等效

```yaml
actionbar:
  text: '%np_conditional_actionbar%'
```


# bubble.yml

**发送者和查看者的要求:**

* **发送者要求:** 要发送气泡，玩家必须满足`sender-requirements`下定义的条件。在这种情况下:
  * 玩家需要`bubbles.send`权限。
  * 玩家还必须具有指定的`potion-effect`，在本例中为`"INVISIBILITY<0"`，这意味着玩家没有隐身药水效果
* **查看者要求:** 要查看气泡，玩家必须具有`viewer-requirements`下定义的`bubbles.see`权限。

```yaml
sender-requirements:
  permission: bubbles.send
  potion-effect: "INVISIBILITY<0"

viewer-requirements:
  permission: bubbles.see
```

**黑名单频道**:

* `blacklist-channels` 部分允许您指定哪些频道不会显示气泡。在此示例中:

  * "Private"和"Admin"频道被列入黑名单，这意味着这些频道中不会显示气泡。

  ```yaml
  blacklist-channels:
    - Private
    - Admin
  ```

**频道模式:**

* `channel-mode` 选项控制谁可以看到频道内的气泡:
  * **ALL:** 所有玩家都可以看到气泡。
  * **JOINED:** 只有同一频道内的玩家才能看到彼此的气泡。
  * **CAN\_JOIN:** 有权加入特定频道的玩家将在这些频道中看到气泡。在此配置中，`channel-mode`设置为`ALL`，这意味着所有玩家都可以看到气泡。

```yaml
channel-mode: ALL
```

**默认气泡:**

* 如果玩家没有指定特定的气泡，则 `default-bubble` 设置定义应显示哪个气泡。此处，它设置为 `'chat'`。

```yaml
default-bubble: 'chat'
```

**显示设置:**

* **Y-Offset:** `y-offset` 调整气泡相对于最高铭牌的位置。在本例中，它设置为 `0.1`，这意味着它将显示在铭牌略上方。
* **查看范围:** `view-range` 定义玩家在多远的距离内仍能看到气泡。这里，它设置为`0.5`。（0.5 \* 视距）

```yaml
y-offset: 0.1
view-range: 0.5
```

**气泡显示时间:**

* **停留时间:** `stay-duration` 指定气泡保持可见的时间（以刻为单位）。在本例中，它设置为 150 刻，相当于 7.5 秒。
* **淡入和淡出时间:** `appear-duration` 和 `disappear-duration` 控制气泡淡入和淡出所需的时间。在这里，气泡需要 4 刻（0.2 秒）才完全出现，2 刻（0.1 秒）才完全消失。

```yaml
stay-duration: 150
appear-duration: 4
disappear-duration: 2
```

**气泡设置:**

* 在`bubble-settings`下，您可以配置单个气泡：

  * **显示名称:** `display-name` 是气泡的名称，在本例中，它被称为`"白色气泡"`。
  * **最大行数:** `max-lines` 设置决定可以显示多少行文本。对于"chat"气泡，最多允许显示 3 行。
  * **行:** 每行对应一个特定的聊天气泡（例如，`chat_1`、`chat_2`、`chat_3`）。
  * **行宽:** `line-width` 定义每行的最大宽度，这里设置为 150。
  * **背景颜色:** `background-color` 指定气泡背景的 ARGB 值（alpha、红色、绿色、蓝色）。在本例中，它设置为 `0,0,0,0`（完全透明）。
  * **文本前缀和后缀:** 这些字段允许您为文本添加格式。此处的`text-prefix`使用`<black>`颜色标签和名为"nameplates"的自定义字体，并带有移位效果（`shift_0`）。`text-suffix`关闭字体和颜色标签。

  ```yaml
  bubble-settings:
    chat:
      display-name: "白色气泡"
      max-lines: 3
      lines:
        1: chat_1
        2: chat_2
        3: chat_3
      line-width: 150
      background-color: 0,0,0,0
      text-prefix: "<black><font:nameplates:shift_0>"
      text-suffix: "</font></black>"
  ```




---

[Next Page](/llms-full.txt/1)

