Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feeding baby animals accelerate their growth #907

Merged
merged 9 commits into from Apr 29, 2018
37 changes: 28 additions & 9 deletions src/main/java/net/glowstone/entity/GlowAgeable.java
Expand Up @@ -134,10 +134,11 @@ protected final void setScale(float scale) {

@Override
public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) {
super.entityInteract(player, message);
if (message.getAction() == InteractEntityMessage.Action.INTERACT.ordinal()) {
if (!super.entityInteract(player, message)
&& message.getAction() == InteractEntityMessage.Action.INTERACT.ordinal()) {
ItemStack item = InventoryUtil
.itemOrEmpty(player.getInventory().getItem(message.getHandSlot()));
int growthAmount = computeGrowthAmount(item.getType());

// Spawn eggs are used to spawn babies
if (item.getType() == Material.MONSTER_EGG && item.hasItemMeta()) {
Expand All @@ -147,16 +148,14 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message)

if (player.getGameMode() == GameMode.SURVIVAL
|| player.getGameMode() == GameMode.ADVENTURE) {
// Consume the egg
if (item.getAmount() > 1) {
item.setAmount(item.getAmount() - 1);
} else {
player.getInventory()
.setItem(message.getHandSlot(), InventoryUtil.createEmptyStack());
}
player.getInventory().consumeItemInMainHand();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get the hand slot that was used from the message data

}
return true;
}
} else if (growthAmount > 0) {
grow(growthAmount);
player.getInventory().consumeItemInMainHand();
return true;
}
}
return false;
Expand Down Expand Up @@ -184,4 +183,24 @@ protected float getSoundPitch() {
}
return super.getSoundPitch();
}

/**
* Grows an ageable creature.
*
* @param age The age to add to the ageable creature.
*/
public void grow(int age) {
setAge(this.age + age);
}

/**
* Computes the growth amount using a specific material for the current ageable creature.
* Always returns 0 for an adult or if the material is not food for the creature.
*
* @param material The food used to compute the growth amount.
* @return The age gained using the given food.
*/
protected int computeGrowthAmount(Material material) {
return 0;
}
}
16 changes: 13 additions & 3 deletions src/main/java/net/glowstone/entity/GlowAnimal.java
Expand Up @@ -45,9 +45,8 @@ protected int getAmbientDelay() {

@Override
public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) {
super.entityInteract(player, message);

if (message.getAction() == InteractEntityMessage.Action.INTERACT.ordinal()) {
if (!super.entityInteract(player, message)
&& message.getAction() == InteractEntityMessage.Action.INTERACT.ordinal()) {
ItemStack item = InventoryUtil
.itemOrEmpty(player.getInventory().getItem(message.getHandSlot()));

Expand All @@ -60,7 +59,9 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message)
&& getBreedingFoods().contains(item.getType())) {
// TODO set love mode if possible and spawn particles
// TODO heal
// TODO only consume the item if the animal is healed or something else
player.getInventory().consumeItemInMainHand();
return true;
}
}

Expand All @@ -74,4 +75,13 @@ && getBreedingFoods().contains(item.getType())) {
public Set<Material> getBreedingFoods() {
return DEFAULT_BREEDING_FOODS;
}

@Override
protected int computeGrowthAmount(Material material) {
if (!isAdult() && getBreedingFoods().contains(material)) {
return Math.abs(getAge() / 10);
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else statement is redundant because of the return statement.

return 0;
}
}
}
31 changes: 29 additions & 2 deletions src/main/java/net/glowstone/entity/passive/GlowAbstractHorse.java
@@ -1,8 +1,10 @@
package net.glowstone.entity.passive;

import com.flowpowered.network.Message;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -15,13 +17,22 @@
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.inventory.HorseInventory;

public abstract class GlowAbstractHorse extends GlowTameable implements AbstractHorse {

private static final Set<Material> BREEDING_FOODS = Sets.immutableEnumSet(Material.GOLDEN_APPLE,
Material.GOLDEN_CARROT);

private static final Map<Material, Integer> GROWING_FOODS = ImmutableMap
.<Material, Integer>builder()
.put(Material.SUGAR, 600)
.put(Material.WHEAT, 400)
.put(Material.APPLE, 1200)
.put(Material.GOLDEN_CARROT, 1200)
.put(Material.GOLDEN_APPLE, 4800)
.put(Material.HAY_BLOCK, 3600)
.build();

@Getter
@Setter
private int domestication;
Expand Down Expand Up @@ -67,7 +78,7 @@ private int getHorseFlags() {
}
if (this instanceof GlowHorse) {
GlowHorse horse = (GlowHorse) this;
if (getInventory() != null && ((HorseInventory) getInventory()).getSaddle() != null) {
if (getInventory() != null && getInventory().getSaddle() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace the null check for the saddle with InventoryUtil.isEmpty

value |= 0x04;
}
if (horse.hasReproduced()) {
Expand All @@ -90,4 +101,20 @@ private int getHorseFlags() {
public Set<Material> getBreedingFoods() {
return BREEDING_FOODS;
}

@Override
protected int computeGrowthAmount(Material material) {
int amount = 0;

// We need to be a baby and only tamed horses can be fed with hay block
if (!isAdult() && !(Material.HAY_BLOCK == material && !isTamed())) {
Integer mapResult = GROWING_FOODS.get(material);

if (mapResult != null) {
amount = Math.min(mapResult, Math.abs(getAge()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for that local variable. Just return at this line, and return 0 and the end of the method.

}
}

return amount;
}
}
29 changes: 29 additions & 0 deletions src/main/java/net/glowstone/entity/passive/GlowLlama.java
@@ -1,6 +1,9 @@
package net.glowstone.entity.passive;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import net.glowstone.entity.meta.MetadataIndex;
Expand All @@ -11,10 +14,20 @@
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Llama;

/**
* Represents a llama.
* The data come from https://minecraft.gamepedia.com/Llama
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: the data comes from

Although this is debatable because data is the plural form of datum. However, data is used as a singular mass noun in everyday usage.

*/
public class GlowLlama extends GlowChestedHorse<GlowLlamaInventory> implements Llama {

private static final Set<Material> BREEDING_FOODS = Sets.immutableEnumSet(Material.HAY_BLOCK);

private static final Map<Material, Integer> GROWING_FOODS = ImmutableMap
.<Material, Integer>builder()
.put(Material.WHEAT, 200)
.put(Material.HAY_BLOCK, 1800)
.build();

/**
* Creates a llama entity.
*
Expand Down Expand Up @@ -81,4 +94,20 @@ protected GlowLlamaInventory createNewInventory() {
public Set<Material> getBreedingFoods() {
return BREEDING_FOODS;
}

@Override
protected int computeGrowthAmount(Material material) {
int amount = 0;

if (!isAdult()) {
Integer mapResult = GROWING_FOODS.get(material);

if (mapResult != null) {
amount = Math.min(mapResult, Math.abs(getAge()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous review comment about the local variable.

}
}

return amount;
}

}
12 changes: 12 additions & 0 deletions src/main/java/net/glowstone/entity/passive/GlowUndeadHorse.java
@@ -1,12 +1,19 @@
package net.glowstone.entity.passive;

import com.google.common.collect.Sets;
import java.util.EnumSet;
import java.util.Set;
import net.glowstone.inventory.GlowHorseInventory;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.EntityType;

public class GlowUndeadHorse extends GlowAbstractHorse implements AbstractHorse {

private static final Set<Material> BREEDING_FOODS =
Sets.immutableEnumSet(EnumSet.noneOf(Material.class));

public GlowUndeadHorse(Location location, EntityType type, double maxHealth) {
super(location, type, maxHealth);
}
Expand All @@ -25,4 +32,9 @@ public GlowHorseInventory getInventory() {
public boolean isUndead() {
return true;
}

@Override
public Set<Material> getBreedingFoods() {
return BREEDING_FOODS;
}
}
49 changes: 49 additions & 0 deletions src/test/java/net/glowstone/entity/GlowAgeableTest.java
Expand Up @@ -7,11 +7,15 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;

import java.util.function.Function;
import net.glowstone.net.message.play.player.InteractEntityMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Ageable;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.ItemStack;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
Expand Down Expand Up @@ -153,4 +157,49 @@ public void testCreateBaby() {
public void testGetSoundPitch() {
// TODO
}

@Test
public void testComputeGrowthAmount() {
entity.setBaby();
assertEquals(0, entity.computeGrowthAmount(null));
assertEquals(0, entity.computeGrowthAmount(Material.WHEAT));
assertEquals(0, entity.computeGrowthAmount(Material.HAY_BLOCK));
assertEquals(0, entity.computeGrowthAmount(Material.CARROT_ITEM));
}

@Test
public void testComputeGrowthAmountAdult() {
entity.setAge(0);
assertEquals(0, entity.computeGrowthAmount(null));
assertEquals(0, entity.computeGrowthAmount(Material.WHEAT));
assertEquals(0, entity.computeGrowthAmount(Material.HAY_BLOCK));
assertEquals(0, entity.computeGrowthAmount(Material.CARROT_ITEM));
}

@Test
public void testEntityInteractGrowsBaby() {
entity.setBaby();
T mockedEntity = spy(entity);
inventory.setItemInMainHand(new ItemStack(Material.RAW_FISH, 60));
InteractEntityMessage message = new InteractEntityMessage(0, InteractEntityMessage.Action.INTERACT.ordinal(), 0);

Mockito.when(mockedEntity.computeGrowthAmount(any())).thenReturn(100);

mockedEntity.entityInteract(player, message);

assertEquals(-23900, mockedEntity.getAge());
assertEquals(59, inventory.getItemInMainHand().getAmount());
}

@Test
public void testEntityInteractDoesNotGrowBaby() {
entity.setBaby();
inventory.setItemInMainHand(new ItemStack(Material.BEDROCK, 60));
InteractEntityMessage message = new InteractEntityMessage(0, InteractEntityMessage.Action.INTERACT.ordinal(), 0);

entity.entityInteract(player, message);

assertEquals(-24000, entity.getAge());
assertEquals(60, inventory.getItemInMainHand().getAmount());
}
}
24 changes: 24 additions & 0 deletions src/test/java/net/glowstone/entity/GlowAnimalTest.java
Expand Up @@ -5,6 +5,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;

import static org.junit.Assert.assertEquals;

Expand All @@ -23,4 +24,27 @@ public void testGetBreedingFoods() {
public void testGetBreedingFoodsReturnsImmutableSet() {
entity.getBreedingFoods().add(Material.SANDSTONE);
}

@Test
@Override
public void testComputeGrowthAmount() {
entity.setAge(-21000);
Assertions.assertEquals(0, entity.computeGrowthAmount(null));
Assertions.assertEquals(0, entity.computeGrowthAmount(Material.SAND));

for (Material food : entity.getBreedingFoods()) {
Assertions.assertEquals(2100, entity.computeGrowthAmount(food), food.name());
}
}

@Test
public void testComputeGrowthAmountAdult() {
entity.setAge(0);
Assertions.assertEquals(0, entity.computeGrowthAmount(null));
Assertions.assertEquals(0, entity.computeGrowthAmount(Material.SAND));

for (Material food : entity.getBreedingFoods()) {
Assertions.assertEquals(0, entity.computeGrowthAmount(food), food.name());
}
}
}
9 changes: 9 additions & 0 deletions src/test/java/net/glowstone/entity/GlowEntityTest.java
Expand Up @@ -17,9 +17,11 @@
import net.glowstone.GlowWorld;
import net.glowstone.block.GlowBlock;
import net.glowstone.chunk.GlowChunk;
import net.glowstone.inventory.GlowPlayerInventory;
import net.glowstone.scoreboard.GlowScoreboard;
import net.glowstone.scoreboard.GlowScoreboardManager;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
Expand Down Expand Up @@ -66,6 +68,8 @@ public abstract class GlowEntityTest<T extends GlowEntity> {
protected EventFactory eventFactory;
@Mock
private PluginManager pluginManager;
@Mock
protected GlowPlayer player;

// Real objects
protected Location location;
Expand All @@ -76,6 +80,7 @@ public abstract class GlowEntityTest<T extends GlowEntity> {
protected final Function<? super Location, ? extends T> entityCreator;
protected T entity;
private EventFactory oldEventFactory;
protected GlowPlayerInventory inventory;


protected GlowEntityTest(Function<? super Location, ? extends T> entityCreator) {
Expand Down Expand Up @@ -130,6 +135,9 @@ public void setUp() throws Exception {
when(eventFactory.callEvent(any(Event.class))).thenAnswer(RETURN_FIRST_ARG);
when(eventFactory.onEntityDamage(any(EntityDamageEvent.class))).thenAnswer(
RETURN_FIRST_ARG);
inventory = new GlowPlayerInventory(player);
Mockito.when(player.getInventory()).thenReturn(inventory);
Mockito.when(player.getGameMode()).thenReturn(GameMode.SURVIVAL);
}

@After
Expand All @@ -145,6 +153,7 @@ public void tearDown() {
block = null;
log = null;
entity = null;
player = null;
}

@Test
Expand Down