RAM-powered Minecarts

- Fixed critical memory leak from minecart controller listeners
- Made JEI heat conditions a little more readable
This commit is contained in:
simibubi 2020-10-20 14:56:07 +02:00
parent df252b3e30
commit fdd1e22c3e
4 changed files with 50 additions and 11 deletions

View file

@ -177,8 +177,8 @@ public class BasinCategory extends CreateRecipeCategory<BasinRecipe> {
AllGuiTextures heatBar = noHeat ? AllGuiTextures.JEI_NO_HEAT_BAR : AllGuiTextures.JEI_HEAT_BAR; AllGuiTextures heatBar = noHeat ? AllGuiTextures.JEI_NO_HEAT_BAR : AllGuiTextures.JEI_HEAT_BAR;
heatBar.draw(4, 80); heatBar.draw(4, 80);
Minecraft.getInstance().fontRenderer.drawStringWithShadow(Lang.translate(requiredHeat.getTranslationKey()), 9, Minecraft.getInstance().fontRenderer.drawString(Lang.translate(requiredHeat.getTranslationKey()), 9,
85, requiredHeat.getColor()); 86, requiredHeat.getColor());
} }
} }

View file

@ -25,6 +25,7 @@ import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.INBT;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -33,6 +34,7 @@ import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullConsumer;
import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.ChunkEvent;
@ -45,6 +47,37 @@ public class CapabilityMinecartController implements ICapabilitySerializable<Com
static WorldAttached<List<AbstractMinecartEntity>> queuedAdditions; static WorldAttached<List<AbstractMinecartEntity>> queuedAdditions;
static WorldAttached<List<UUID>> queuedUnloads; static WorldAttached<List<UUID>> queuedUnloads;
/**
* This callback wrapper ensures that the listeners map in the controller
* capability only ever contains one instance
*/
public static class MinecartRemovalListener implements NonNullConsumer<LazyOptional<MinecartController>> {
private World world;
private AbstractMinecartEntity cart;
public MinecartRemovalListener(World world, AbstractMinecartEntity cart) {
this.world = world;
this.cart = cart;
}
@Override
public boolean equals(Object obj) {
return obj instanceof MinecartRemovalListener;
}
@Override
public int hashCode() {
return 100;
}
@Override
public void accept(LazyOptional<MinecartController> t) {
onCartRemoved(world, cart);
}
}
static { static {
loadedMinecartsByUUID = new WorldAttached<>(HashMap::new); loadedMinecartsByUUID = new WorldAttached<>(HashMap::new);
loadedMinecartsWithCoupling = new WorldAttached<>(HashSet::new); loadedMinecartsWithCoupling = new WorldAttached<>(HashSet::new);
@ -66,10 +99,12 @@ public class CapabilityMinecartController implements ICapabilitySerializable<Com
for (AbstractMinecartEntity cart : queued) { for (AbstractMinecartEntity cart : queued) {
UUID uniqueID = cart.getUniqueID(); UUID uniqueID = cart.getUniqueID();
cartsWithCoupling.remove(uniqueID); cartsWithCoupling.remove(uniqueID);
LazyOptional<MinecartController> capability = cart.getCapability(MINECART_CONTROLLER_CAPABILITY); LazyOptional<MinecartController> capability = cart.getCapability(MINECART_CONTROLLER_CAPABILITY);
MinecartController controller = capability.orElse(null); MinecartController controller = capability.orElse(null);
capability.addListener(cap -> onCartRemoved(world, cart)); capability.addListener(new MinecartRemovalListener(world, cart));
carts.put(uniqueID, controller); carts.put(uniqueID, controller);
capability.ifPresent(mc -> { capability.ifPresent(mc -> {
if (mc.isLeadingCoupling()) if (mc.isLeadingCoupling())
cartsWithCoupling.add(uniqueID); cartsWithCoupling.add(uniqueID);
@ -128,14 +163,14 @@ public class CapabilityMinecartController implements ICapabilitySerializable<Com
MinecartController next = CouplingHandler.getNextInCouplingChain(world, controller, forward); MinecartController next = CouplingHandler.getNextInCouplingChain(world, controller, forward);
if (next == null || next == MinecartController.EMPTY) if (next == null || next == MinecartController.EMPTY)
continue; continue;
next.removeConnection(!forward); next.removeConnection(!forward);
if (controller.hasContraptionCoupling(forward)) if (controller.hasContraptionCoupling(forward))
continue; continue;
AbstractMinecartEntity cart = next.cart(); AbstractMinecartEntity cart = next.cart();
if (cart == null) if (cart == null)
continue; continue;
Vec3d itemPos = cart.getPositionVec() Vec3d itemPos = cart.getPositionVec()
.add(removedPos) .add(removedPos)
.scale(.5f); .scale(.5f);
@ -165,8 +200,13 @@ public class CapabilityMinecartController implements ICapabilitySerializable<Com
Entity entity = event.getObject(); Entity entity = event.getObject();
if (!(entity instanceof AbstractMinecartEntity)) if (!(entity instanceof AbstractMinecartEntity))
return; return;
event.addCapability(Create.asResource("minecart_controller"), CapabilityMinecartController capability = new CapabilityMinecartController((AbstractMinecartEntity) entity);
new CapabilityMinecartController((AbstractMinecartEntity) entity)); ResourceLocation id = Create.asResource("minecart_controller");
event.addCapability(id, capability);
event.addListener(() -> {
if (capability.cap.isPresent())
capability.cap.invalidate();
});
queuedAdditions.get(entity.getEntityWorld()) queuedAdditions.get(entity.getEntityWorld())
.add((AbstractMinecartEntity) entity); .add((AbstractMinecartEntity) entity);
} }

View file

@ -62,9 +62,8 @@ public class MinecartController implements INBTSerializable<CompoundNBT> {
World world = getWorld(); World world = getWorld();
if (needsEntryRefresh) { if (needsEntryRefresh) {
List<AbstractMinecartEntity> list = CapabilityMinecartController.queuedAdditions.get(world); CapabilityMinecartController.queuedAdditions.get(world).add(cart);
if (list != null) needsEntryRefresh = false;
list.add(cart);
} }
stallData.forEach(opt -> opt.ifPresent(sd -> sd.tick(cart))); stallData.forEach(opt -> opt.ifPresent(sd -> sd.tick(cart)));

View file

@ -7,7 +7,7 @@ import com.simibubi.create.foundation.utility.Lang;
public enum HeatCondition { public enum HeatCondition {
NONE(0xffffff), HEATED(0xFFD528), SUPERHEATED(0xA2DFFF), NONE(0xffffff), HEATED(0xE88300), SUPERHEATED(0x5C93E8),
; ;