Skip to content

Commit 96781f9

Browse files
committed
Fix instantaneous mob effects
1 parent 49c83f3 commit 96781f9

File tree

13 files changed

+340
-127
lines changed

13 files changed

+340
-127
lines changed

src/main/java/cn/nukkit/Player.java

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,7 @@ protected void processMovement(int tickDiff) {
17111711

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

17161716
if (!revert && distanceSquared != 0) {
17171717
double dx = newPos.x - this.x;
@@ -1820,18 +1820,18 @@ protected void processMovement(int tickDiff) {
18201820
if (!revert && (this.isFoodEnabled() || this.getServer().getDifficulty() == 0)) {
18211821
if (this.isSurvivalLike()/* && !this.getRiddingOn() instanceof Entity*/) {
18221822
//UpdateFoodExpLevel
1823-
if (distance >= 0.05) {
1824-
double jump = 0;
1825-
double swimming = this.isInsideOfWater() ? 0.015 * distance : 0;
1823+
if (distance >= 0.05f) {
1824+
float jump = 0;
1825+
float swimming = this.isInsideOfWater() ? 0.015f * distance : 0;
18261826
if (swimming != 0) distance = 0;
18271827
if (this.isSprinting()) { //Running
18281828
if (this.inAirTicks == 3 && swimming == 0) {
1829-
jump = 0.2;
1829+
jump = 0.2f;
18301830
}
1831-
this.getFoodData().updateFoodExpLevel(0.1 * distance + jump + swimming);
1831+
this.getFoodData().updateFoodExpLevel(0.1f * distance + jump + swimming);
18321832
} else {
18331833
if (this.inAirTicks == 3 && swimming == 0) {
1834-
jump = 0.05;
1834+
jump = 0.05f;
18351835
}
18361836
this.getFoodData().updateFoodExpLevel(jump + swimming);
18371837
}
@@ -1928,16 +1928,15 @@ public boolean setMotion(Vector3 motion) {
19281928
}
19291929

19301930
public void sendAttributes() {
1931-
UpdateAttributesPacket pk = new UpdateAttributesPacket();
1932-
pk.entityId = this.getId();
1933-
pk.entries = new Attribute[]{
1931+
this.setAttribute(
19341932
Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getMaxHealth()).setValue(health >= 1 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0),
19351933
Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(this.getFoodData().getLevel()),
1934+
Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(this.getFoodData().getFoodSaturationLevel()),
1935+
Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(this.getFoodData().getExhaustionLevel()),
19361936
movementSpeedAttribute.copy().setValue(movementSpeedAttribute.getModifiedValue()),
19371937
Attribute.getAttribute(Attribute.PLAYER_LEVEL).setValue(this.getExperienceLevel()),
19381938
Attribute.getAttribute(Attribute.PLAYER_EXPERIENCE).setValue(((float) this.getExperience()) / calculateRequireExperience(this.getExperienceLevel()))
1939-
};
1940-
this.dataPacket(pk);
1939+
);
19411940
}
19421941

19431942
@Override
@@ -3573,7 +3572,7 @@ public void onCompletion(Server server) {
35733572

35743573
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) {
35753574
if (this.isSurvival()) {
3576-
this.getFoodData().updateFoodExpLevel(0.005);
3575+
this.getFoodData().updateFoodExpLevel(0.005f);
35773576
if (!i.equals(oldItem) || i.getCount() != oldItem.getCount()) {
35783577
inventory.setItemInHand(i);
35793578
inventory.sendHeldItem(this.getViewers().values());
@@ -4651,27 +4650,28 @@ public void setHealth(float health) {
46514650
}
46524651

46534652
super.setHealth(health);
4654-
//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)
4655-
Attribute attr = Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0);
4656-
if (this.spawned) {
4657-
UpdateAttributesPacket pk = new UpdateAttributesPacket();
4658-
pk.entries = new Attribute[]{attr};
4659-
pk.entityId = this.id;
4660-
this.dataPacket(pk);
4653+
4654+
if (!this.spawned) {
4655+
return;
46614656
}
4657+
4658+
//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)
4659+
this.setAttribute(Attribute.getAttribute(Attribute.HEALTH)
4660+
.setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth())
4661+
.setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0));
46624662
}
46634663

46644664
@Override
46654665
public void setMaxHealth(int maxHealth) {
46664666
super.setMaxHealth(maxHealth);
46674667

4668-
Attribute attr = Attribute.getAttribute(Attribute.HEALTH).setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0);
4669-
if (this.spawned) {
4670-
UpdateAttributesPacket pk = new UpdateAttributesPacket();
4671-
pk.entries = new Attribute[]{attr};
4672-
pk.entityId = this.id;
4673-
this.dataPacket(pk);
4668+
if (!this.spawned) {
4669+
return;
46744670
}
4671+
4672+
this.setAttribute(Attribute.getAttribute(Attribute.HEALTH)
4673+
.setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth())
4674+
.setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0));
46754675
}
46764676

46774677
public int getExperience() {
@@ -4741,10 +4741,10 @@ public void sendExperienceLevel(int level) {
47414741
}
47424742
}
47434743

4744-
public void setAttribute(Attribute attribute) {
4744+
public void setAttribute(Attribute... attribute) {
47454745
UpdateAttributesPacket pk = new UpdateAttributesPacket();
4746-
pk.entries = new Attribute[]{attribute};
4747-
pk.entityId = this.id;
4746+
pk.entries = attribute;
4747+
pk.entityId = this.getId();
47484748
this.dataPacket(pk);
47494749
}
47504750

@@ -4800,7 +4800,7 @@ public boolean attack(EntityDamageEvent source) {
48004800
if (source instanceof EntityDamageByEntityEvent && source.getCause() == DamageCause.ENTITY_ATTACK) {
48014801
Entity damager = ((EntityDamageByEntityEvent) source).getDamager();
48024802
if (damager instanceof Player) {
4803-
((Player) damager).getFoodData().updateFoodExpLevel(0.1);
4803+
((Player) damager).getFoodData().updateFoodExpLevel(0.1f);
48044804
}
48054805

48064806
//Critical hit

src/main/java/cn/nukkit/PlayerFood.java

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,25 @@
66
import cn.nukkit.event.entity.EntityRegainHealthEvent;
77
import cn.nukkit.event.player.PlayerFoodLevelChangeEvent;
88
import cn.nukkit.item.food.Food;
9+
import cn.nukkit.level.GameRule;
910
import cn.nukkit.potion.Effect;
1011

1112
/**
1213
* Created by funcraft on 2015/11/11.
1314
*/
1415
public class PlayerFood {
16+
private static final int MAX_FOOD_LEVEL = 20;
1517

1618
private int foodLevel;
17-
private final int maxFoodLevel;
1819
private float foodSaturationLevel;
19-
private int foodTickTimer = 0;
20-
private double foodExpLevel = 0;
20+
private float exhaustionLevel;
21+
private int foodTickTimer;
2122

2223
private final Player player;
2324

2425
public PlayerFood(Player player, int foodLevel, float foodSaturationLevel) {
2526
this.player = player;
2627
this.foodLevel = foodLevel;
27-
this.maxFoodLevel = 20;
2828
this.foodSaturationLevel = foodSaturationLevel;
2929
}
3030

@@ -37,7 +37,7 @@ public int getLevel() {
3737
}
3838

3939
public int getMaxLevel() {
40-
return this.maxFoodLevel;
40+
return MAX_FOOD_LEVEL;
4141
}
4242

4343
public void setLevel(int foodLevel) {
@@ -62,14 +62,20 @@ public void setLevel(int foodLevel, float saturationLevel) {
6262
PlayerFoodLevelChangeEvent ev = new PlayerFoodLevelChangeEvent(this.getPlayer(), foodLevel, saturationLevel);
6363
this.getPlayer().getServer().getPluginManager().callEvent(ev);
6464
if (ev.isCancelled()) {
65-
this.sendFoodLevel(this.getLevel());
65+
this.sendFoodLevel();
6666
return;
6767
}
6868
int foodLevel0 = ev.getFoodLevel();
6969
float fsl = ev.getFoodSaturationLevel();
7070
if (fsl != -1) {
7171
if (fsl > foodLevel) fsl = foodLevel;
72-
this.foodSaturationLevel = fsl;
72+
if (foodSaturationLevel != fsl) {
73+
this.foodSaturationLevel = fsl;
74+
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel));
75+
}
76+
}
77+
if (this.foodLevel == foodLevel0) {
78+
return;
7379
}
7480
this.foodLevel = foodLevel0;
7581
this.sendFoodLevel();
@@ -88,7 +94,18 @@ public void setFoodSaturationLevel(float fsl) {
8894
return;
8995
}
9096
fsl = ev.getFoodSaturationLevel();
97+
if (foodSaturationLevel == fsl) {
98+
return;
99+
}
91100
this.foodSaturationLevel = fsl;
101+
if (!player.spawned) {
102+
return;
103+
}
104+
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel));
105+
}
106+
107+
public float getExhaustionLevel() {
108+
return this.exhaustionLevel;
92109
}
93110

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

118-
public void sendFoodLevel() {
119-
this.sendFoodLevel(this.getLevel());
120-
}
121-
122135
public void reset() {
123136
this.foodLevel = 20;
124137
this.foodSaturationLevel = 5;
125-
this.foodExpLevel = 0;
138+
this.exhaustionLevel = 0;
126139
this.foodTickTimer = 0;
127-
this.sendFoodLevel();
140+
this.sendAll();
128141
}
129142

130-
public void sendFoodLevel(int foodLevel) {
143+
public void sendFoodLevel() {
131144
if (this.getPlayer().spawned) {
132145
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(foodLevel));
133146
}
134147
}
135148

149+
public void sendAll() {
150+
if (!player.spawned) {
151+
return;
152+
}
153+
player.setAttribute(
154+
Attribute.getAttribute(Attribute.PLAYER_HUNGER).setValue(foodLevel),
155+
Attribute.getAttribute(Attribute.PLAYER_SATURATION).setValue(foodSaturationLevel),
156+
Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(exhaustionLevel)
157+
);
158+
}
159+
136160
public void update(int tickDiff) {
137161
if (!this.getPlayer().isFoodEnabled()) return;
138162
if (this.getPlayer().isAlive()) {
139163
int diff = Server.getInstance().getDifficulty();
140164
if (this.getLevel() > 17) {
141165
this.foodTickTimer += tickDiff;
142166
if (this.foodTickTimer >= 80) {
143-
if (this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) {
167+
if (player.level.gameRules.getBoolean(GameRule.NATURAL_REGENERATION) && this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) {
144168
EntityRegainHealthEvent ev = new EntityRegainHealthEvent(this.getPlayer(), 1, EntityRegainHealthEvent.CAUSE_EATING);
145169
this.getPlayer().heal(ev);
146-
//this.updateFoodExpLevel(3);
170+
171+
this.updateFoodExpLevel(3);
147172
}
148173
this.foodTickTimer = 0;
149174
}
150-
} else if (this.getLevel() == 0) {
175+
} else if (this.getLevel() <= 0) {
151176
this.foodTickTimer += tickDiff;
152177
if (this.foodTickTimer >= 80) {
153178
EntityDamageEvent ev = new EntityDamageEvent(this.getPlayer(), DamageCause.HUNGER, 1);
@@ -159,26 +184,39 @@ public void update(int tickDiff) {
159184
} else {
160185
this.getPlayer().attack(ev);
161186
}
162-
163187
this.foodTickTimer = 0;
164188
}
189+
} else {
190+
this.foodTickTimer = 0;
165191
}
192+
166193
Effect hunger = this.getPlayer().getEffect(Effect.HUNGER);
167194
if (hunger != null) {
168-
this.updateFoodExpLevel(0.1 * (hunger.getAmplifier() + 1));
195+
this.updateFoodExpLevel(0.005f * (hunger.getAmplifier() + 1));
169196
}
170197
}
171198
}
172199

173-
public void updateFoodExpLevel(double use) {
200+
/**
201+
* add exhaustion
202+
*/
203+
public void updateFoodExpLevel(float use) {
174204
if (!this.getPlayer().isFoodEnabled()) return;
175205
if (Server.getInstance().getDifficulty() == 0) return;
176206
if (this.getPlayer().hasEffect(Effect.SATURATION)) return;
177-
this.foodExpLevel += use;
178-
if (this.foodExpLevel > 4) {
207+
float lastExhaustionLevel = exhaustionLevel;
208+
this.exhaustionLevel += use;
209+
if (this.exhaustionLevel > 4) {
179210
this.useHunger(1);
180-
this.foodExpLevel = 0;
211+
this.exhaustionLevel = 0;
212+
}
213+
if (lastExhaustionLevel == exhaustionLevel) {
214+
return;
215+
}
216+
if (!player.spawned) {
217+
return;
181218
}
219+
this.getPlayer().setAttribute(Attribute.getAttribute(Attribute.PLAYER_EXHAUSTION).setValue(exhaustionLevel));
182220
}
183221

184222
/**

src/main/java/cn/nukkit/command/defaults/EffectCommand.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,17 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args)
6565
}
6666
return result;
6767
});
68-
int durationSec = Math.min(parser.parseIntOrDefault(effect.isInstantaneous() ? 1 : 30, 0), 1000000);
68+
int durationSec = Math.min(parser.parseIntOrDefault(30, 0), 1000000);
6969
int amplifier = parser.parseIntOrDefault(0, 0, 255);
7070
boolean hideParticle = parser.parseBooleanOrDefault(false);
7171

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

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

9190
if (durationSec != 0) {
9291
targets.forEach(entity -> {
93-
if (effect.isInstantaneous()) {
94-
effect.applyEffect(entity);
95-
} else {
96-
entity.addEffect(effect.clone());
97-
}
92+
entity.addEffect(effect.clone());
9893
broadcastCommandMessage(sender, new TranslationContainer("commands.effect.success", effect.getName(), amplifier, entity.getName(), durationSec));
9994
});
10095
} else {

src/main/java/cn/nukkit/command/exceptions/CommandSyntaxException.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,14 @@ public class CommandSyntaxException extends RuntimeException {
88
CommandSyntaxException(String message) {
99
super(message, null, false, false);
1010
}
11+
12+
@Override
13+
public Throwable fillInStackTrace() {
14+
return this;
15+
}
16+
17+
@Override
18+
public Throwable initCause(Throwable cause) {
19+
return this;
20+
}
1121
}

0 commit comments

Comments
 (0)