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 176 177 178 179 180 181 182 183 184 185 186
use std::fmt;
use crate::item_id::ItemId;
/// Identifies a specific scoreboard
///
/// Debris has one main scoreboard and an arbitrary amount of custom scoreboards
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum Scoreboard {
/// The Main scoreboard, where all operations are per default
Main,
/// Custom scoreboards, each with a unique identifier
Custom(usize),
/// Special scoreboards used for internal tracking
Internal(usize),
}
impl fmt::Display for Scoreboard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Scoreboard::Main => write!(f, "Main"),
Scoreboard::Custom(id) => write!(f, "{id}"),
Scoreboard::Internal(id) => write!(f, "internal({id})"),
}
}
}
/// A Value that can be stored on a scoreboard
///
/// Either a real scoreboard value or a static number
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ScoreboardValue {
Static(i32),
Scoreboard(ItemId),
}
impl ScoreboardValue {
pub fn id(&self) -> Option<&ItemId> {
match self {
ScoreboardValue::Static(_) => None,
ScoreboardValue::Scoreboard(id) => Some(id),
}
}
}
impl fmt::Display for ScoreboardValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ScoreboardValue::Static(static_value) => write!(f, "{static_value}"),
ScoreboardValue::Scoreboard(id) => write!(f, "{id}"),
}
}
}
/// Any operation that can be executed on a scoreboard-
/// This excludes copy, because scoreboard operations are assumed
/// to be trinary (a = b OP c), but copy is only a binary
/// Operation.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ScoreboardOperation {
Plus,
Minus,
Times,
Divide,
Modulo,
Min,
Max,
}
impl ScoreboardOperation {
pub fn str_value(&self) -> &'static str {
use ScoreboardOperation::*;
match self {
Plus => "+",
Minus => "-",
Times => "*",
Divide => "/",
Modulo => "%",
Min => "min",
Max => "max",
}
}
}
impl ScoreboardOperation {
pub fn evaluate(&self, lhs: i32, rhs: i32) -> i32 {
use ScoreboardOperation::*;
match self {
Min => i32::min(lhs, rhs),
Max => i32::max(lhs, rhs),
Plus => lhs.wrapping_add(rhs),
Minus => lhs.wrapping_sub(rhs),
Times => lhs.wrapping_mul(rhs),
Divide => {
// Minecraft does not modify the lhs value on division by zero
if rhs == 0 {
lhs
} else {
// Minecraft rounds towards -infinity, while rust rounds towards 0
let nat_div = lhs.wrapping_div(rhs);
let Some(prod) = rhs.checked_mul(nat_div) else {
return nat_div;
};
if lhs != prod && (lhs >= 0) != (rhs >= 0) {
nat_div - 1
} else {
nat_div
}
}
}
Modulo => {
// If b is 0 minecraft throws an exception and does nothing to a
if rhs == 0 {
lhs
} else {
// Minecraft rounds towards -infinity, while rust rounds towards 0
lhs.checked_rem(rhs).unwrap_or(0).abs()
}
}
}
}
}
/// Any comparison that can be executed on two scoreboard values
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ScoreboardComparison {
Equal,
NotEqual,
Greater,
GreaterOrEqual,
Less,
LessOrEqual,
}
impl ScoreboardComparison {
/// Flips the comparison (converts OP such that `a OP b == b OP.flip_sides() a`)
pub fn flip_sides(&self) -> ScoreboardComparison {
use ScoreboardComparison::*;
match self {
Equal => Equal,
NotEqual => NotEqual,
Greater => Less,
GreaterOrEqual => LessOrEqual,
Less => Greater,
LessOrEqual => GreaterOrEqual,
}
}
/// Inverts the comparison, such that it is exactly and only then true
/// when the original comparison is false
pub fn invert(&self) -> ScoreboardComparison {
use ScoreboardComparison::*;
match self {
Equal => NotEqual,
NotEqual => Equal,
Greater => LessOrEqual,
GreaterOrEqual => Less,
Less => GreaterOrEqual,
LessOrEqual => Greater,
}
}
pub fn evaluate(&self, lhs: i32, rhs: i32) -> bool {
use ScoreboardComparison::*;
match self {
Equal => lhs == rhs,
NotEqual => lhs != rhs,
Greater => lhs > rhs,
GreaterOrEqual => lhs >= rhs,
Less => lhs < rhs,
LessOrEqual => lhs <= rhs,
}
}
pub fn str_value(&self) -> &'static str {
match self {
ScoreboardComparison::Equal => "==",
ScoreboardComparison::NotEqual => "!=",
ScoreboardComparison::Greater => ">",
ScoreboardComparison::GreaterOrEqual => ">=",
ScoreboardComparison::Less => "<",
ScoreboardComparison::LessOrEqual => "<=",
}
}
}