SPIGOT-7300, #1180: Add new DamageSource API providing enhanced information about entity damage

By: Doc <nachito94@msn.com>
This commit is contained in:
CraftBukkit/Spigot
2024-02-11 09:54:25 +11:00
parent db4af65c2e
commit 49b5ee78bb
29 changed files with 640 additions and 310 deletions

View File

@@ -0,0 +1,37 @@
package org.bukkit.craftbukkit.damage;
import net.minecraft.world.damagesource.DamageEffects;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.CraftSound;
import org.bukkit.damage.DamageEffect;
public class CraftDamageEffect implements DamageEffect {
private final DamageEffects damageEffects;
public CraftDamageEffect(DamageEffects damageEffects) {
this.damageEffects = damageEffects;
}
public DamageEffects getHandle() {
return this.damageEffects;
}
@Override
public Sound getSound() {
return CraftSound.minecraftToBukkit(this.getHandle().sound());
}
public static DamageEffect getById(String id) {
for (DamageEffects damageEffects : DamageEffects.values()) {
if (damageEffects.getSerializedName().equalsIgnoreCase(id)) {
return toBukkit(damageEffects);
}
}
return null;
}
public static DamageEffect toBukkit(DamageEffects damageEffects) {
return new CraftDamageEffect(damageEffects);
}
}

View File

@@ -0,0 +1,128 @@
package org.bukkit.craftbukkit.damage;
import java.util.Objects;
import net.minecraft.world.phys.Vec3D;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.Entity;
public class CraftDamageSource implements DamageSource {
private final net.minecraft.world.damagesource.DamageSource damageSource;
private final DamageType damageType;
public CraftDamageSource(net.minecraft.world.damagesource.DamageSource damageSource) {
this.damageSource = damageSource;
this.damageType = CraftDamageType.minecraftHolderToBukkit(damageSource.typeHolder());
}
public net.minecraft.world.damagesource.DamageSource getHandle() {
return this.damageSource;
}
public World getCausingEntityWorld() {
org.bukkit.entity.Entity causingEntity = getCausingEntity();
return causingEntity != null ? causingEntity.getWorld() : null;
}
public Block getDirectBlock() {
return this.getHandle().getDirectBlock();
}
@Override
public DamageType getDamageType() {
return this.damageType;
}
@Override
public org.bukkit.entity.Entity getCausingEntity() {
net.minecraft.world.entity.Entity entity = this.getHandle().getCausingEntity();
return (entity != null) ? entity.getBukkitEntity() : null;
}
@Override
public org.bukkit.entity.Entity getDirectEntity() {
net.minecraft.world.entity.Entity entity = this.getHandle().getDirectEntity();
return (entity != null) ? entity.getBukkitEntity() : null;
}
@Override
public Location getDamageLocation() {
Vec3D vec3D = this.getHandle().sourcePositionRaw();
return (vec3D != null) ? CraftLocation.toBukkit(vec3D, this.getCausingEntityWorld()) : null;
}
@Override
public Location getSourceLocation() {
Vec3D vec3D = this.getHandle().getSourcePosition();
return (vec3D != null) ? CraftLocation.toBukkit(vec3D, this.getCausingEntityWorld()) : null;
}
@Override
public boolean isIndirect() {
return this.getHandle().getCausingEntity() != this.getHandle().getDirectEntity();
}
@Override
public float getFoodExhaustion() {
return this.damageType.getExhaustion();
}
@Override
public boolean scalesWithDifficulty() {
return this.getHandle().scalesWithDifficulty();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof DamageSource)) {
return false;
}
DamageSource other = (DamageSource) obj;
return Objects.equals(this.getDamageType(), other.getDamageType()) && Objects.equals(this.getCausingEntity(), other.getCausingEntity())
&& Objects.equals(this.getDirectEntity(), other.getDirectEntity()) && Objects.equals(this.getDamageLocation(), other.getDamageLocation());
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + this.damageType.hashCode();
result = 31 * result + (this.getCausingEntity() != null ? this.getCausingEntity().hashCode() : 0);
result = 31 * result + (this.getDirectEntity() != null ? this.getDirectEntity().hashCode() : 0);
result = 31 * result + (this.getDamageLocation() != null ? this.getDamageLocation().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "DamageSource{damageType=" + this.getDamageType() + ",causingEntity=" + this.getCausingEntity() + ",directEntity=" + this.getDirectEntity() + ",damageLocation=" + this.getDamageLocation() + "}";
}
public static DamageSource buildFromBukkit(DamageType damageType, Entity causingEntity, Entity directEntity, Location damageLocation) {
net.minecraft.core.Holder<net.minecraft.world.damagesource.DamageType> holderDamageType = CraftDamageType.bukkitToMinecraftHolder(damageType);
net.minecraft.world.entity.Entity nmsCausingEntity = null;
if (causingEntity instanceof CraftEntity craftCausingEntity) {
nmsCausingEntity = craftCausingEntity.getHandle();
}
net.minecraft.world.entity.Entity nmsDirectEntity = null;
if (directEntity instanceof CraftEntity craftDirectEntity) {
nmsDirectEntity = craftDirectEntity.getHandle();
}
Vec3D vec3D = (damageLocation == null) ? null : CraftLocation.toVec3D(damageLocation);
return new CraftDamageSource(new net.minecraft.world.damagesource.DamageSource(holderDamageType, nmsDirectEntity, nmsCausingEntity, vec3D));
}
}

View File

@@ -0,0 +1,46 @@
package org.bukkit.craftbukkit.damage;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.Entity;
public class CraftDamageSourceBuilder implements DamageSource.Builder {
private final DamageType damageType;
private Entity causingEntity;
private Entity directEntity;
private Location damageLocation;
public CraftDamageSourceBuilder(DamageType damageType) {
Preconditions.checkArgument(damageType != null, "DamageType cannot be null");
this.damageType = damageType;
}
@Override
public DamageSource.Builder withCausingEntity(Entity entity) {
Preconditions.checkArgument(entity != null, "Entity cannot be null");
this.causingEntity = entity;
return this;
}
@Override
public DamageSource.Builder withDirectEntity(Entity entity) {
Preconditions.checkArgument(entity != null, "Entity cannot be null");
this.directEntity = entity;
return this;
}
@Override
public DamageSource.Builder withDamageLocation(Location location) {
Preconditions.checkArgument(location != null, "Location cannot be null");
this.damageLocation = location.clone();
return this;
}
@Override
public DamageSource build() {
return CraftDamageSource.buildFromBukkit(damageType, causingEntity, directEntity, damageLocation);
}
}

View File

@@ -0,0 +1,126 @@
package org.bukkit.craftbukkit.damage;
import com.google.common.base.Preconditions;
import net.minecraft.core.Holder;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.damage.DamageEffect;
import org.bukkit.damage.DamageScaling;
import org.bukkit.damage.DamageType;
import org.bukkit.damage.DeathMessageType;
public class CraftDamageType implements DamageType, Handleable<net.minecraft.world.damagesource.DamageType> {
private final NamespacedKey key;
private final net.minecraft.world.damagesource.DamageType damageType;
public CraftDamageType(NamespacedKey key, net.minecraft.world.damagesource.DamageType damageType) {
this.key = key;
this.damageType = damageType;
}
@Override
public net.minecraft.world.damagesource.DamageType getHandle() {
return this.damageType;
}
@Override
public String getTranslationKey() {
return this.getHandle().msgId();
}
@Override
public DamageScaling getDamageScaling() {
return damageScalingToBukkit(this.getHandle().scaling());
}
@Override
public DamageEffect getDamageEffect() {
return CraftDamageEffect.toBukkit(this.getHandle().effects());
}
@Override
public DeathMessageType getDeathMessageType() {
return deathMessageTypeToBukkit(this.getHandle().deathMessageType());
}
@Override
public float getExhaustion() {
return this.getHandle().exhaustion();
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public String toString() {
return "CraftDamageType{" + "key=" + this.getKey() + ",damageScaling=" + this.getDamageScaling() + ",damageEffect=" + this.getDamageEffect() + ",deathMessageType=" + this.getDeathMessageType() + ",exhaustion=" + this.getExhaustion() + "}";
}
public static DeathMessageType deathMessageTypeToBukkit(net.minecraft.world.damagesource.DeathMessageType deathMessageType) {
return switch (deathMessageType) {
case DEFAULT -> DeathMessageType.DEFAULT;
case FALL_VARIANTS -> DeathMessageType.FALL_VARIANTS;
case INTENTIONAL_GAME_DESIGN -> DeathMessageType.INTENTIONAL_GAME_DESIGN;
default -> throw new IllegalArgumentException("NMS DeathMessageType." + deathMessageType + " cannot be converted to a Bukkit DeathMessageType.");
};
}
public static net.minecraft.world.damagesource.DeathMessageType deathMessageTypeToNMS(DeathMessageType deathMessageType) {
return switch (deathMessageType) {
case DEFAULT -> net.minecraft.world.damagesource.DeathMessageType.DEFAULT;
case FALL_VARIANTS -> net.minecraft.world.damagesource.DeathMessageType.FALL_VARIANTS;
case INTENTIONAL_GAME_DESIGN -> net.minecraft.world.damagesource.DeathMessageType.INTENTIONAL_GAME_DESIGN;
default -> throw new IllegalArgumentException("Bukkit DeathMessageType." + deathMessageType + " cannot be converted to a NMS DeathMessageType.");
};
}
public static DamageScaling damageScalingToBukkit(net.minecraft.world.damagesource.DamageScaling damageScaling) {
return switch (damageScaling) {
case ALWAYS -> DamageScaling.ALWAYS;
case WHEN_CAUSED_BY_LIVING_NON_PLAYER -> DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER;
case NEVER -> DamageScaling.NEVER;
default -> throw new IllegalArgumentException("NMS DamageScaling." + damageScaling + " cannot be converted to a Bukkit DamageScaling");
};
}
public static net.minecraft.world.damagesource.DamageScaling damageScalingToNMS(DamageScaling damageScaling) {
return switch (damageScaling) {
case ALWAYS -> net.minecraft.world.damagesource.DamageScaling.ALWAYS;
case WHEN_CAUSED_BY_LIVING_NON_PLAYER -> net.minecraft.world.damagesource.DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER;
case NEVER -> net.minecraft.world.damagesource.DamageScaling.NEVER;
default -> throw new IllegalArgumentException("Bukkit DamageScaling." + damageScaling + " cannot be converted to a NMS DamageScaling");
};
}
public static DamageType minecraftHolderToBukkit(Holder<net.minecraft.world.damagesource.DamageType> minecraftHolder) {
return minecraftToBukkit(minecraftHolder.value());
}
public static Holder<net.minecraft.world.damagesource.DamageType> bukkitToMinecraftHolder(DamageType bukkitDamageType) {
Preconditions.checkArgument(bukkitDamageType != null);
IRegistry<net.minecraft.world.damagesource.DamageType> registry = CraftRegistry.getMinecraftRegistry(Registries.DAMAGE_TYPE);
if (registry.wrapAsHolder(bukkitToMinecraft(bukkitDamageType)) instanceof Holder.c<net.minecraft.world.damagesource.DamageType> holder) {
return holder;
}
throw new IllegalArgumentException("No Reference holder found for " + bukkitDamageType
+ ", this can happen if a plugin creates its own damage type with out properly registering it.");
}
public static net.minecraft.world.damagesource.DamageType bukkitToMinecraft(DamageType bukkitDamageType) {
return CraftRegistry.bukkitToMinecraft(bukkitDamageType);
}
public static DamageType minecraftToBukkit(net.minecraft.world.damagesource.DamageType minecraftDamageType) {
return CraftRegistry.minecraftToBukkit(minecraftDamageType, Registries.DAMAGE_TYPE, Registry.DAMAGE_TYPE);
}
}