major builder improvements

This commit is contained in:
asiekierka 2015-10-06 16:12:16 +02:00
parent 4e38f7e027
commit 69e29342f0
8 changed files with 200 additions and 65 deletions

View file

@ -1,3 +1,8 @@
Improvements:
* Builder "Needed" list now shows exact amount of required blocks on hover (asie)
* More Builder optimizations (asie)
Bugs fixed:
* [#3056] PipeTransportFluids crash (asie)

View file

@ -75,6 +75,7 @@ import buildcraft.builders.BlockQuarry;
import buildcraft.builders.BlueprintServerDatabase;
import buildcraft.builders.BuilderProxy;
import buildcraft.builders.BuilderProxyClient;
import buildcraft.builders.BuilderTooltipHandler;
import buildcraft.builders.BuildersGuiHandler;
import buildcraft.builders.HeuristicBlockDetection;
import buildcraft.builders.ItemBlueprintStandard;
@ -344,6 +345,8 @@ public class BuildCraftBuilders extends BuildCraftMod {
public void init(FMLInitializationEvent evt) {
NetworkRegistry.INSTANCE.registerGuiHandler(instance, new BuildersGuiHandler());
MinecraftForge.EVENT_BUS.register(new BuilderTooltipHandler());
// Standard blocks
ISchematicRegistry schemes = BuilderAPI.schematicRegistry;
schemes.registerSchematicBlock(Blocks.air, SchematicAir.class);

View file

@ -94,6 +94,7 @@ import buildcraft.core.TilePathMarker;
import buildcraft.core.Version;
import buildcraft.core.blueprints.SchematicHelper;
import buildcraft.core.blueprints.SchematicRegistry;
import buildcraft.core.blueprints.BuildingSlotMapIterator;
import buildcraft.core.builders.patterns.FillerPattern;
import buildcraft.core.builders.patterns.FillerRegistry;
import buildcraft.core.builders.patterns.PatternBox;
@ -195,6 +196,7 @@ public class BuildCraftCore extends BuildCraftMod {
public static boolean canEnginesExplode = false;
public static int itemLifespan = 1200;
public static int updateFactor = 10;
public static int builderMaxPerItemFactor = 1024;
public static long longUpdateFactor = 40;
public static BuildCraftConfiguration mainConfiguration;
public static ConfigManager mainConfigManager;
@ -299,6 +301,8 @@ public class BuildCraftCore extends BuildCraftMod {
mainConfigManager.getCat("debug").setShowInGui(false);
mainConfigManager.getCat("vars").setShowInGui(false);
mainConfigManager.register("general.builderMaxIterationsPerItemFactor", BuildCraftCore.builderMaxPerItemFactor, "Lower this number if BuildCraft builders/fillers are causing TPS lag. Raise it if you think they are being too slow.", ConfigManager.RestartRequirement.NONE);
mainConfigManager.register("general.miningBreaksPlayerProtectedBlocks", false, "Should BuildCraft miners be allowed to break blocks using player-specific protection?", ConfigManager.RestartRequirement.NONE);
mainConfigManager.register("general.updateCheck", true, "Should I check the BuildCraft version on startup?", ConfigManager.RestartRequirement.NONE);
mainConfigManager.register("display.hidePowerValues", false, "Should all power values (RF, RF/t) be hidden?", ConfigManager.RestartRequirement.NONE);
@ -549,19 +553,30 @@ public class BuildCraftCore extends BuildCraftMod {
public void serverStarting(FMLServerStartingEvent event) {
event.registerServerCommand(commandBuildcraft);
/* Increase the builder speed in singleplayer mode.
Singleplayer users generally run far fewer of them. */
if (FMLCommonHandler.instance().getSide() == Side.CLIENT) {
BuildingSlotMapIterator.MAX_PER_ITEM = builderMaxPerItemFactor * 4;
} else {
BuildingSlotMapIterator.MAX_PER_ITEM = builderMaxPerItemFactor;
}
if (Utils.CAULDRON_DETECTED) {
BCLog.logger.warn("############################################");
BCLog.logger.warn("# #");
BCLog.logger.warn("# Cauldron has been detected! Please keep #");
BCLog.logger.warn("# in mind that BuildCraft does NOT support #");
BCLog.logger.warn("# Cauldron and we do not promise to fix #");
BCLog.logger.warn("# bugs caused by its modifications to the #");
BCLog.logger.warn("# Minecraft engine. Please reconsider. #");
BCLog.logger.warn("# in mind that BuildCraft may NOT provide #");
BCLog.logger.warn("# support to Cauldron users, as the mod is #");
BCLog.logger.warn("# primarily tested without Bukkit/Spigot's #");
BCLog.logger.warn("# changes to the Minecraft internals. #");
BCLog.logger.warn("# #");
BCLog.logger.warn("# Any lag caused by BuildCraft on top of #");
BCLog.logger.warn("# Cauldron likely arises from our fixes to #");
BCLog.logger.warn("# their bugs, so please don't report that #");
BCLog.logger.warn("# either. Thanks for your attention! ~BC #");
BCLog.logger.warn("# Cauldron likely arises from workarounds #");
BCLog.logger.warn("# which we apply to make sure BuildCraft #");
BCLog.logger.warn("# works properly with Cauldron installed. #");
BCLog.logger.warn("# #");
BCLog.logger.warn("# Thanks for your attention! ~ BC devs #");
BCLog.logger.warn("# #");
BCLog.logger.warn("############################################");
@ -617,6 +632,7 @@ public class BuildCraftCore extends BuildCraftMod {
} else if (restartType == ConfigManager.RestartRequirement.WORLD) {
reloadConfig(ConfigManager.RestartRequirement.NONE);
} else {
builderMaxPerItemFactor = mainConfigManager.get("general.builderMaxIterationsPerItemFactor").getInt();
hideFluidNumbers = mainConfigManager.get("display.hideFluidValues").getBoolean();
hidePowerNumbers = mainConfigManager.get("display.hidePowerValues").getBoolean();
itemLifespan = mainConfigManager.get("general.itemLifespan").getInt();
@ -625,6 +641,8 @@ public class BuildCraftCore extends BuildCraftMod {
miningMultiplier = (float) mainConfigManager.get("power.miningUsageMultiplier").getDouble();
miningAllowPlayerProtectedBlocks = mainConfigManager.get("general.miningBreaksPlayerProtectedBlocks").getBoolean();
BuildingSlotMapIterator.MAX_PER_ITEM = builderMaxPerItemFactor;
if (mainConfigManager.get("general.updateCheck").getBoolean(true)) {
Version.check();
}

View file

@ -0,0 +1,35 @@
package buildcraft.builders;
import java.util.List;
import net.minecraft.util.EnumChatFormatting;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import buildcraft.builders.gui.ContainerBuilder;
import buildcraft.core.blueprints.RequirementItemStack;
/**
* Created by asie on 10/6/15.
*/
public class BuilderTooltipHandler {
@SubscribeEvent
public void itemTooltipEvent(ItemTooltipEvent event) {
if (event.itemStack != null && event.entityPlayer != null && event.entityPlayer.openContainer != null
&& event.entityPlayer.openContainer instanceof ContainerBuilder) {
ContainerBuilder containerBuilder = (ContainerBuilder) event.entityPlayer.openContainer;
TileBuilder builder = containerBuilder.getBuilder();
if (builder != null) {
List<RequirementItemStack> needs = builder.getNeededItems();
if (needs != null) {
for (RequirementItemStack ris : needs) {
if (ris.stack == event.itemStack) {
event.toolTip.add(EnumChatFormatting.GRAY + "" + EnumChatFormatting.ITALIC + "Needed: " + ris.size);
}
}
}
}
}
}
}

View file

@ -39,6 +39,7 @@ import buildcraft.api.core.BlockIndex;
import buildcraft.api.core.IInvSlot;
import buildcraft.api.core.IPathProvider;
import buildcraft.api.core.Position;
import buildcraft.api.core.SafeTimeTracker;
import buildcraft.api.robots.IRequestProvider;
import buildcraft.api.tiles.IControllable;
import buildcraft.api.tiles.IHasWork;
@ -80,6 +81,9 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
};
public TankManager<Tank> fluidTank = new TankManager<Tank>(fluidTanks);
private SafeTimeTracker networkUpdateTracker = new SafeTimeTracker(BuildCraftCore.updateFactor / 2);
private boolean shouldUpdateRequirements;
private SimpleInventory inv = new SimpleInventory(28, "Builder", 64);
private BptBuilderBase currentBuilder;
private RecursiveBlueprintBuilder recursiveBuilder;
@ -216,7 +220,6 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
return;
}
if (initNBT != null) {
iterateBpt(true);
@ -262,7 +265,6 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
if (path != null && pathLasers.size() == 0) {
createLasersForPath();
sendNetworkUpdate();
}
@ -333,7 +335,7 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
currentPathIterator = null;
}
updateRequirements();
scheduleRequirementUpdate();
sendNetworkUpdate();
@ -373,13 +375,13 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
done = false;
}
updateRequirements();
scheduleRequirementUpdate();
} else {
if (currentBuilder != null && currentBuilder.isDone(this)) {
currentBuilder.postProcessing(worldObj);
currentBuilder = recursiveBuilder.nextBuilder();
updateRequirements();
scheduleRequirementUpdate();
} else {
BlueprintBase bpt = instanciateBlueprint();
@ -389,7 +391,7 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
currentBuilder = recursiveBuilder.nextBuilder();
updateRequirements();
scheduleRequirementUpdate();
}
}
@ -572,6 +574,11 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
return;
}
if (shouldUpdateRequirements && networkUpdateTracker.markTimeIfDelay(worldObj)) {
updateRequirements();
shouldUpdateRequirements = false;
}
if ((currentBuilder == null || currentBuilder.isDone(this))
&& box.isInitialized()) {
box.reset();
@ -591,7 +598,7 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
}
if (!isBuilding && this.isBuildingBlueprint()) {
updateRequirements();
scheduleRequirementUpdate();
}
isBuilding = this.isBuildingBlueprint();
@ -612,7 +619,7 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
}
public List<RequirementItemStack> getNeededItems() {
return requiredToBuild;
return worldObj.isRemote ? requiredToBuild : (currentBuilder instanceof BptBuilderBlueprint ? ((BptBuilderBlueprint) currentBuilder).getNeededItems() : null);
}
@Override
@ -716,16 +723,16 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
public void build() {
if (currentBuilder != null) {
if (currentBuilder.buildNextSlot(worldObj, this, xCoord, yCoord, zCoord)) {
updateRequirements();
scheduleRequirementUpdate();
}
}
}
public void updateRequirements() {
private void updateRequirements() {
List<RequirementItemStack> reqCopy = null;
if (currentBuilder instanceof BptBuilderBlueprint) {
currentBuilder.initialize();
reqCopy = ((BptBuilderBlueprint) currentBuilder).neededItems;
reqCopy = ((BptBuilderBlueprint) currentBuilder).getNeededItems();
}
for (EntityPlayer p : guiWatchers) {
@ -733,11 +740,15 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
}
}
public void updateRequirements(EntityPlayer caller) {
public void scheduleRequirementUpdate() {
shouldUpdateRequirements = true;
}
public void updateRequirementsOnGuiOpen(EntityPlayer caller) {
List<RequirementItemStack> reqCopy = null;
if (currentBuilder instanceof BptBuilderBlueprint) {
currentBuilder.initialize();
reqCopy = ((BptBuilderBlueprint) currentBuilder).neededItems;
reqCopy = ((BptBuilderBlueprint) currentBuilder).getNeededItems();
}
BuildCraftCore.instance.sendToPlayer(caller, getItemRequirementsPacket(reqCopy));
@ -830,7 +841,7 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
} else {
BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;
return bpt.neededItems.size();
return bpt.getNeededItems().size();
}
}
@ -842,12 +853,13 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
return null;
} else {
BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;
List<RequirementItemStack> neededItems = bpt.getNeededItems();
if (bpt.neededItems.size() <= slot) {
if (neededItems.size() <= slot) {
return null;
}
RequirementItemStack requirement = bpt.neededItems.get(slot);
RequirementItemStack requirement = neededItems.get(slot);
int qty = quantityMissing(requirement.stack, requirement.size);
@ -868,12 +880,13 @@ public class TileBuilder extends TileAbstractBuilder implements IHasWork, IFluid
return stack;
} else {
BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;
List<RequirementItemStack> neededItems = bpt.getNeededItems();
if (bpt.neededItems.size() <= slot) {
if (neededItems.size() <= slot) {
return stack;
}
RequirementItemStack requirement = bpt.neededItems.get(slot);
RequirementItemStack requirement = neededItems.get(slot);
int qty = quantityMissing(requirement.stack, requirement.size);

View file

@ -52,11 +52,15 @@ public class ContainerBuilder extends BuildCraftContainer {
if (!builder.getWorldObj().isRemote && playerInventory instanceof InventoryPlayer) {
// Refresh the requirements list for the player opening the GUI,
// in case he does not have it.
builder.updateRequirements(((InventoryPlayer) playerInventory).player);
builder.updateRequirementsOnGuiOpen(((InventoryPlayer) playerInventory).player);
builder.addGuiWatcher(((InventoryPlayer) playerInventory).player);
}
}
public TileBuilder getBuilder() {
return builder;
}
@Override
public void onContainerClosed(EntityPlayer player) {
super.onContainerClosed(player);

View file

@ -48,7 +48,6 @@ import buildcraft.core.builders.BuildingSlot;
import buildcraft.core.builders.BuildingSlotBlock;
import buildcraft.core.builders.BuildingSlotBlock.Mode;
import buildcraft.core.builders.BuildingSlotEntity;
import buildcraft.core.builders.BuildingSlotMapIterator;
import buildcraft.core.builders.IBuildingItemsProvider;
import buildcraft.core.builders.TileAbstractBuilder;
import buildcraft.core.lib.inventory.InventoryCopy;
@ -56,12 +55,12 @@ import buildcraft.core.lib.inventory.InventoryIterator;
import buildcraft.core.lib.utils.BlockUtils;
public class BptBuilderBlueprint extends BptBuilderBase {
public ArrayList<RequirementItemStack> neededItems = new ArrayList<RequirementItemStack>();
protected HashSet<Integer> builtEntities = new HashSet<Integer>();
protected HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>> buildList = new HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>>();
protected int[] buildStageOccurences;
private ArrayList<RequirementItemStack> neededItems = new ArrayList<RequirementItemStack>();
private HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>> buildList = new HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>>();
private int[] buildStageOccurences;
private LinkedList<BuildingSlotEntity> entityList = new LinkedList<BuildingSlotEntity>();
private LinkedList<BuildingSlot> postProcessing = new LinkedList<BuildingSlot>();
private BuildingSlotMapIterator iterator;
@ -254,8 +253,6 @@ public class BptBuilderBlueprint extends BptBuilderBase {
}
private void checkDone() {
recomputeNeededItems();
if (getBuildListCount() == 0 && entityList.size() == 0) {
done = true;
} else {
@ -346,7 +343,7 @@ public class BptBuilderBlueprint extends BptBuilderBase {
}
if (iterator == null) {
iterator = new BuildingSlotMapIterator(buildList, builder, buildStageOccurences);
iterator = new BuildingSlotMapIterator(this, builder);
}
BuildingSlotBlock slot;
@ -473,6 +470,7 @@ public class BptBuilderBlueprint extends BptBuilderBase {
return null;
}
// TODO: Remove recomputeNeededItems() and replace with something more efficient
private BuildingSlot internalGetNextEntity(World world, TileAbstractBuilder builder) {
Iterator<BuildingSlotEntity> it = entityList.iterator();
@ -481,12 +479,14 @@ public class BptBuilderBlueprint extends BptBuilderBase {
if (slot.isAlreadyBuilt(context)) {
it.remove();
recomputeNeededItems();
} else {
if (checkRequirements(builder, slot.schematic)) {
builder.consumeEnergy(slot.getEnergyRequirement());
useRequirements(builder, slot);
it.remove();
recomputeNeededItems();
postProcessing.add(slot);
builtEntities.add(slot.sequenceNumber);
return slot;
@ -656,7 +656,82 @@ public class BptBuilderBlueprint extends BptBuilderBase {
}
}
public void recomputeNeededItems() {
public List<RequirementItemStack> getNeededItems() {
return neededItems;
}
protected void onRemoveBuildingSlotBlock(BuildingSlotBlock slot) {
buildStageOccurences[slot.buildStage]--;
LinkedList<ItemStack> stacks = new LinkedList<ItemStack>();
try {
stacks = slot.getRequirements(context);
} catch (Throwable t) {
// Defensive code against errors in implementers
t.printStackTrace();
BCLog.logger.throwing(t);
}
HashMap<StackKey, Integer> computeStacks = new HashMap<StackKey, Integer>();
for (ItemStack stack : stacks) {
if (stack == null || stack.getItem() == null || stack.stackSize == 0) {
continue;
}
StackKey key = new StackKey(stack);
if (!computeStacks.containsKey(key)) {
computeStacks.put(key, stack.stackSize);
} else {
Integer num = computeStacks.get(key);
num += stack.stackSize;
computeStacks.put(key, num);
}
}
for (RequirementItemStack ris : neededItems) {
StackKey stackKey = new StackKey(ris.stack);
if (computeStacks.containsKey(stackKey)) {
Integer num = computeStacks.get(stackKey);
if (ris.size <= num) {
recomputeNeededItems();
return;
} else {
neededItems.set(neededItems.indexOf(ris), new RequirementItemStack(ris.stack, ris.size - num));
}
}
}
sortNeededItems();
}
private void sortNeededItems() {
Collections.sort(neededItems, new Comparator<RequirementItemStack>() {
@Override
public int compare(RequirementItemStack o1, RequirementItemStack o2) {
if (o1.size != o2.size) {
return o1.size < o2.size ? 1 : -1;
} else {
ItemStack os1 = o1.stack;
ItemStack os2 = o2.stack;
if (Item.getIdFromItem(os1.getItem()) > Item.getIdFromItem(os2.getItem())) {
return -1;
} else if (Item.getIdFromItem(os1.getItem()) < Item.getIdFromItem(os2.getItem())) {
return 1;
} else if (os1.getItemDamage() > os2.getItemDamage()) {
return -1;
} else if (os1.getItemDamage() < os2.getItemDamage()) {
return 1;
} else {
return 0;
}
}
}
});
}
private void recomputeNeededItems() {
neededItems.clear();
HashMap<StackKey, Integer> computeStacks = new HashMap<StackKey, Integer>();
@ -730,28 +805,7 @@ public class BptBuilderBlueprint extends BptBuilderBase {
neededItems.add(new RequirementItemStack(e.getKey().stack.copy(), e.getValue()));
}
Collections.sort(neededItems, new Comparator<RequirementItemStack>() {
@Override
public int compare(RequirementItemStack o1, RequirementItemStack o2) {
if (o1.size != o2.size) {
return o1.size < o2.size ? 1 : -1;
} else {
ItemStack os1 = o1.stack;
ItemStack os2 = o2.stack;
if (Item.getIdFromItem(os1.getItem()) > Item.getIdFromItem(os2.getItem())) {
return -1;
} else if (Item.getIdFromItem(os1.getItem()) < Item.getIdFromItem(os2.getItem())) {
return 1;
} else if (os1.getItemDamage() > os2.getItemDamage()) {
return -1;
} else if (os1.getItemDamage() < os2.getItemDamage()) {
return 1;
} else {
return 0;
}
}
}
});
sortNeededItems();
}
@Override
@ -793,5 +847,4 @@ public class BptBuilderBlueprint extends BptBuilderBase {
builtEntities.add(i);
}
}
}

View file

@ -6,7 +6,7 @@
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package buildcraft.core.builders;
package buildcraft.core.blueprints;
import java.util.HashSet;
import java.util.Iterator;
@ -17,10 +17,14 @@ import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.world.WorldSettings;
import buildcraft.core.builders.BuilderItemMetaPair;
import buildcraft.core.builders.BuildingSlotBlock;
import buildcraft.core.builders.TileAbstractBuilder;
import buildcraft.core.lib.fluids.Tank;
public class BuildingSlotMapIterator {
private static final int MAX_PER_ITEM = 64;
public static int MAX_PER_ITEM = 512;
private final BptBuilderBlueprint builderBlueprint;
private final Map<BuilderItemMetaPair, List<BuildingSlotBlock>> slotMap;
private final Set<BuilderItemMetaPair> availablePairs = new HashSet<BuilderItemMetaPair>();
private final int[] buildStageOccurences;
@ -30,10 +34,10 @@ public class BuildingSlotMapIterator {
private List<BuildingSlotBlock> slots;
private int slotPos, slotFound;
public BuildingSlotMapIterator(Map<BuilderItemMetaPair, List<BuildingSlotBlock>> slots, TileAbstractBuilder builder,
int[] buildStageOccurences) {
this.slotMap = slots;
this.buildStageOccurences = buildStageOccurences;
public BuildingSlotMapIterator(BptBuilderBlueprint builderBlueprint, TileAbstractBuilder builder) {
this.builderBlueprint = builderBlueprint;
this.slotMap = builderBlueprint.buildList;
this.buildStageOccurences = builderBlueprint.buildStageOccurences;
this.isCreative = builder == null
|| builder.getWorldObj().getWorldInfo().getGameType() == WorldSettings.GameType.CREATIVE;
@ -107,7 +111,7 @@ public class BuildingSlotMapIterator {
}
public void remove() {
buildStageOccurences[slots.get(slotPos).buildStage]--;
builderBlueprint.onRemoveBuildingSlotBlock(slots.get(slotPos));
slots.set(slotPos, null);
}