Skip to content

Commit

Permalink
feeding trough now use a different fake player for each animal
Browse files Browse the repository at this point in the history
added needs iron too and needs stone tool tags
  • Loading branch information
MehVahdJukaar committed Dec 31, 2023
1 parent 230b416 commit 3747f37
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.entity.ai.sensing.TemptingSensor;
Expand All @@ -31,7 +30,6 @@
import org.violetmoon.quark.base.config.Config;
import org.violetmoon.quark.content.automation.block.FeedingTroughBlock;
import org.violetmoon.quark.content.automation.block.be.FeedingTroughBlockEntity;
import org.violetmoon.quark.content.building.block.VariantLadderBlock;
import org.violetmoon.quark.mixin.mixins.accessor.AccessorTemptingSensor;
import org.violetmoon.zeta.event.bus.LoadEvent;
import org.violetmoon.zeta.event.bus.PlayEvent;
Expand All @@ -42,9 +40,7 @@
import org.violetmoon.zeta.module.ZetaModule;
import org.violetmoon.zeta.util.Hint;

import java.util.Objects;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.*;

/**
* @author WireSegal
Expand All @@ -55,7 +51,12 @@ public class FeedingTroughModule extends ZetaModule {

//using a ResourceKey because they're interned, and Holder.Reference#is leverages this for a very efficient implementation
private static final ResourceKey<PoiType> FEEDING_TROUGH_POI_KEY = ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, Quark.asResource("feeding_trough"));
private static final GameProfile DUMMY_PROFILE = new GameProfile(UUID.randomUUID(), "[FeedingTrough]");
private static final Set<FakePlayer> FREE_FAKE_PLAYERS = new HashSet<>();
//fake players created are either stored here above or in the cache below.
//this way each animal has its own player which is needed as they are moved in diff pos
private static final WeakHashMap<Animal, TroughPointer> NEARBY_TROUGH_CACHE = new WeakHashMap<>();
private static final ThreadLocal<Boolean> breedingOccurred = ThreadLocal.withInitial(() -> false);
private static int fakePlayersCount = 0;

public static BlockEntityType<FeedingTroughBlockEntity> blockEntityType;
@Hint
Expand All @@ -77,12 +78,9 @@ public class FeedingTroughModule extends ZetaModule {
public static double range = 10;

@Config(description = "Chance that an animal decides to look for a through. Closer it is to 1 the more performance it will take. Decreasing will make animals take longer to find one")
public static double lookChance = 0.02;

private static final WeakHashMap<Animal, TroughPointer> NEARBY_TROUGH_CACHE = new WeakHashMap<>();

private static final ThreadLocal<Boolean> breedingOccurred = ThreadLocal.withInitial(() -> false);
public static double lookChance = 0.015;

//TODO: not sure this works properly. it only cancels the first orb
@PlayEvent
public void onBreed(ZBabyEntitySpawn.Lowest event) {
if (event.getCausedByPlayer() == null && event.getParentA().level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT))
Expand Down Expand Up @@ -124,16 +122,26 @@ public void onOrbSpawn(ZEntityJoinLevel event) {
}

//do we already know about a nearby trough?
NEARBY_TROUGH_CACHE.entrySet().removeIf(p -> !p.getValue().valid(p.getKey()));

var iterator = NEARBY_TROUGH_CACHE.entrySet().iterator();
while (iterator.hasNext()) {
var entry = iterator.next();
TroughPointer pointer = entry.getValue();
if (!pointer.valid(entry.getKey())) {
iterator.remove();
// add fake player back to the list
FREE_FAKE_PLAYERS.add(pointer.fakePlayer);
}
}
TroughPointer pointer = NEARBY_TROUGH_CACHE.get(animal);

//There's no cached trough nearby.
//Randomize whether we actually look for a new trough, to hopefully not eat all the tick time.
if (pointer == null && level.random.nextFloat() <= lookChance) {
if (pointer == null && level.random.nextFloat() <= lookChance*20) {
pointer = TroughPointer.find(level, animal, temptations);
if (pointer != null){
NEARBY_TROUGH_CACHE.put(animal, pointer);
// remove from free players list
FREE_FAKE_PLAYERS.remove(pointer.fakePlayer);
}
}

Expand All @@ -149,7 +157,7 @@ public void onOrbSpawn(ZEntityJoinLevel event) {
Vec3 targetPos = new Vec3(location.getX(), location.getY(), location.getZ()).add(0.5, 0.0625, 0.5);
BlockHitResult ray = level.clip(new ClipContext(eyesPos, targetPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, animal));
if (ray.getType() == HitResult.Type.BLOCK && ray.getBlockPos().equals(location)) {
return pointer.foodHolder;
return pointer.fakePlayer;
}
}
}
Expand All @@ -172,37 +180,38 @@ public final void register(ZRegister event) {

private static final class TroughPointer {
private final BlockPos pos;
private final FakePlayer foodHolder;
private final FakePlayer fakePlayer;
private final Ingredient temptations;
private int eatCooldown = 0; //Ideally cooldown should be per entity... Assuming troughs don't change much this is fine
private int giveUpCooldown = 20 * 20; //max seconds till we give up

private TroughPointer(BlockPos pos, FakePlayer player, Ingredient temptations) {
this.pos = pos;
this.foodHolder = player;
this.fakePlayer = player;
this.temptations = temptations;
}

// This is a bit ugly. 0 = new pointer, 1 = end of life, other = ticking cooldown
// Once a through is found and an animal is fed, its considered valid until cooldown runs out.
// Then its invalidated so animals can find possibly closer ones
boolean valid(Animal animal) {
if (animal.isRemoved() || !animal.isAlive() || fakePlayer.level() != animal.level() || pos.distSqr(animal.blockPosition()) > range * range) {
return false;
}
if (eatCooldown == 1){
return false;
}
if (giveUpCooldown <= 0){
return false;
}
if (eatCooldown != 0) return true;
if (animal.isRemoved() || !animal.isAlive() || foodHolder.level() != animal.level() || pos.distSqr(animal.blockPosition()) > range * range) {
return false;
}

//check if it has food and tile is valid
if(animal.level().getBlockEntity(pos) instanceof FeedingTroughBlockEntity trough){
//this should be called in tick, but we save one tile call by doing this...
trough.updateFoodHolder(animal, temptations, foodHolder);
trough.updateFoodHolder(animal, temptations, fakePlayer);
//if it still has food
return !foodHolder.getMainHandItem().isEmpty();
return !fakePlayer.getMainHandItem().isEmpty();
}
return false;
}
Expand All @@ -228,12 +237,12 @@ public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (TroughPointer) obj;
return Objects.equals(this.pos, that.pos) &&
Objects.equals(this.foodHolder, that.foodHolder);
Objects.equals(this.fakePlayer, that.fakePlayer);
}

@Override
public int hashCode() {
return Objects.hash(pos, foodHolder);
return Objects.hash(pos, fakePlayer);
}

// If animal cant eat.
Expand All @@ -256,7 +265,7 @@ static TroughPointer find(ServerLevel level, Animal animal, Ingredient temptatio

if (level.getBlockEntity(pos) instanceof FeedingTroughBlockEntity trough) {
//only returns if it has the right food
FakePlayer foodHolder = FakePlayerFactory.get(level, DUMMY_PROFILE);
FakePlayer foodHolder = getOrCreateFakePlayer(level);
if (foodHolder != null) {
trough.updateFoodHolder(animal, temptations, foodHolder);
// if it has a food item
Expand All @@ -270,4 +279,17 @@ static TroughPointer find(ServerLevel level, Animal animal, Ingredient temptatio
return null;
}
}

private static FakePlayer getOrCreateFakePlayer(ServerLevel serverLevel){
Optional<FakePlayer> any = FREE_FAKE_PLAYERS.stream().findAny();
if(any.isEmpty()){
GameProfile dummyProfile = new GameProfile(UUID.randomUUID(), "[FeedingTrough-"+ ++fakePlayersCount+"]");
var p = FakePlayerFactory.get(serverLevel, dummyProfile);
FREE_FAKE_PLAYERS.add(p);
return p;
}
else {
return any.get();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
"quark:brick_vertical_slab",
"quark:cobbled_deepslate_vertical_slab",
"quark:cobblestone_vertical_slab",
"quark:cut_copper_vertical_slab",
"quark:cut_red_sandstone_vertical_slab",
"quark:cut_sandstone_vertical_slab",
"quark:dark_prismarine_vertical_slab",
"quark:deepslate_brick_vertical_slab",
"quark:deepslate_tile_vertical_slab",
"quark:diorite_vertical_slab",
"quark:end_stone_brick_vertical_slab",
"quark:cut_copper_vertical_slab",
"quark:exposed_cut_copper_vertical_slab",
"quark:oxidized_cut_copper_vertical_slab",
"quark:granite_vertical_slab",
"quark:mossy_cobblestone_vertical_slab",
"quark:mossy_stone_brick_vertical_slab",
"quark:nether_brick_vertical_slab",
"quark:oxidized_cut_copper_vertical_slab",
"quark:polished_andesite_vertical_slab",
"quark:polished_blackstone_brick_vertical_slab",
"quark:polished_blackstone_vertical_slab",
Expand Down Expand Up @@ -441,7 +441,7 @@
"quark:carved_mud_bricks",
"quark:mud_pillar",
"quark:mud_brick_lattice",
"quark:crafter",
{ "id": "quark:crafter", "required": false },
{ "id": "quark:lootr_nether_brick_chest", "required": false },
{ "id": "quark:lootr_purpur_chest", "required": false },
{ "id": "quark:lootr_prismarine_chest", "required": false },
Expand Down
10 changes: 10 additions & 0 deletions src/main/resources/data/minecraft/tags/blocks/needs_iron_tool.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

{
"replace": false,
"values": [
"quark:raw_gold_bricks",
"quark:raw_gold_bricks_stairs",
"quark:raw_gold_bricks_slab",
"quark:raw_gold_bricks_vertical_slab"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

{
"replace": false,
"values": [
"quark:waxed_cut_copper_vertical_slab",
"quark:waxed_exposed_cut_copper_vertical_slab",
"quark:waxed_oxidized_cut_copper_vertical_slab",
"quark:waxed_weathered_cut_copper_vertical_slab",
"quark:weathered_cut_copper_vertical_slab",
"quark:cut_copper_vertical_slab",
"quark:exposed_cut_copper_vertical_slab",
"quark:oxidized_cut_copper_vertical_slab",

"quark:iron_rod",

"quark:raw_iron_bricks",
"quark:raw_copper_bricks",
"quark:raw_gold_bricks",
"quark:raw_iron_bricks_stairs",
"quark:raw_copper_bricks_stairs",
"quark:raw_gold_bricks_stairs",
"quark:raw_iron_bricks_slab",
"quark:raw_copper_bricks_slab",
"quark:raw_gold_bricks_slab",
"quark:raw_iron_bricks_vertical_slab",
"quark:raw_copper_bricks_vertical_slab",
"quark:raw_gold_bricks_vertical_slab"
]
}

0 comments on commit 3747f37

Please sign in to comment.