1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/* * minecraft-json: processing Minecraft JSON data * Copyright (C) 2021 Xie Ruifeng * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ //! Predicates are technical JSON files that represent the conditions for loot tables, `/execute //! if predicate` command, or predicate target selector argument. They are a part of data packs. //! //! Inside a data pack, a predicate is located within data/<namespace>/predicates. //! //! A predicate file may also contain an array of multiple predicate objects, in which case the //! predicate passes only if all sub-predicates pass. use std::collections::BTreeMap; use derivative::Derivative; use serde::{Serialize, Deserialize}; use serde_json::Number; use crate::minecraft::data::conditions::{DamageSource, Entity, Location, Item}; use crate::minecraft::common::{Ranged, Ranged2, NumberProviderValue}; use crate::defaults; /// Predicate. #[derive(Eq, PartialEq, Debug)] #[derive(Serialize, Deserialize)] #[serde(tag = "condition", rename_all = "snake_case")] #[non_exhaustive] pub enum Predicate { /// Joins conditions from parameter terms with "or". Alternative { /// A list of conditions to join using 'or'. terms: Vec<Predicate>, }, /// Check properties of a block state. BlockStateProperty { /// A block ID. The test fails if the block doesn't match. block: String, /// A map of block property names to values. All values are strings. The test fails if /// the block doesn't match. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] properties: BTreeMap<String, String>, }, /// Check properties of damage source. DamageSourceProperties { /// Predicate applied to the damage source. predicate: DamageSource, }, /// Test properties of an entity. EntityProperties { /// Specifies the entity to check for the condition. entity: WhichEntity, /// Predicate applied to entity, uses same structure as advancements. predicate: Box<Entity>, }, /// Test the scoreboard scores of an entity. EntityScores { /// Specifies the entity to check for the condition. entity: WhichEntity, /// Scores to check. All specified scores must pass for the condition to pass. /// /// Item: Key name is the objective while the value is the exact score value (or a range /// of score values) required for the condition to pass. scores: BTreeMap<String, Ranged<isize>>, }, /// Inverts condition from parameter term. Inverted { /// The condition to be negated. term: Box<Predicate>, }, /// Test if a [`WhichEntity::KillerPlayer`] entity is available. KilledByPlayer { /// If true, the condition passes if [`WhichEntity::KillerPlayer`] is *not* available. #[serde(default, skip_serializing_if = "defaults::is_default")] inverse: bool, }, /// Checks if the current location matches. #[serde(rename_all = "camelCase")] LocationCheck { /// Optional offsets to location. #[serde(default, skip_serializing_if = "Option::is_none")] offset_x: Option<isize>, /// Optional offsets to location. #[serde(default, skip_serializing_if = "Option::is_none")] offset_y: Option<isize>, /// Optional offsets to location. #[serde(default, skip_serializing_if = "Option::is_none")] offset_z: Option<isize>, /// Predicate applied to location, uses same structure as advancements. predicate: Box<Location>, }, /// Checks tool. MatchTool { /// Predicate applied to item, uses same structure as advancements. predicate: Box<Item>, }, /// Test if a random number 0.0–1.0 is less than a specified value. RandomChance { /// Success rate as a number 0.0–1.0. chance: Number, }, /// Test if a random number 0.0–1.0 is less than a specified value, affected by the level of /// `Looting` on the killer entity. RandomChanceWithLooting { /// Base success rate. chance: Number, /// Looting adjustment to the base success rate. /// Formula is `chance + (looting_level * looting_multiplier)`. looting_multiplier: Number, }, /// Test if another referred condition (predicate) passes. Reference { /// The namespaced ID of the condition (predicate) referred to. A cyclic reference /// causes a parsing failure. name: String, }, /// Returns true with 1/explosion radius probability. SurvivesExplosion, /// Passes with probability picked from table, indexed by enchantment level. TableBonus { /// Id of enchantment. enchantment: isize, /// List of probabilities for enchantment level, indexed from 0. chances: Vec<Number>, }, /// Checks the current time. TimeCheck { /// The time value in ticks. value: Ranged2<isize, NumberProviderValue<isize>>, /// If present, time gets modulo-divided by this value (for example, if set to `24000`, /// value operates on a time period of daytime ticks just like `/time query daytime`). #[serde(default, skip_serializing_if = "Option::is_none")] period: Option<isize>, }, /// Checks for a current weather state. WeatherCheck { /// If true, the condition evaluates to true only if it's raining or thundering. #[serde(default, skip_serializing_if = "Option::is_none")] raining: Option<bool>, /// If true, the condition evaluates to true only if it's thundering. #[serde(default, skip_serializing_if = "Option::is_none")] thundering: Option<bool>, }, /// Checks for range of value. ValueCheck { /// Number Provider. The value to test. value: NumberProviderValue<isize>, /// The exact value to check, or the range to check the value. range: Ranged<NumberProviderValue<isize>>, }, } /// Specifies the entity to check for the condition. #[derive(Eq, PartialEq, Debug)] #[derive(Derivative, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum WhichEntity { /// The entity that died or the player that gained the advancement. This, /// The killer. Killer, /// A killer that is a player. KillerPlayer, }