Skip to content

Commit

Permalink
Fix instantaneous mob effects
Browse files Browse the repository at this point in the history
  • Loading branch information
wode490390 committed Feb 24, 2024
1 parent 49c83f3 commit 96781f9
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 127 deletions.
60 changes: 30 additions & 30 deletions src/main/java/cn/nukkit/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -1711,7 +1711,7 @@ protected void processMovement(int tickDiff) {

double tdx = newPos.x - this.x;
double tdz = newPos.z - this.z;
double distance = Math.sqrt(tdx * tdx + tdz * tdz);
float distance = (float) Math.sqrt(tdx * tdx + tdz * tdz);

if (!revert && distanceSquared != 0) {
double dx = newPos.x - this.x;
Expand Down Expand Up @@ -1820,18 +1820,18 @@ protected void processMovement(int tickDiff) {
if (!revert && (this.isFoodEnabled() || this.getServer().getDifficulty() == 0)) {
if (this.isSurvivalLike()/* && !this.getRiddingOn() instanceof Entity*/) {
//UpdateFoodExpLevel
if (distance >= 0.05) {
double jump = 0;
double swimming = this.isInsideOfWater() ? 0.015 * distance : 0;
if (distance >= 0.05f) {
float jump = 0;
float swimming = this.isInsideOfWater() ? 0.015f * distance : 0;
if (swimming != 0) distance = 0;
if (this.isSprinting()) { //Running
if (this.inAirTicks == 3 && swimming == 0) {
jump = 0.2;
jump = 0.2f;
}
this.getFoodData().updateFoodExpLevel(0.1 * distance + jump + swimming);
this.getFoodData().updateFoodExpLevel(0.1f * distance + jump + swimming);
} else {
if (this.inAirTicks == 3 && swimming == 0) {
jump = 0.05;
jump = 0.05f;
}
this.getFoodData().updateFoodExpLevel(jump + swimming);
}
Expand Down Expand Up @@ -1928,16 +1928,15 @@ public boolean setMotion(Vector3 motion) {
}

public void sendAttributes() {
UpdateAttributesPacket pk = new UpdateAttributesPacket();
pk.entityId = this.getId();
pk.entries = new Attribute[]{
this.setAttribute(
Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getMaxHealth()).setValue(health >= 1 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0),
Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(this.getFoodData().getLevel()),
Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(this.getFoodData().getFoodSaturationLevel()),
Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(this.getFoodData().getExhaustionLevel()),
movementSpeedAttribute.copy().setValue(movementSpeedAttribute.getModifiedValue()),
Attribute.getAttribute(Attribute.PLAYER_LEVEL).setValue(this.getExperienceLevel()),
Attribute.getAttribute(Attribute.PLAYER_EXPERIENCE).setValue(((float) this.getExperience()) / calculateRequireExperience(this.getExperienceLevel()))
};
this.dataPacket(pk);
);
}

@Override
Expand Down Expand Up @@ -3573,7 +3572,7 @@ public void onCompletion(Server server) {

if (this.canInteract(blockVector.add(0.5, 0.5, 0.5), this.isCreative() ? 16 : 8) && (i = this.level.useBreakOn(blockVector.asVector3(), i, this, true)) != null) {
if (this.isSurvival()) {
this.getFoodData().updateFoodExpLevel(0.005);
this.getFoodData().updateFoodExpLevel(0.005f);
if (!i.equals(oldItem) || i.getCount() != oldItem.getCount()) {
inventory.setItemInHand(i);
inventory.sendHeldItem(this.getViewers().values());
Expand Down Expand Up @@ -4651,27 +4650,28 @@ public void setHealth(float health) {
}

super.setHealth(health);
//TODO: Remove it in future! This a hack to solve the client-side absorption bug! WFT Mojang (Half a yellow heart cannot be shown, we can test it in local gaming)
Attribute attr = Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0);
if (this.spawned) {
UpdateAttributesPacket pk = new UpdateAttributesPacket();
pk.entries = new Attribute[]{attr};
pk.entityId = this.id;
this.dataPacket(pk);

if (!this.spawned) {
return;
}

//TODO: Remove it in future! This a hack to solve the client-side absorption bug! WFT Mojang (Half a yellow heart cannot be shown, we can test it in local gaming)
this.setAttribute(Attribute.getAttribute(Attribute.HEALTH)
.setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth())
.setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0));
}

@Override
public void setMaxHealth(int maxHealth) {
super.setMaxHealth(maxHealth);

Attribute attr = Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0);
if (this.spawned) {
UpdateAttributesPacket pk = new UpdateAttributesPacket();
pk.entries = new Attribute[]{attr};
pk.entityId = this.id;
this.dataPacket(pk);
if (!this.spawned) {
return;
}

this.setAttribute(Attribute.getAttribute(Attribute.HEALTH)
.setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth())
.setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0));
}

public int getExperience() {
Expand Down Expand Up @@ -4741,10 +4741,10 @@ public void sendExperienceLevel(int level) {
}
}

public void setAttribute(Attribute attribute) {
public void setAttribute(Attribute... attribute) {
UpdateAttributesPacket pk = new UpdateAttributesPacket();
pk.entries = new Attribute[]{attribute};
pk.entityId = this.id;
pk.entries = attribute;
pk.entityId = this.getId();
this.dataPacket(pk);
}

Expand Down Expand Up @@ -4800,7 +4800,7 @@ public boolean attack(EntityDamageEvent source) {
if (source instanceof EntityDamageByEntityEvent && source.getCause() == DamageCause.ENTITY_ATTACK) {
Entity damager = ((EntityDamageByEntityEvent) source).getDamager();
if (damager instanceof Player) {
((Player) damager).getFoodData().updateFoodExpLevel(0.1);
((Player) damager).getFoodData().updateFoodExpLevel(0.1f);
}

//Critical hit
Expand Down
84 changes: 61 additions & 23 deletions src/main/java/cn/nukkit/PlayerFood.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
import cn.nukkit.event.entity.EntityRegainHealthEvent;
import cn.nukkit.event.player.PlayerFoodLevelChangeEvent;
import cn.nukkit.item.food.Food;
import cn.nukkit.level.GameRule;
import cn.nukkit.potion.Effect;

/**
* Created by funcraft on 2015/11/11.
*/
public class PlayerFood {
private static final int MAX_FOOD_LEVEL = 20;

private int foodLevel;
private final int maxFoodLevel;
private float foodSaturationLevel;
private int foodTickTimer = 0;
private double foodExpLevel = 0;
private float exhaustionLevel;
private int foodTickTimer;

private final Player player;

public PlayerFood(Player player, int foodLevel, float foodSaturationLevel) {
this.player = player;
this.foodLevel = foodLevel;
this.maxFoodLevel = 20;
this.foodSaturationLevel = foodSaturationLevel;
}

Expand All @@ -37,7 +37,7 @@ public int getLevel() {
}

public int getMaxLevel() {
return this.maxFoodLevel;
return MAX_FOOD_LEVEL;
}

public void setLevel(int foodLevel) {
Expand All @@ -62,14 +62,20 @@ public void setLevel(int foodLevel, float saturationLevel) {
PlayerFoodLevelChangeEvent ev = new PlayerFoodLevelChangeEvent(this.getPlayer(), foodLevel, saturationLevel);
this.getPlayer().getServer().getPluginManager().callEvent(ev);
if (ev.isCancelled()) {
this.sendFoodLevel(this.getLevel());
this.sendFoodLevel();
return;
}
int foodLevel0 = ev.getFoodLevel();
float fsl = ev.getFoodSaturationLevel();
if (fsl != -1) {
if (fsl > foodLevel) fsl = foodLevel;
this.foodSaturationLevel = fsl;
if (foodSaturationLevel != fsl) {
this.foodSaturationLevel = fsl;
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel));
}
}
if (this.foodLevel == foodLevel0) {
return;
}
this.foodLevel = foodLevel0;
this.sendFoodLevel();
Expand All @@ -88,7 +94,18 @@ public void setFoodSaturationLevel(float fsl) {
return;
}
fsl = ev.getFoodSaturationLevel();
if (foodSaturationLevel == fsl) {
return;
}
this.foodSaturationLevel = fsl;
if (!player.spawned) {
return;
}
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel));
}

public float getExhaustionLevel() {
return this.exhaustionLevel;
}

public void useHunger() {
Expand All @@ -115,39 +132,47 @@ public void addFoodLevel(int foodLevel, float fsl) {
this.setLevel(this.getLevel() + foodLevel, this.getFoodSaturationLevel() + fsl);
}

public void sendFoodLevel() {
this.sendFoodLevel(this.getLevel());
}

public void reset() {
this.foodLevel = 20;
this.foodSaturationLevel = 5;
this.foodExpLevel = 0;
this.exhaustionLevel = 0;
this.foodTickTimer = 0;
this.sendFoodLevel();
this.sendAll();
}

public void sendFoodLevel(int foodLevel) {
public void sendFoodLevel() {
if (this.getPlayer().spawned) {
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(foodLevel));
}
}

public void sendAll() {
if (!player.spawned) {
return;
}
player.setAttribute(
Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(foodLevel),
Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel),
Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(exhaustionLevel)
);
}

public void update(int tickDiff) {
if (!this.getPlayer().isFoodEnabled()) return;
if (this.getPlayer().isAlive()) {
int diff = Server.getInstance().getDifficulty();
if (this.getLevel() > 17) {
this.foodTickTimer += tickDiff;
if (this.foodTickTimer >= 80) {
if (this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) {
if (player.level.gameRules.getBoolean(GameRule.NATURAL_REGENERATION) && this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) {
EntityRegainHealthEvent ev = new EntityRegainHealthEvent(this.getPlayer(), 1, EntityRegainHealthEvent.CAUSE_EATING);
this.getPlayer().heal(ev);
//this.updateFoodExpLevel(3);

this.updateFoodExpLevel(3);
}
this.foodTickTimer = 0;
}
} else if (this.getLevel() == 0) {
} else if (this.getLevel() <= 0) {
this.foodTickTimer += tickDiff;
if (this.foodTickTimer >= 80) {
EntityDamageEvent ev = new EntityDamageEvent(this.getPlayer(), DamageCause.HUNGER, 1);
Expand All @@ -159,26 +184,39 @@ public void update(int tickDiff) {
} else {
this.getPlayer().attack(ev);
}

this.foodTickTimer = 0;
}
} else {
this.foodTickTimer = 0;
}

Effect hunger = this.getPlayer().getEffect(Effect.HUNGER);
if (hunger != null) {
this.updateFoodExpLevel(0.1 * (hunger.getAmplifier() + 1));
this.updateFoodExpLevel(0.005f * (hunger.getAmplifier() + 1));
}
}
}

public void updateFoodExpLevel(double use) {
/**
* add exhaustion
*/
public void updateFoodExpLevel(float use) {
if (!this.getPlayer().isFoodEnabled()) return;
if (Server.getInstance().getDifficulty() == 0) return;
if (this.getPlayer().hasEffect(Effect.SATURATION)) return;
this.foodExpLevel += use;
if (this.foodExpLevel > 4) {
float lastExhaustionLevel = exhaustionLevel;
this.exhaustionLevel += use;
if (this.exhaustionLevel > 4) {
this.useHunger(1);
this.foodExpLevel = 0;
this.exhaustionLevel = 0;
}
if (lastExhaustionLevel == exhaustionLevel) {
return;
}
if (!player.spawned) {
return;
}
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(exhaustionLevel));
}

/**
Expand Down
11 changes: 3 additions & 8 deletions src/main/java/cn/nukkit/command/defaults/EffectCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,17 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args)
}
return result;
});
int durationSec = Math.min(parser.parseIntOrDefault(effect.isInstantaneous() ? 1 : 30, 0), 1000000);
int durationSec = Math.min(parser.parseIntOrDefault(30, 0), 1000000);
int amplifier = parser.parseIntOrDefault(0, 0, 255);
boolean hideParticle = parser.parseBooleanOrDefault(false);

if (effect.getId() == EffectID.NO_EFFECT) {
targets.forEach(entity -> {
if (entity.getEffects().isEmpty()) {
if (!entity.removeAllEffects()) {
sender.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.effect.failure.notActive.all", entity.getName()));
return;
}

entity.removeAllEffects();
broadcastCommandMessage(sender, new TranslationContainer("commands.effect.success.removed.all", entity.getName()));
});
return true;
Expand All @@ -90,11 +89,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args)

if (durationSec != 0) {
targets.forEach(entity -> {
if (effect.isInstantaneous()) {
effect.applyEffect(entity);
} else {
entity.addEffect(effect.clone());
}
entity.addEffect(effect.clone());
broadcastCommandMessage(sender, new TranslationContainer("commands.effect.success", effect.getName(), amplifier, entity.getName(), durationSec));
});
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,14 @@ public class CommandSyntaxException extends RuntimeException {
CommandSyntaxException(String message) {
super(message, null, false, false);
}

@Override
public Throwable fillInStackTrace() {
return this;
}

@Override
public Throwable initCause(Throwable cause) {
return this;
}
}
Loading

0 comments on commit 96781f9

Please sign in to comment.