Compare commits

..
4 Commits
18 changed files with 535 additions and 187 deletions

No files matched your search

+5 -5
View File
@@ -1,14 +1,14 @@
mcversion=1.12.1
forgeversion=14.22.0.2462
mcp_mappings=snapshot_20170826
forgeversion=14.22.0.2469
mcp_mappings=snapshot_20170904
curse_project_id=59751
tesla_version=1.0.60
tesla_mcversion=1.12
jei_version=4.7.8.91
jei_version=4.7.8.92
jei_mcversion=1.12.1
ic2_version=2.8.17-ex112
ic2_version=2.8.24-ex112
version_major=5
version_minor=5
version_patch=1
version_patch=3
+1 -1
View File
@@ -60,7 +60,7 @@ import forestry.plugins.compat.PluginIC2;
guiFactory = "forestry.core.config.ForestryGuiConfigFactory",
acceptedMinecraftVersions = "[1.12, 1.12.1]",
dependencies = "required-after:forge@[14.21.1.2395,);"
+ "after:jei@[4.7.0,);"
+ "after:jei@[4.7.8.91,);"
+ "after:" + PluginIC2.modId + ";"
+ "after:" + PluginNatura.modId + ";")
public class Forestry {
@@ -5,12 +5,14 @@
******************************************************************************/
package forestry.api.apiculture;
import java.io.IOException;
import java.util.List;
import forestry.api.core.INbtReadable;
import forestry.api.core.INbtWritable;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.relauncher.Side;
@@ -79,4 +81,12 @@ public interface IBeekeepingLogic extends INbtWritable, INbtReadable {
* These positions are synced to the client from the server.
*/
List<BlockPos> getFlowerPositions();
default void readData(PacketBuffer data) throws IOException {
}
default void writeData(PacketBuffer data) {
}
}
@@ -0,0 +1,13 @@
/*******************************************************************************
* Copyright 2011-2014 SirSengir
*
* This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details.
******************************************************************************/
package forestry.api.core;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public interface IBlockPosPredicate {
boolean test(World world, BlockPos blockPos);
}
@@ -5,10 +5,12 @@
******************************************************************************/
package forestry.api.genetics;
import java.util.Iterator;
import java.util.List;
import forestry.api.apiculture.IBee;
import forestry.api.apiculture.IBeeHousing;
import forestry.api.core.IBlockPosPredicate;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
@@ -60,17 +62,38 @@ public interface IFlowerRegistry {
*/
boolean growFlower(String flowerType, World world, IIndividual individual, BlockPos pos);
/**
* Gets an iterator over the area a bee can travel from its beeHousing.
* Starts at the bee housing and spirals outward.
*
* @param beeHousing The bee housing that will help determine the size of the area to check.
* @param bee The bee that will help determine the size of the area to check.
* @return an iterator over the area a bee can travel from its beeHousing.
* @since Forestry 5.5.2
*/
Iterator<BlockPos.MutableBlockPos> getAreaIterator(IBeeHousing beeHousing, IBee bee);
/**
* Checks a single coordinate to see if it is an accepted flower.
* @since Forestry 5.5.2
*/
IBlockPosPredicate createAcceptedFlowerPredicate(String flowerType);
/**
* @param beeHousing The bee housing that will help determine the size of the area to check.
* @param bee The bee that will help determine the size of the area to check.
* @param flowerType See {@link forestry.api.apiculture.FlowerManager}.FlowerTypeXXX
* @param maxFlowers the largest number of flowers to check for before returning. Use 1 if you only need 1.
* @return the coordinates of nearby accepted flowers, with size from 0 to maxFlowers.
* @deprecated since Forestry 5.5.2. Use {@link #getAreaIterator(IBeeHousing, IBee)} and {@link #createAcceptedFlowerPredicate(String)}.
*/
@Deprecated
List<BlockPos> getAcceptedFlowerCoordinates(IBeeHousing beeHousing, IBee bee, String flowerType, int maxFlowers);
/**
* Checks a single coordinate to see if it is an accepted flower.
* @deprecated since Forestry 5.5.2. Use {@link #createAcceptedFlowerPredicate(String)}.
*/
@Deprecated
boolean isAcceptedFlower(String flowerType, World world, BlockPos pos);
}
@@ -38,8 +38,6 @@ import forestry.apiculture.network.packets.PacketBeeLogicActive;
import forestry.apiculture.network.packets.PacketBeeLogicActiveEntity;
import forestry.core.config.Constants;
import forestry.core.errors.EnumErrorCode;
import forestry.core.network.IStreamable;
import forestry.core.network.PacketBufferForestry;
import forestry.core.utils.Log;
import forestry.core.utils.NetworkUtil;
import net.minecraft.client.Minecraft;
@@ -48,13 +46,14 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class BeekeepingLogic implements IBeekeepingLogic, IStreamable {
public class BeekeepingLogic implements IBeekeepingLogic {
private static final int totalBreedingTime = Constants.APIARY_BREEDING_TIME;
@@ -136,7 +135,7 @@ public class BeekeepingLogic implements IBeekeepingLogic, IStreamable {
}
@Override
public void writeData(PacketBufferForestry data) {
public void writeData(PacketBuffer data) {
data.writeBoolean(active);
if (active) {
data.writeItemStack(queenStack);
@@ -145,7 +144,7 @@ public class BeekeepingLogic implements IBeekeepingLogic, IStreamable {
}
@Override
public void readData(PacketBufferForestry data) throws IOException {
public void readData(PacketBuffer data) throws IOException {
boolean active = data.readBoolean();
setActive(active);
if (active) {
@@ -222,7 +221,8 @@ public class BeekeepingLogic implements IBeekeepingLogic, IStreamable {
errorLogic.setCondition(true, errorState);
}
boolean hasFlowers = hasFlowersCache.hasFlowers(queen, housing);
hasFlowersCache.update(queen, housing);
boolean hasFlowers = hasFlowersCache.hasFlowers();
boolean flowerCacheNeedsSync = hasFlowersCache.needsSync();
errorLogic.setCondition(!hasFlowers, EnumErrorCode.NO_FLOWER);
@@ -10,80 +10,92 @@
******************************************************************************/
package forestry.apiculture;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import forestry.api.apiculture.BeeManager;
import forestry.api.apiculture.FlowerManager;
import forestry.api.apiculture.IBee;
import forestry.api.apiculture.IBeeHousing;
import forestry.api.apiculture.IBeeModifier;
import forestry.api.core.INbtReadable;
import forestry.api.core.INbtWritable;
import forestry.api.core.IBlockPosPredicate;
import forestry.api.genetics.IFlowerProvider;
import forestry.core.network.IStreamable;
import forestry.core.network.PacketBufferForestry;
import forestry.core.utils.VectUtil;
import forestry.core.utils.TickHelper;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
public class HasFlowersCache implements INbtWritable, INbtReadable, IStreamable {
private static final String nbtKey = "hasFlowerCache";
private static final String nbtKeyFlowers = "flowers";
private static final String nbtKeyCooldown = "cooldown";
public class HasFlowersCache implements INbtWritable, INbtReadable {
private static final String NBT_KEY = "hasFlowerCache";
private static final String NBT_KEY_FLOWERS = "flowers";
private static final int FLOWER_CHECK_INTERVAL = 200;
private static final Random random = new Random();
private static final int flowerCheckInterval = 128;
private final TickHelper tickHelper = new TickHelper();
private final int flowerCheckTime = random.nextInt(flowerCheckInterval);
private List<BlockPos> flowerCoords = new ArrayList<>();
private int cooldown = 0;
@Nullable
private FlowerData flowerData;
private final List<BlockPos> flowerCoords = new ArrayList<>();
private boolean needsSync = false;
public boolean hasFlowers(IBee queen, IBeeHousing beeHousing) {
IFlowerProvider flowerProvider = queen.getGenome().getFlowerProvider();
String flowerType = flowerProvider.getFlowerType();
private static class FlowerData {
public final String flowerType;
public final IBlockPosPredicate flowerPredicate;
public Iterator<BlockPos.MutableBlockPos> areaIterator;
public FlowerData(IBee queen, IBeeHousing beeHousing) {
IFlowerProvider flowerProvider = queen.getGenome().getFlowerProvider();
this.flowerType = flowerProvider.getFlowerType();
this.flowerPredicate = FlowerManager.flowerRegistry.createAcceptedFlowerPredicate(flowerType);
this.areaIterator = FlowerManager.flowerRegistry.getAreaIterator(beeHousing, queen);
}
public void resetIterator(IBee queen, IBeeHousing beeHousing) {
this.areaIterator = FlowerManager.flowerRegistry.getAreaIterator(beeHousing, queen);
}
}
public void update(IBee queen, IBeeHousing beeHousing) {
if (flowerData == null) {
this.flowerData = new FlowerData(queen, beeHousing);
this.flowerCoords.clear();
}
World world = beeHousing.getWorldObj();
tickHelper.onTick();
if (!flowerCoords.isEmpty()) {
if (world.getTotalWorldTime() % flowerCheckInterval != flowerCheckTime) {
return true;
}
IBeeModifier beeModifier = BeeManager.beeRoot.createBeeHousingModifier(beeHousing);
BlockPos housingCoords = beeHousing.getCoordinates();
Vec3i genomeTerritory = queen.getGenome().getTerritory();
float housingModifier = beeModifier.getTerritoryModifier(queen.getGenome(), 1f);
Vec3i area = VectUtil.scale(genomeTerritory, housingModifier * 3.0f);
BlockPos min = VectUtil.scale(area, -0.5f).add(housingCoords);
BlockPos max = VectUtil.scale(area, 0.5f).add(housingCoords);
for (BlockPos flowerPos : flowerCoords) {
if (!isFlowerValid(world, flowerPos, flowerType, min, max)) {
cooldown = 0;
break;
if (!flowerCoords.isEmpty() && tickHelper.updateOnInterval(FLOWER_CHECK_INTERVAL)) {
Iterator<BlockPos> iterator = flowerCoords.iterator();
while (iterator.hasNext()) {
BlockPos flowerPos = iterator.next();
if (!flowerData.flowerPredicate.test(world, flowerPos) && world.isBlockLoaded(flowerPos)) {
iterator.remove();
needsSync = true;
}
}
}
if (cooldown <= 0) {
List<BlockPos> newFlowerCoords = FlowerManager.flowerRegistry.getAcceptedFlowerCoordinates(beeHousing, queen, flowerType, 5);
cooldown = PluginApiculture.ticksPerBeeWorkCycle;
if (!flowerCoords.equals(newFlowerCoords)) {
flowerCoords = newFlowerCoords;
needsSync = true;
}
} else {
cooldown--;
}
final int flowerCount = flowerCoords.size();
final int ticksPerCheck = 1 + (flowerCount * flowerCount);
if (tickHelper.updateOnInterval(ticksPerCheck)) {
if (flowerData.areaIterator.hasNext()) {
BlockPos.MutableBlockPos blockPos = flowerData.areaIterator.next();
if (flowerData.flowerPredicate.test(world, blockPos)) {
flowerCoords.add(blockPos.toImmutable());
needsSync = true;
}
} else {
flowerData.resetIterator(queen, beeHousing);
}
}
}
public boolean hasFlowers() {
return !flowerCoords.isEmpty();
}
@@ -95,35 +107,23 @@ public class HasFlowersCache implements INbtWritable, INbtReadable, IStreamable
public void clear() {
flowerCoords.clear();
cooldown = 0;
flowerData = null;
}
public List<BlockPos> getFlowerCoords() {
return Collections.unmodifiableList(flowerCoords);
}
private static boolean isFlowerValid(World world, BlockPos flowerCoords, String flowerType, BlockPos min, BlockPos max) {
if (!isFlowerCoordInRange(flowerCoords, min, max)) {
return false;
}
return FlowerManager.flowerRegistry.isAcceptedFlower(flowerType, world, flowerCoords);
}
private static boolean isFlowerCoordInRange(BlockPos flowerCoords, BlockPos min, BlockPos max) {
return flowerCoords.getX() >= min.getX() && flowerCoords.getX() <= max.getX() && flowerCoords.getY() >= min.getY() && flowerCoords.getY() <= max.getY() && flowerCoords.getZ() >= min.getZ() && flowerCoords.getZ() <= max.getZ();
}
@Override
public void readFromNBT(NBTTagCompound nbttagcompound) {
if (!nbttagcompound.hasKey(nbtKey)) {
if (!nbttagcompound.hasKey(NBT_KEY)) {
return;
}
NBTTagCompound hasFlowerCacheNBT = nbttagcompound.getCompoundTag(nbtKey);
NBTTagCompound hasFlowerCacheNBT = nbttagcompound.getCompoundTag(NBT_KEY);
if (hasFlowerCacheNBT.hasKey(nbtKeyFlowers)) {
int[] flowersList = hasFlowerCacheNBT.getIntArray(nbtKeyFlowers);
if (hasFlowerCacheNBT.hasKey(NBT_KEY_FLOWERS)) {
int[] flowersList = hasFlowerCacheNBT.getIntArray(NBT_KEY_FLOWERS);
if (flowersList.length % 3 == 0) {
int flowerCount = flowersList.length / 3;
for (int i = 0; i < flowerCount; i++) {
@@ -133,8 +133,6 @@ public class HasFlowersCache implements INbtWritable, INbtReadable, IStreamable
needsSync = true;
}
}
cooldown = hasFlowerCacheNBT.getInteger(nbtKeyCooldown);
}
@Override
@@ -151,17 +149,14 @@ public class HasFlowersCache implements INbtWritable, INbtReadable, IStreamable
i++;
}
hasFlowerCacheNBT.setIntArray(nbtKeyFlowers, flowersList);
hasFlowerCacheNBT.setIntArray(NBT_KEY_FLOWERS, flowersList);
}
hasFlowerCacheNBT.setInteger(nbtKeyCooldown, cooldown);
nbttagcompound.setTag(nbtKey, hasFlowerCacheNBT);
nbttagcompound.setTag(NBT_KEY, hasFlowerCacheNBT);
return nbttagcompound;
}
@Override
public void writeData(PacketBufferForestry data) {
public void writeData(PacketBuffer data) {
int size = flowerCoords.size();
data.writeVarInt(size);
if (size > 0) {
@@ -173,8 +168,7 @@ public class HasFlowersCache implements INbtWritable, INbtReadable, IStreamable
}
}
@Override
public void readData(PacketBufferForestry data) throws IOException {
public void readData(PacketBuffer data) throws IOException {
flowerCoords.clear();
int size = data.readVarInt();
@@ -0,0 +1,166 @@
/*******************************************************************************
* Copyright (c) 2011-2014 SirSengir.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Various Contributors including, but not limited to:
* SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges
******************************************************************************/
package forestry.apiculture;
import java.io.IOException;
import java.util.List;
import forestry.api.apiculture.IBee;
import forestry.api.apiculture.IBeekeepingLogic;
import forestry.api.genetics.IEffectData;
import forestry.apiculture.network.packets.PacketBeeLogicActive;
import forestry.apiculture.tiles.TileHive;
import forestry.core.utils.NetworkUtil;
import forestry.core.utils.TickHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class WorldgenBeekeepingLogic implements IBeekeepingLogic {
private final TileHive housing;
private IEffectData effectData[] = new IEffectData[2];
private final HasFlowersCache hasFlowersCache = new HasFlowersCache();
private final TickHelper tickHelper = new TickHelper();
// Client
private boolean active;
public WorldgenBeekeepingLogic(TileHive housing) {
this.housing = housing;
}
// / SAVING & LOADING
@Override
public void readFromNBT(NBTTagCompound nbttagcompound) {
setActive(nbttagcompound.getBoolean("Active"));
hasFlowersCache.readFromNBT(nbttagcompound);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbttagcompound) {
nbttagcompound.setBoolean("Active", active);
hasFlowersCache.writeToNBT(nbttagcompound);
return nbttagcompound;
}
@Override
public void writeData(PacketBuffer data) {
data.writeBoolean(active);
if (active) {
hasFlowersCache.writeData(data);
}
}
@Override
public void readData(PacketBuffer data) throws IOException {
boolean active = data.readBoolean();
setActive(active);
if (active) {
hasFlowersCache.readData(data);
}
}
/* Activatable */
private void setActive(boolean active) {
if (this.active == active) {
return;
}
this.active = active;
syncToClient();
}
/* UPDATING */
@Override
public boolean canWork() {
tickHelper.onTick();
IBee queen = housing.getContainedBee();
hasFlowersCache.update(queen, housing);
if (tickHelper.updateOnInterval(200)) {
World world = housing.getWorldObj();
boolean canWork = (world.isDaytime() || queen.getGenome().getNeverSleeps()) &&
(!housing.isRaining() || queen.getGenome().getToleratesRain());
boolean flowerCacheNeedsSync = hasFlowersCache.needsSync();
if (active != canWork) {
setActive(canWork);
} else if (flowerCacheNeedsSync) {
syncToClient();
}
}
return active;
}
@Override
public void doWork() {
}
@Override
public void clearCachedValues() {
if (!housing.getWorldObj().isRemote) {
hasFlowersCache.clear();
canWork();
}
}
/* CLIENT */
@Override
public void syncToClient() {
World world = housing.getWorldObj();
if (world != null && !world.isRemote) {
NetworkUtil.sendNetworkPacket(new PacketBeeLogicActive(housing), housing.getCoordinates(), world);
}
}
@Override
public void syncToClient(EntityPlayerMP player) {
World world = housing.getWorldObj();
if (world != null && !world.isRemote) {
NetworkUtil.sendToPlayer(new PacketBeeLogicActive(housing), player);
}
}
@Override
public int getBeeProgressPercent() {
return 0;
}
@Override
@SideOnly(Side.CLIENT)
public boolean canDoBeeFX() {
return !Minecraft.getMinecraft().isGamePaused() && active;
}
@Override
@SideOnly(Side.CLIENT)
public void doBeeFX() {
IBee queen = housing.getContainedBee();
queen.doFX(effectData, housing);
}
@Override
public List<BlockPos> getFlowerPositions() {
return hasFlowersCache.getFlowerCoords();
}
}
@@ -36,6 +36,7 @@ import forestry.core.owner.OwnerHandler;
import forestry.core.tiles.IClimatised;
import forestry.core.utils.ClimateUtil;
import forestry.core.utils.NetworkUtil;
import forestry.core.utils.TickHelper;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.EntityDataManager;
@@ -47,12 +48,10 @@ import net.minecraft.world.biome.Biome;
public abstract class EntityMinecartBeeHousingBase extends EntityMinecartContainerForestry implements IBeeHousing, IOwnedTile, IGuiBeeHousingDelegate, IClimatised, IStreamableGui {
private static final DataParameter<Optional<GameProfile>> OWNER = EntityDataManager.createKey(EntityMinecartBeeHousingBase.class, GameProfileDataSerializer.INSTANCE);
private static final Random random = new Random();
private static final int beeFXInterval = 4;
private static final int pollenFXInterval = 50;
private final int beeFXTime = random.nextInt(beeFXInterval);
private final int pollenFXTime = random.nextInt(pollenFXInterval);
private final TickHelper tickHelper = new TickHelper();
private final IBeekeepingLogic beeLogic = BeeManager.beeRoot.createBeekeepingLogic(this);
private final IErrorLogic errorLogic = ForestryAPI.errorStateRegistry.createErrorLogic();
@@ -184,6 +183,7 @@ public abstract class EntityMinecartBeeHousingBase extends EntityMinecartContain
@Override
public void onUpdate() {
super.onUpdate();
tickHelper.onTick();
if (!world.isRemote) {
if (beeLogic.canWork()) {
beeLogic.doWork();
@@ -196,11 +196,11 @@ public abstract class EntityMinecartBeeHousingBase extends EntityMinecartContain
}
if (beeLogic.canDoBeeFX()) {
if (world.getTotalWorldTime() % beeFXInterval == beeFXTime) {
if (tickHelper.updateOnInterval(beeFXInterval)) {
beeLogic.doBeeFX();
}
if (world.getTotalWorldTime() % pollenFXInterval == pollenFXTime) {
if (tickHelper.updateOnInterval(pollenFXInterval)) {
TileBeeHousingBase.doPollenFX(world, posX - 0.5, posY - 0.1, posZ - 0.5);
}
}
@@ -12,6 +12,7 @@ package forestry.apiculture.flowers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -27,11 +28,13 @@ import forestry.api.apiculture.IBee;
import forestry.api.apiculture.IBeeGenome;
import forestry.api.apiculture.IBeeHousing;
import forestry.api.apiculture.IBeeModifier;
import forestry.api.core.IBlockPosPredicate;
import forestry.api.genetics.IFlowerAcceptableRule;
import forestry.api.genetics.IFlowerGrowthHelper;
import forestry.api.genetics.IFlowerGrowthRule;
import forestry.api.genetics.IFlowerRegistry;
import forestry.api.genetics.IIndividual;
import forestry.core.utils.BlockStateSet;
import forestry.core.utils.VectUtil;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
@@ -43,7 +46,7 @@ import net.minecraft.world.World;
public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelper {
private final HashMultimap<String, IFlowerAcceptableRule> registeredRules;
private final HashMultimap<String, Block> acceptableBlocks;
private final HashMultimap<String, IBlockState> acceptableBlockStates;
private final Map<String, BlockStateSet> acceptableBlockStates;
private final HashMultimap<String, Flower> plantableFlowers;
private final ArrayListMultimap<String, IFlowerGrowthRule> growthRules;
@@ -52,7 +55,7 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
public FlowerRegistry() {
this.registeredRules = HashMultimap.create();
this.acceptableBlocks = HashMultimap.create();
this.acceptableBlockStates = HashMultimap.create();
this.acceptableBlockStates = new HashMap<>();
this.plantableFlowers = HashMultimap.create();
this.growthRules = ArrayListMultimap.create();
this.chances = new HashMap<>();
@@ -78,7 +81,7 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
throw new NullPointerException("Tried to register flower with null type. " + blockState);
}
this.acceptableBlockStates.get(flowerType).add(blockState);
this.getAcceptedBlockStates(flowerType).add(blockState);
}
}
@@ -113,7 +116,7 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
Set<Flower> flowers = this.plantableFlowers.get(flowerType);
flowers.add(newFlower);
Set<IBlockState> blocks = this.acceptableBlockStates.get(flowerType);
Set<IBlockState> blocks = this.getAcceptedBlockStates(flowerType);
blocks.add(blockState);
if (this.chances.containsKey(flowerType)) {
@@ -129,43 +132,16 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
}
@Override
public List<BlockPos> getAcceptedFlowerCoordinates(IBeeHousing beeHousing, IBee bee, String flowerType, int maxFlowers) {
Set<IFlowerAcceptableRule> acceptableRules = this.registeredRules.get(flowerType);
Set<IBlockState> acceptedBlockStates = this.acceptableBlockStates.get(flowerType);
Set<Block> acceptedBlocks = this.acceptableBlocks.get(flowerType);
World world = beeHousing.getWorldObj();
IBeeModifier beeModifier = BeeManager.beeRoot.createBeeHousingModifier(beeHousing);
Vec3i area = getArea(bee.getGenome(), beeModifier);
BlockPos minPos = beeHousing.getCoordinates().add(-area.getX() / 2, -area.getY() / 2, -area.getZ() / 2);
BlockPos maxPos = minPos.add(area);
List<BlockPos> flowerCoords = new ArrayList<>();
for (BlockPos.MutableBlockPos posBlock : VectUtil.getAllInBoxFromCenterMutable(world, minPos, beeHousing.getCoordinates(), maxPos)) {
if (!world.isBlockLoaded(posBlock)) {
continue;
}
IBlockState blockState = world.getBlockState(posBlock);
if (blockState.getBlock().isAir(blockState, world, posBlock)) {
continue;
}
for (IFlowerAcceptableRule acceptableRule : acceptableRules) {
if (acceptableRule.isAcceptableFlower(blockState, world, posBlock, flowerType)) {
flowerCoords.add(posBlock.toImmutable());
if (flowerCoords.size() >= maxFlowers) {
return flowerCoords;
}
}
}
if (isAcceptedFlower(blockState, acceptedBlocks, acceptedBlockStates)) {
flowerCoords.add(posBlock.toImmutable());
if (flowerCoords.size() >= maxFlowers) {
return flowerCoords;
}
World world = beeHousing.getWorldObj();
IBlockPosPredicate acceptedFlowerPredicate = createAcceptedFlowerPredicate(flowerType);
Iterator<BlockPos.MutableBlockPos> areaIterator = getAreaIterator(beeHousing, bee);
while (areaIterator.hasNext() && flowerCoords.size() < maxFlowers) {
BlockPos.MutableBlockPos pos = areaIterator.next();
if (acceptedFlowerPredicate.test(world, pos)) {
flowerCoords.add(pos.toImmutable());
}
}
@@ -173,6 +149,17 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
}
@Override
public Iterator<BlockPos.MutableBlockPos> getAreaIterator(IBeeHousing beeHousing, IBee bee) {
IBeeModifier beeModifier = BeeManager.beeRoot.createBeeHousingModifier(beeHousing);
Vec3i area = getArea(bee.getGenome(), beeModifier);
BlockPos minPos = beeHousing.getCoordinates().add(-area.getX() / 2, -area.getY() / 2, -area.getZ() / 2);
BlockPos maxPos = minPos.add(area);
World world = beeHousing.getWorldObj();
return VectUtil.getAllInBoxFromCenterMutable(world, minPos, beeHousing.getCoordinates(), maxPos);
}
@Override
@Deprecated
public boolean isAcceptedFlower(String flowerType, World world, BlockPos pos) {
if (!world.isBlockLoaded(pos)) {
return true; // Avoid actually checking until the flower's position is loaded.
@@ -185,12 +172,25 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
}
}
Set<IBlockState> acceptedBlockStates = this.acceptableBlockStates.get(flowerType);
Set<IBlockState> acceptedBlockStates = this.getAcceptedBlockStates(flowerType);
Set<Block> acceptedBlocks = this.acceptableBlocks.get(flowerType);
return isAcceptedFlower(blockState, acceptedBlocks, acceptedBlockStates);
}
private Set<IBlockState> getAcceptedBlockStates(String flowerType) {
return this.acceptableBlockStates.computeIfAbsent(flowerType, k -> new BlockStateSet());
}
@Override
public IBlockPosPredicate createAcceptedFlowerPredicate(String flowerType) {
Set<IFlowerAcceptableRule> acceptableRules = this.registeredRules.get(flowerType);
Set<IBlockState> acceptedBlockStates = this.getAcceptedBlockStates(flowerType);
Set<Block> acceptedBlocks = this.acceptableBlocks.get(flowerType);
return new AcceptedFlowerPredicate(flowerType, acceptableRules, acceptedBlocks, acceptedBlockStates);
}
private static boolean isAcceptedFlower(IBlockState blockState, Set<Block> acceptedBlocks, Set<IBlockState> acceptedBlockStates) {
Block block = blockState.getBlock();
return acceptedBlocks.contains(block) || acceptedBlockStates.contains(blockState);
@@ -255,4 +255,37 @@ public final class FlowerRegistry implements IFlowerRegistry, IFlowerGrowthHelpe
Flower flower = getRandomPlantableFlower(flowerType, world.rand);
return world.setBlockState(pos, flower.getBlockState());
}
private static class AcceptedFlowerPredicate implements IBlockPosPredicate {
private final String flowerType;
private final Set<IFlowerAcceptableRule> acceptableRules;
private final Set<Block> acceptedBlocks;
private final Set<IBlockState> acceptedBlockStates;
public AcceptedFlowerPredicate(String flowerType, Set<IFlowerAcceptableRule> acceptableRules, Set<Block> acceptedBlocks, Set<IBlockState> acceptedBlockStates) {
this.flowerType = flowerType;
this.acceptableRules = acceptableRules;
this.acceptedBlocks = acceptedBlocks;
this.acceptedBlockStates = acceptedBlockStates;
}
@Override
public boolean test(World world, BlockPos blockPos) {
if (world.isBlockLoaded(blockPos)) {
IBlockState blockState = world.getBlockState(blockPos);
if (!blockState.getBlock().isAir(blockState, world, blockPos)) {
for (IFlowerAcceptableRule acceptableRule : acceptableRules) {
if (acceptableRule.isAcceptableFlower(blockState, world, blockPos, flowerType)) {
return true;
}
}
if (isAcceptedFlower(blockState, acceptedBlocks, acceptedBlockStates)) {
return true;
}
}
}
return false;
}
}
}
@@ -14,7 +14,6 @@ import java.io.IOException;
import forestry.api.apiculture.IBeeHousing;
import forestry.api.apiculture.IBeekeepingLogic;
import forestry.apiculture.BeekeepingLogic;
import forestry.core.network.ForestryPacket;
import forestry.core.network.IForestryPacketClient;
import forestry.core.network.IForestryPacketHandlerClient;
@@ -28,11 +27,11 @@ import net.minecraftforge.fml.relauncher.SideOnly;
public class PacketBeeLogicActive extends ForestryPacket implements IForestryPacketClient {
private final BlockPos tilePos;
private final BeekeepingLogic beekeepingLogic;
private final IBeekeepingLogic beekeepingLogic;
public PacketBeeLogicActive(IBeeHousing tile) {
this.tilePos = tile.getCoordinates();
this.beekeepingLogic = (BeekeepingLogic) tile.getBeekeepingLogic();
this.beekeepingLogic = tile.getBeekeepingLogic();
}
@Override
@@ -55,9 +54,7 @@ public class PacketBeeLogicActive extends ForestryPacket implements IForestryPac
IBeeHousing beeHousing = TileUtil.getTile(player.world, tilePos, IBeeHousing.class);
if (beeHousing != null) {
IBeekeepingLogic beekeepingLogic = beeHousing.getBeekeepingLogic();
if (beekeepingLogic instanceof BeekeepingLogic) {
((BeekeepingLogic) beekeepingLogic).readData(data);
}
beekeepingLogic.readData(data);
}
}
}
@@ -16,6 +16,8 @@ import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import forestry.apiculture.WorldgenBeekeepingLogic;
import forestry.core.utils.TickHelper;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
@@ -59,7 +61,6 @@ import forestry.api.core.EnumTemperature;
import forestry.api.core.ForestryAPI;
import forestry.api.core.IErrorLogic;
import forestry.api.genetics.IAllele;
import forestry.apiculture.BeekeepingLogic;
import forestry.apiculture.blocks.BlockBeeHives;
import forestry.apiculture.genetics.BeeDefinition;
import forestry.apiculture.genetics.alleles.AlleleEffect;
@@ -78,9 +79,10 @@ public class TileHive extends TileEntity implements ITickable, IHiveTile, IActiv
private final InventoryAdapter contained = new InventoryAdapter(2, "Contained");
private final HiveBeeHousingInventory inventory;
private final BeekeepingLogic beeLogic;
private final WorldgenBeekeepingLogic beeLogic;
private final IErrorLogic errorLogic;
private final Predicate<EntityLivingBase> beeTargetPredicate;
private final TickHelper tickHelper = new TickHelper();
@Nullable
private IBee containedBee = null;
@@ -96,7 +98,7 @@ public class TileHive extends TileEntity implements ITickable, IHiveTile, IActiv
public TileHive() {
inventory = new HiveBeeHousingInventory(this);
beeLogic = new BeekeepingLogic(this);
beeLogic = new WorldgenBeekeepingLogic(this);
errorLogic = ForestryAPI.errorStateRegistry.createErrorLogic();
beeTargetPredicate = new BeeTargetPredicate(this);
}
@@ -106,12 +108,13 @@ public class TileHive extends TileEntity implements ITickable, IHiveTile, IActiv
if (Config.generateBeehivesDebug) {
return;
}
tickHelper.onTick();
if (world.isRemote) {
if (!updatedLight && world.getWorldTime() % 100 == 0) {
if (!updatedLight && tickHelper.updateOnInterval(100)) {
updatedLight = world.checkLightFor(EnumSkyBlock.BLOCK, getPos());
}
if (active && world.rand.nextInt(4) == 0) {
if (active && tickHelper.updateOnInterval(4)) {
if (beeLogic.canDoBeeFX()) {
beeLogic.doBeeFX();
}
@@ -119,7 +122,7 @@ public class TileHive extends TileEntity implements ITickable, IHiveTile, IActiv
} else {
boolean canWork = beeLogic.canWork(); // must be called every tick to stay updated
if (world.rand.nextInt(angry ? 10 : 200) == 0) {
if (tickHelper.updateOnInterval(angry ? 10 : 200)) {
if (calmTime == 0) {
if (canWork) {
if(world.getWorldInfo().getDifficulty() != EnumDifficulty.PEACEFUL) {
@@ -12,18 +12,26 @@ package forestry.core;
import com.google.common.collect.LinkedListMultimap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraft.world.gen.IChunkGenerator;
import net.minecraftforge.event.world.ChunkDataEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.gameevent.TickEvent.WorldTickEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import forestry.core.config.Config;
import forestry.core.config.Constants;
@@ -34,6 +42,7 @@ public class TickHandlerCoreServer {
private final WorldGenerator worldGenerator;
private final LinkedListMultimap<Integer, ChunkCoords> chunkRegenList = LinkedListMultimap.create();
private final IntSet checkForRetrogen = new IntArraySet();
public TickHandlerCoreServer(WorldGenerator worldGenerator) {
this.worldGenerator = worldGenerator;
@@ -54,27 +63,49 @@ public class TickHandlerCoreServer {
}
}
if (Config.doRetrogen) {
World world = event.world;
if (Config.doRetrogen && event.world instanceof WorldServer) {
WorldServer world = (WorldServer) event.world;
int dimensionID = world.provider.getDimension();
List<ChunkCoords> chunkList = chunkRegenList.get(dimensionID);
if (!chunkList.isEmpty()) {
ChunkCoords coords = chunkList.get(0);
chunkList.remove(0);
// This bit is from FML's GameRegistry.generateWorld where the seed is constructed.
long worldSeed = world.getSeed();
Random random = new Random(worldSeed);
long xSeed = random.nextLong() >> 2 + 1L;
long zSeed = random.nextLong() >> 2 + 1L;
random.setSeed(xSeed * coords.x + zSeed * coords.z ^ worldSeed);
worldGenerator.retroGen(random, coords.x, coords.z, world);
if (checkForRetrogen.contains(dimensionID)) {
List<ChunkCoords> chunkList = chunkRegenList.get(dimensionID);
Iterator<ChunkCoords> iterator = chunkList.iterator();
while (iterator.hasNext()) {
ChunkCoords coords = iterator.next();
if (canDecorate(world, coords)) {
iterator.remove();
Random random = getRetrogenRandom(world, coords);
worldGenerator.retroGen(random, coords.x, coords.z, world);
}
}
checkForRetrogen.remove(dimensionID);
}
}
}
/**
* This is from {@link GameRegistry#generateWorld(int, int, World, IChunkGenerator, IChunkProvider)} where the seed is constructed.
*/
private static Random getRetrogenRandom(World world, ChunkCoords coords) {
long worldSeed = world.getSeed();
Random random = new Random(worldSeed);
long xSeed = random.nextLong() >> 2 + 1L;
long zSeed = random.nextLong() >> 2 + 1L;
random.setSeed(xSeed * coords.x + zSeed * coords.z ^ worldSeed);
return random;
}
private static boolean canDecorate(WorldServer server, ChunkCoords chunkCoords) {
ChunkProviderServer chunkProvider = server.getChunkProvider();
for (int x = 0; x <= 1; x++) {
for (int z = 0; z <= 1; z++) {
if (!chunkProvider.chunkExists(chunkCoords.x + x, chunkCoords.z + z)) {
return false;
}
}
}
return true;
}
@SubscribeEvent
public void chunkSaveEventHandler(ChunkDataEvent.Save event) {
NBTTagCompound tag = new NBTTagCompound();
@@ -94,6 +125,7 @@ public class TickHandlerCoreServer {
if (!tag.hasKey("retrogen") || Config.forceRetrogen) {
ChunkCoords coords = new ChunkCoords(event.getChunk());
chunkRegenList.put(coords.dimension, coords);
checkForRetrogen.add(coords.dimension);
}
}
}
@@ -68,32 +68,30 @@ public class ParticleRender {
int color = genome.getPrimary().getSpriteColour(0);
if (!flowerPositions.isEmpty()) {
int randomInt = world.rand.nextInt(100);
int randomInt = world.rand.nextInt(100);
if (housing instanceof IHiveTile) {
if (((IHiveTile) housing).isAngry() || randomInt >= 85) {
List<EntityLivingBase> entitiesInRange = AlleleEffect.getEntitiesInRange(genome, housing, EntityLivingBase.class);
if (!entitiesInRange.isEmpty()) {
EntityLivingBase entity = entitiesInRange.get(world.rand.nextInt(entitiesInRange.size()));
Particle particle = new ParticleBeeTargetEntity(world, particleStart, entity, color);
effectRenderer.addEffect(particle);
return;
}
if (housing instanceof IHiveTile) {
if (((IHiveTile) housing).isAngry() || randomInt >= 85) {
List<EntityLivingBase> entitiesInRange = AlleleEffect.getEntitiesInRange(genome, housing, EntityLivingBase.class);
if (!entitiesInRange.isEmpty()) {
EntityLivingBase entity = entitiesInRange.get(world.rand.nextInt(entitiesInRange.size()));
Particle particle = new ParticleBeeTargetEntity(world, particleStart, entity, color);
effectRenderer.addEffect(particle);
return;
}
}
}
if (randomInt < 75) {
BlockPos destination = flowerPositions.get(world.rand.nextInt(flowerPositions.size()));
Particle particle = new ParticleBeeRoundTrip(world, particleStart, destination, color);
effectRenderer.addEffect(particle);
} else {
Vec3i area = AlleleEffect.getModifiedArea(genome, housing);
Vec3i offset = housing.getCoordinates().add(-area.getX() / 2, -area.getY() / 4, -area.getZ() / 2);
BlockPos destination = VectUtil.getRandomPositionInArea(world.rand, area).add(offset);
Particle particle = new ParticleBeeExplore(world, particleStart, destination, color);
effectRenderer.addEffect(particle);
}
if (randomInt < 75 && !flowerPositions.isEmpty()) {
BlockPos destination = flowerPositions.get(world.rand.nextInt(flowerPositions.size()));
Particle particle = new ParticleBeeRoundTrip(world, particleStart, destination, color);
effectRenderer.addEffect(particle);
} else {
Vec3i area = AlleleEffect.getModifiedArea(genome, housing);
Vec3i offset = housing.getCoordinates().add(-area.getX() / 2, -area.getY() / 4, -area.getZ() / 2);
BlockPos destination = VectUtil.getRandomPositionInArea(world.rand, area).add(offset);
Particle particle = new ParticleBeeExplore(world, particleStart, destination, color);
effectRenderer.addEffect(particle);
}
}
@@ -27,6 +27,7 @@ import forestry.core.network.PacketBufferForestry;
import forestry.core.network.packets.PacketTileStream;
import forestry.core.utils.NBTUtilForestry;
import forestry.core.utils.NetworkUtil;
import forestry.core.utils.TickHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
@@ -48,14 +49,12 @@ import net.minecraftforge.items.wrapper.SidedInvWrapper;
//@Optional.Interface(iface = "buildcraft.api.statements.ITriggerProvider", modid = "BuildCraftAPI|statements")
public abstract class TileForestry extends TileEntity implements IStreamable, IErrorLogicSource, ISidedInventory, IFilterSlotDelegate, ITitled, ILocatable, IGuiHandlerTile, ITickable {
private static final Random rand = new Random();
private final ErrorLogic errorHandler = new ErrorLogic();
private final AdjacentTileCache tileCache = new AdjacentTileCache(this);
private IInventoryAdapter inventory = FakeInventoryAdapter.instance();
private int tickCount = rand.nextInt(256);
private final TickHelper tickHelper = new TickHelper();
private boolean needsNetworkUpdate = false;
protected AdjacentTileCache getTileCache() {
@@ -81,7 +80,7 @@ public abstract class TileForestry extends TileEntity implements IStreamable, IE
// / UPDATING
@Override
public final void update() {
tickCount++;
tickHelper.onTick();
if (!world.isRemote) {
updateServerSide();
@@ -103,7 +102,7 @@ public abstract class TileForestry extends TileEntity implements IStreamable, IE
}
protected final boolean updateOnInterval(int tickInterval) {
return tickCount % tickInterval == 0;
return tickHelper.updateOnInterval(tickInterval);
}
// / SAVING & LOADING
@@ -0,0 +1,63 @@
package forestry.core.utils;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
/**
* A set with fast {@link #contains(Object)} for IBlockState
*/
public class BlockStateSet extends AbstractSet<IBlockState> {
private final Set<IBlockState> blockStates = new HashSet<>();
private final Map<Block, Integer> blocks = new IdentityHashMap<>();
@Override
public boolean add(IBlockState blockState) {
Block block = blockState.getBlock();
Integer count = blocks.getOrDefault(block, 0);
blocks.put(block, count + 1);
return blockStates.add(blockState);
}
@Override
public boolean remove(Object o) {
IBlockState blockState = (IBlockState) o;
Block block = blockState.getBlock();
Integer count = blocks.getOrDefault(block, 0);
if (count > 0) {
blocks.put(block, count - 1);
} else {
blocks.remove(block);
}
return blockStates.remove(blockState);
}
@Override
public boolean contains(Object o) {
IBlockState blockState = (IBlockState) o;
Block block = blockState.getBlock();
return blocks.containsKey(block) && blockStates.contains(blockState);
}
@Override
public void clear() {
blockStates.clear();
blocks.clear();
}
@Override
public Iterator<IBlockState> iterator() {
return blockStates.iterator();
}
@Override
public int size() {
return blockStates.size();
}
}
@@ -0,0 +1,16 @@
package forestry.core.utils;
import java.util.Random;
public final class TickHelper {
private static final Random rand = new Random();
private int tickCount = rand.nextInt(2048);
public void onTick() {
tickCount++;
}
public boolean updateOnInterval(int tickInterval) {
return tickCount % tickInterval == 0;
}
}
@@ -11,6 +11,7 @@
package forestry.core.utils;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Random;
import com.google.common.collect.AbstractIterator;
@@ -57,11 +58,11 @@ public final class VectUtil {
}
}
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxFromCenterMutable(World world, final BlockPos from, final BlockPos center, final BlockPos to) {
public static Iterator<BlockPos.MutableBlockPos> getAllInBoxFromCenterMutable(World world, final BlockPos from, final BlockPos center, final BlockPos to) {
final BlockPos minPos = new BlockPos(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()));
final BlockPos maxPos = new BlockPos(Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
return () -> new MutableBlockPosSpiralIterator(world, center, maxPos, minPos);
return new MutableBlockPosSpiralIterator(world, center, maxPos, minPos);
}
private static class MutableBlockPosSpiralIterator extends AbstractIterator<BlockPos.MutableBlockPos> {