From 3b6a7bac6c2260477e2ff625cde8102d567cb52c Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 18 Mar 2017 01:12:43 +0100 Subject: [PATCH 1/6] Finish and improve fluid implementation --- .../java/nova/core/component/fluid/Fluid.java | 27 +++- .../core/component/fluid/FluidFactory.java | 2 +- .../core/component/fluid/FluidFilter.java | 64 +++++++++ .../core/component/fluid/FluidHandler.java | 125 +++++++++++++++++- .../core/component/fluid/FluidManager.java | 9 +- .../core/component/fluid/FluidProvider.java | 17 +++ .../component/fluid/SidedTankProvider.java | 34 ----- .../java/nova/core/component/fluid/Tank.java | 9 +- .../nova/core/component/fluid/TankSimple.java | 42 ++++-- 9 files changed, 272 insertions(+), 57 deletions(-) create mode 100644 src/main/java/nova/core/component/fluid/FluidFilter.java delete mode 100644 src/main/java/nova/core/component/fluid/SidedTankProvider.java diff --git a/src/main/java/nova/core/component/fluid/Fluid.java b/src/main/java/nova/core/component/fluid/Fluid.java index 809e968ca..73d3fe39e 100644 --- a/src/main/java/nova/core/component/fluid/Fluid.java +++ b/src/main/java/nova/core/component/fluid/Fluid.java @@ -21,6 +21,8 @@ package nova.core.component.fluid; import nova.core.block.BlockFactory; +import nova.core.component.exception.ComponentException; +import nova.core.component.misc.FactoryProvider; import nova.core.retention.Data; import nova.core.retention.Storable; import nova.core.retention.Store; @@ -29,11 +31,12 @@ import java.util.Optional; +// TODO: Should this extend ComponentProvider? public class Fluid implements Identifiable, Storable, Cloneable { /** * 1000 liters = 1 cubic meter */ - public static final int bucketVolume = 1000; + public static final int BUCKET_VOLUME = 1000; /** * Fluid amount is measured in liters. */ @@ -41,7 +44,7 @@ public class Fluid implements Identifiable, Storable, Cloneable { private int amount = 1; //TODO: Public instance variable is not good practice - public FluidFactory factory; + private FluidFactory factory = null; /** * @return Amount of fluid @@ -104,7 +107,7 @@ public Fluid withAmount(int amount) { * @return The block. There may be no block associated with this fluid. */ public Optional getBlockFactory() { - return Optional.empty(); + return Game.blocks().get(getID()); } @Override @@ -125,9 +128,25 @@ public boolean sameType(Fluid stack) { return stack.getID().equals(getID()); } + void initFactory(FluidFactory factory) { + if (factory == null) { + this.factory = factory; + } else { + throw new ComponentException("Attempt to add two components of the type %s to " + this, FactoryProvider.class); + } + } + + public final FluidFactory getFactory() { + if (factory != null) { + return factory; + } else { + throw new ComponentException("Attempt to get component that does not exist: %s", FactoryProvider.class); + } + } + @Override public final String getID() { - return factory.getID(); + return getFactory().getID(); } @Override diff --git a/src/main/java/nova/core/component/fluid/FluidFactory.java b/src/main/java/nova/core/component/fluid/FluidFactory.java index 2357716de..f36cdddc7 100644 --- a/src/main/java/nova/core/component/fluid/FluidFactory.java +++ b/src/main/java/nova/core/component/fluid/FluidFactory.java @@ -54,7 +54,7 @@ public FluidFactory(String id, Supplier constructor) { @Override public Fluid build() { Fluid build = super.build(); - build.factory = this; + build.initFactory(this); return build; } diff --git a/src/main/java/nova/core/component/fluid/FluidFilter.java b/src/main/java/nova/core/component/fluid/FluidFilter.java new file mode 100644 index 000000000..4cf7cc776 --- /dev/null +++ b/src/main/java/nova/core/component/fluid/FluidFilter.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.component.fluid; + +import java.util.function.Predicate; + +/** + * A filter that only accepts a specific sub-type of {@link Fluid}. For use with tanks. + * + * @author ExE Boss + */ +@FunctionalInterface +public interface FluidFilter extends Predicate { + + /** + * Returns an {@link FluidFilter} that accepts an {@link Fluid} of the same + * type as the provided. + * + * @param item + * @return ItemFilter + */ + static FluidFilter of(Fluid fluid) { + return fluid::sameType; + } + + /** + * Returns an {@link FluidFilter} that accepts an {@link Fluid} of the same + * type as provided. + * + * @param id + * @return ItemFilter + */ + static FluidFilter of(String id) { + return (other) -> id.equals(other.getID()); + } + + /** + * Accepts any {@link Fluid} that has a >= amount than provided. + * + * @param amount + * @return + */ + static FluidFilter of(int amount) { + return (other) -> other.amount() >= amount; + } +} diff --git a/src/main/java/nova/core/component/fluid/FluidHandler.java b/src/main/java/nova/core/component/fluid/FluidHandler.java index 6360835b9..5b468d03f 100644 --- a/src/main/java/nova/core/component/fluid/FluidHandler.java +++ b/src/main/java/nova/core/component/fluid/FluidHandler.java @@ -16,29 +16,142 @@ * * You should have received a copy of the GNU General Public License * along with NOVA. If not, see . - */package nova.core.component.fluid; + */ + +package nova.core.component.fluid; import nova.core.component.Component; -import nova.core.util.Direction; +import nova.core.component.SidedComponent; import java.util.Arrays; import java.util.HashSet; +import java.util.Optional; import java.util.Set; -import java.util.function.Function; +import java.util.function.Predicate; /** + * A sided component that provides a fluid container. * @author Calclavia */ -public class FluidHandler extends Component { +@SidedComponent +public class FluidHandler extends Component implements FluidConsumer, FluidProvider { - public Set tanks = new HashSet<>(); - public Function> sidedTanks = direction -> tanks; + protected Set tanks = new HashSet<>(); + protected boolean resizable; + + public static FluidHandler singleTank() { + return new FluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME)); + } + + public static FluidHandler singleTank(int capacity) { + return new FluidHandler(false, new TankSimple(capacity)); + } + + public static FluidHandler singleTank(Predicate fluidFilter) { + return new FluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME).setFluidFilter(fluidFilter)); + } + + public static FluidHandler singleTank(int capacity, Predicate fluidFilter) { + return new FluidHandler(false, new TankSimple(capacity).setFluidFilter(fluidFilter)); + } public FluidHandler() { + this.resizable = true; } public FluidHandler(Tank... tanks) { + this(true, tanks); + } + + public FluidHandler(boolean resizable, Tank... tanks) { this.tanks.addAll(Arrays.asList(tanks)); + this.resizable = resizable; + if (resizable) { + this.tanks.removeIf(Tank::isEmpty); + } + } + + @Override + public int addFluid(Fluid fluid, boolean simulate) { + if (fluid.amount() == 0) + return 0; + + Fluid f = fluid.clone(); + int added = 0; + + for (Tank tank : tanks) { + int a = tank.addFluid(f, simulate); + added += a; + f.remove(a); + if (f.amount() == 0) + break; + } + + if (f.amount() > 0 && resizable) { + Tank t = new TankSimple(); + added += t.addFluid(f); + tanks.add(t); + } + + return added; + } + + @Override + public Optional removeFluid(Fluid fluid, boolean simulate) { + if (fluid.amount() == 0) + return Optional.empty(); + + Fluid f = fluid.withAmount(0); + Fluid r = fluid.clone(); + + for (Tank tank : tanks) { + if (!tank.hasFluidType(fluid)) + continue; + + int removed = tank.removeFluid(r).get().amount(); + r.remove(removed); + f.add(removed); + + if (r.amount() == 0) + break; + } + + if (resizable) { + this.tanks.removeIf(Tank::isEmpty); + } + + return Optional.of(f).filter(fl -> fl.amount() > 0); } + @Override + public Optional removeFluid(int amount, boolean simulate) { + Optional fluid = tanks.stream() + .filter(Tank::hasFluid) + .findFirst() + .flatMap(Tank::getFluid) + .map(f -> f.withAmount(0)); + + if (amount == 0 || !fluid.isPresent()) + return fluid; + + Fluid f = fluid.get(); + + for (Tank tank : tanks) { + if (!tank.hasFluidType(f)) + continue; + + int removed = tank.removeFluid(amount).get().amount(); + amount -= removed; + f.add(removed); + + if (amount == 0) + break; + } + + if (resizable) { + this.tanks.removeIf(Tank::isEmpty); + } + + return Optional.of(f).filter(fl -> fl.amount() > 0); + } } diff --git a/src/main/java/nova/core/component/fluid/FluidManager.java b/src/main/java/nova/core/component/fluid/FluidManager.java index 633084263..8b04969e3 100644 --- a/src/main/java/nova/core/component/fluid/FluidManager.java +++ b/src/main/java/nova/core/component/fluid/FluidManager.java @@ -22,6 +22,7 @@ import nova.core.util.registry.FactoryManager; import nova.core.util.registry.Registry; +import nova.internal.core.Game; import java.util.Optional; import java.util.function.Function; @@ -61,6 +62,12 @@ public FluidFactory register(FluidFactory factory) { @Override public void init() { - //TODO: Implement + Game.events().publish(new Init(this)); + } + + public class Init extends ManagerEvent { + public Init(FluidManager manager) { + super(manager); + } } } diff --git a/src/main/java/nova/core/component/fluid/FluidProvider.java b/src/main/java/nova/core/component/fluid/FluidProvider.java index 17cecdf0d..1096e4d3b 100644 --- a/src/main/java/nova/core/component/fluid/FluidProvider.java +++ b/src/main/java/nova/core/component/fluid/FluidProvider.java @@ -27,6 +27,23 @@ * @see FluidConsumer */ public interface FluidProvider { + /** + * Attempt to extract fluid from this FluidProvider + * @param fluid The fluid type and max amount to extract + * @param simulate Whether to simulate the extraction + * @return Extracted {@link Fluid} + */ + Optional removeFluid(Fluid fluid, boolean simulate); + + /** + * Attempt to extract fluid from this FluidProvider + * @param amount Amount of fluid to extract + * @return Extracted {@link Fluid} + */ + default Optional removeFluid(Fluid fluid) { + return removeFluid(fluid, false); + } + /** * Attempt to extract fluid from this FluidProvider * @param amount Amount of fluid to extract diff --git a/src/main/java/nova/core/component/fluid/SidedTankProvider.java b/src/main/java/nova/core/component/fluid/SidedTankProvider.java deleted file mode 100644 index 6ff35012d..000000000 --- a/src/main/java/nova/core/component/fluid/SidedTankProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015 NOVA, All rights reserved. - * This library is free software, licensed under GNU Lesser General Public License version 3 - * - * This file is part of NOVA. - * - * NOVA is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * NOVA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NOVA. If not, see . - */ - -package nova.core.component.fluid; - -import nova.core.util.Direction; - -import java.util.Set; - -/** - * A block that provides a fluid container. - * @author Calclavia - */ -//TODO: Implement Component. There will need to be a better way to handle direction. -public interface SidedTankProvider { - Set getTank(Direction dir); -} diff --git a/src/main/java/nova/core/component/fluid/Tank.java b/src/main/java/nova/core/component/fluid/Tank.java index 53ae78ebe..012aadc7a 100644 --- a/src/main/java/nova/core/component/fluid/Tank.java +++ b/src/main/java/nova/core/component/fluid/Tank.java @@ -44,7 +44,14 @@ default int getFluidAmount() { } /** - * @return Whether this container is storing a fluid + * @return Whether this container is empty + */ + default boolean isEmpty() { + return !getFluid().isPresent(); + } + + /** + * @return Whether this container is storing a fluid (is not empty) */ default boolean hasFluid() { return getFluid().isPresent(); diff --git a/src/main/java/nova/core/component/fluid/TankSimple.java b/src/main/java/nova/core/component/fluid/TankSimple.java index 6f3e6d6a3..ec2848eeb 100644 --- a/src/main/java/nova/core/component/fluid/TankSimple.java +++ b/src/main/java/nova/core/component/fluid/TankSimple.java @@ -24,8 +24,11 @@ import nova.core.network.Syncable; import nova.core.retention.Data; import nova.core.retention.Storable; +import nova.core.util.math.MathUtil; import java.util.Optional; +import java.util.OptionalInt; +import java.util.function.Predicate; /** * This class provides basic implementation of {@link Tank} @@ -33,25 +36,34 @@ public class TankSimple implements Tank, Storable, Syncable { private Optional containedFluid = Optional.empty(); - private int capacity; + private OptionalInt capacity; + private Predicate fluidFilter = f -> true; public TankSimple() { - this(Fluid.bucketVolume); + this.capacity = OptionalInt.empty(); } public TankSimple(int maxCapacity) { - this.capacity = maxCapacity; + this.capacity = OptionalInt.of(maxCapacity); + } + + public TankSimple removeCapacity() { + this.capacity = OptionalInt.empty(); + return this; } public TankSimple setCapacity(int capacity) { - this.capacity = capacity; + this.capacity = OptionalInt.of(capacity); setFluid(containedFluid); return this; } @Override public int addFluid(Fluid fluid, boolean simulate) { - int capacity = this.capacity - containedFluid.orElse(fluid.withAmount(0)).amount(); + if (fluid.amount() == 0 || !fluidFilter.test(fluid)) + return 0; + + int capacity = this.capacity.orElse(Integer.MAX_VALUE) - containedFluid.orElseGet(() -> fluid.withAmount(0)).amount(); int toPut = Math.min(fluid.amount(), capacity); if (containedFluid.isPresent()) { @@ -72,6 +84,14 @@ public int addFluid(Fluid fluid, boolean simulate) { } } + @Override + public Optional removeFluid(Fluid fluid, boolean simulate) { + if (!containedFluid.filter(fluid::sameType).isPresent()) + return Optional.empty(); + + return removeFluid(fluid.amount(), simulate); + } + @Override public Optional removeFluid(int amount, boolean simulate) { if (!containedFluid.isPresent()) { @@ -98,7 +118,7 @@ public Optional removeFluid(int amount, boolean simulate) { @Override public int getFluidCapacity() { - return capacity; + return capacity.orElse(Integer.MAX_VALUE); } @Override @@ -106,11 +126,13 @@ public Optional getFluid() { return containedFluid; } + public TankSimple setFluidFilter(Predicate fluidFilter) { + this.fluidFilter = fluidFilter; + return this; + } + public TankSimple setFluid(Optional fluid) { - this.containedFluid = fluid; - if (containedFluid.isPresent()) { - containedFluid.get().setAmount(Math.max(Math.min(containedFluid.get().amount(), capacity), 0)); - } + containedFluid = fluid.filter(fluidFilter).map(f -> f.withAmount(MathUtil.clamp(f.amount(), 0, capacity.orElse(Integer.MAX_VALUE)))).filter(f -> f.amount() > 0); return this; } From c209275af8db3b9a4e892bdf361dec7a1c95813c Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 18 Mar 2017 13:33:18 +0100 Subject: [PATCH 2/6] Call FluidManager.init() after EntityManager.init() --- .../core/wrapper/mc/forge/v17/launcher/NovaMinecraft.java | 1 + .../core/wrapper/mc/forge/v18/launcher/NovaMinecraft.java | 1 + src/main/java/nova/core/component/fluid/Fluid.java | 2 +- src/main/java/nova/core/component/fluid/FluidFilter.java | 8 ++++---- .../java/nova/core/component/fluid/FluidProvider.java | 2 +- .../java/nova/wrappertests/NovaLauncherTestFactory.java | 1 + 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/launcher/NovaMinecraft.java b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/launcher/NovaMinecraft.java index 2f4ac89b8..bcd2c6fdd 100644 --- a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/launcher/NovaMinecraft.java +++ b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/launcher/NovaMinecraft.java @@ -178,6 +178,7 @@ public void preInit(FMLPreInitializationEvent evt) { Game.blocks().init(); Game.items().init(); Game.entities().init(); + Game.fluids().init(); //Load preInit progressBar = ProgressManager.push("Pre-initializing NOVA wrappers", (novaModWrappers.isEmpty() ? 1 : novaModWrappers.size()) + novaWrappers.size()); diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/launcher/NovaMinecraft.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/launcher/NovaMinecraft.java index cbb5ed302..6335072cc 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/launcher/NovaMinecraft.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/launcher/NovaMinecraft.java @@ -183,6 +183,7 @@ public void preInit(FMLPreInitializationEvent evt) { Game.blocks().init(); Game.items().init(); Game.entities().init(); + Game.fluids().init(); //Load preInit progressBar = ProgressManager.push("Pre-initializing NOVA wrappers", (novaModWrappers.isEmpty() ? 1 : novaModWrappers.size()) + novaWrappers.size()); diff --git a/src/main/java/nova/core/component/fluid/Fluid.java b/src/main/java/nova/core/component/fluid/Fluid.java index 73d3fe39e..caeb4ecc7 100644 --- a/src/main/java/nova/core/component/fluid/Fluid.java +++ b/src/main/java/nova/core/component/fluid/Fluid.java @@ -129,7 +129,7 @@ public boolean sameType(Fluid stack) { } void initFactory(FluidFactory factory) { - if (factory == null) { + if (this.factory == null) { this.factory = factory; } else { throw new ComponentException("Attempt to add two components of the type %s to " + this, FactoryProvider.class); diff --git a/src/main/java/nova/core/component/fluid/FluidFilter.java b/src/main/java/nova/core/component/fluid/FluidFilter.java index 4cf7cc776..4261a86b5 100644 --- a/src/main/java/nova/core/component/fluid/FluidFilter.java +++ b/src/main/java/nova/core/component/fluid/FluidFilter.java @@ -34,8 +34,8 @@ public interface FluidFilter extends Predicate { * Returns an {@link FluidFilter} that accepts an {@link Fluid} of the same * type as the provided. * - * @param item - * @return ItemFilter + * @param fluid + * @return FluidFilter */ static FluidFilter of(Fluid fluid) { return fluid::sameType; @@ -46,7 +46,7 @@ static FluidFilter of(Fluid fluid) { * type as provided. * * @param id - * @return ItemFilter + * @return FluidFilter */ static FluidFilter of(String id) { return (other) -> id.equals(other.getID()); @@ -56,7 +56,7 @@ static FluidFilter of(String id) { * Accepts any {@link Fluid} that has a >= amount than provided. * * @param amount - * @return + * @return FluidFilter */ static FluidFilter of(int amount) { return (other) -> other.amount() >= amount; diff --git a/src/main/java/nova/core/component/fluid/FluidProvider.java b/src/main/java/nova/core/component/fluid/FluidProvider.java index 1096e4d3b..80974a4f8 100644 --- a/src/main/java/nova/core/component/fluid/FluidProvider.java +++ b/src/main/java/nova/core/component/fluid/FluidProvider.java @@ -37,7 +37,7 @@ public interface FluidProvider { /** * Attempt to extract fluid from this FluidProvider - * @param amount Amount of fluid to extract + * @param fluid The fluid type and max amount to extract * @return Extracted {@link Fluid} */ default Optional removeFluid(Fluid fluid) { diff --git a/src/test/java/nova/wrappertests/NovaLauncherTestFactory.java b/src/test/java/nova/wrappertests/NovaLauncherTestFactory.java index e92733430..b5c175ea2 100644 --- a/src/test/java/nova/wrappertests/NovaLauncherTestFactory.java +++ b/src/test/java/nova/wrappertests/NovaLauncherTestFactory.java @@ -93,6 +93,7 @@ public NovaLauncher createLauncher(Class... modClasses) { Game.blocks().init(); Game.items().init(); Game.entities().init(); + Game.fluids().init(); Game.recipes().init(); return launcher; From d49441802503d47bc07fd75a332cc815db2efd2b Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 18 Mar 2017 14:03:28 +0100 Subject: [PATCH 3/6] Fix Travis build --- .../core/component/fluid/FluidHandler.java | 52 ++++++++++++++++++- .../nova/core/component/fluid/FluidIO.java | 45 ++++++++++++++++ .../java/nova/core/component/fluid/Tank.java | 17 +++--- .../nova/core/component/fluid/TankSimple.java | 14 +++-- 4 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 src/main/java/nova/core/component/fluid/FluidIO.java diff --git a/src/main/java/nova/core/component/fluid/FluidHandler.java b/src/main/java/nova/core/component/fluid/FluidHandler.java index 5b468d03f..be590119d 100644 --- a/src/main/java/nova/core/component/fluid/FluidHandler.java +++ b/src/main/java/nova/core/component/fluid/FluidHandler.java @@ -22,21 +22,26 @@ import nova.core.component.Component; import nova.core.component.SidedComponent; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.retention.Store; import java.util.Arrays; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * A sided component that provides a fluid container. * @author Calclavia */ @SidedComponent -public class FluidHandler extends Component implements FluidConsumer, FluidProvider { +public class FluidHandler extends Component implements FluidIO, Storable { protected Set tanks = new HashSet<>(); + @Store protected boolean resizable; public static FluidHandler singleTank() { @@ -154,4 +159,49 @@ public Optional removeFluid(int amount, boolean simulate) { return Optional.of(f).filter(fl -> fl.amount() > 0); } + + @Override + public void save(Data data) { + Storable.super.save(data); + data.put("tanks", tanks.stream() + .filter(t -> t instanceof Storable) + .collect(Collectors.toSet())); + } + + @Override + public void load(Data data) { + Storable.super.load(data); + tanks.removeIf(t -> t instanceof Storable); + tanks.addAll(data.getCollection("tanks")); + } + + @Override + public int getFluidAmount() { + return tanks.stream().mapToInt(FluidIO::getFluidAmount).sum(); + } + + @Override + public boolean isEmpty() { + return tanks.isEmpty() || tanks.stream().allMatch(FluidIO::isEmpty); + } + + @Override + public boolean hasFluid() { + return !tanks.isEmpty() && tanks.stream().anyMatch(FluidIO::hasFluid); + } + + @Override + public boolean hasFluidType(String fluidID) { + return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(fluidID)); + } + + @Override + public boolean hasFluidType(Fluid sample) { + return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(sample)); + } + + @Override + public boolean hasFluidType(FluidFactory sample) { + return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(sample)); + } } diff --git a/src/main/java/nova/core/component/fluid/FluidIO.java b/src/main/java/nova/core/component/fluid/FluidIO.java new file mode 100644 index 000000000..5435135cf --- /dev/null +++ b/src/main/java/nova/core/component/fluid/FluidIO.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.component.fluid; + +/** + * @author ExE Boss + */ +public interface FluidIO extends FluidProvider, FluidConsumer { + + int getFluidAmount(); + + /** + * @return Whether this container is empty + */ + boolean isEmpty(); + + /** + * @return Whether this container is storing a fluid (is not empty) + */ + boolean hasFluid(); + + boolean hasFluidType(String id); + + boolean hasFluidType(Fluid fluid); + + boolean hasFluidType(FluidFactory fluid); +} diff --git a/src/main/java/nova/core/component/fluid/Tank.java b/src/main/java/nova/core/component/fluid/Tank.java index 012aadc7a..e39cf08f9 100644 --- a/src/main/java/nova/core/component/fluid/Tank.java +++ b/src/main/java/nova/core/component/fluid/Tank.java @@ -21,42 +21,41 @@ package nova.core.component.fluid; import java.util.Optional; +import java.util.OptionalInt; /** * Classes with this interface declare ability to store fluids * @see FluidConsumer * @see Tank */ -public interface Tank extends FluidConsumer, FluidProvider { +public interface Tank extends FluidIO { /** * @return Maximum capacity of this container */ - int getFluidCapacity(); + OptionalInt getFluidCapacity(); /** * @return Fluid stored in this container */ Optional getFluid(); + @Override default int getFluidAmount() { return hasFluid() ? getFluid().get().amount() : 0; } - /** - * @return Whether this container is empty - */ + @Override default boolean isEmpty() { return !getFluid().isPresent(); } - /** - * @return Whether this container is storing a fluid (is not empty) - */ + @Override default boolean hasFluid() { return getFluid().isPresent(); } + @Override default boolean hasFluidType(String fluidID) { if (hasFluid()) { return getFluid().get().getID().equals(fluidID); @@ -65,6 +64,7 @@ default boolean hasFluidType(String fluidID) { return false; } + @Override default boolean hasFluidType(Fluid sample) { if (hasFluid()) { return getFluid().get().sameType(sample); @@ -73,6 +73,7 @@ default boolean hasFluidType(Fluid sample) { return false; } + @Override default boolean hasFluidType(FluidFactory sample) { if (hasFluid()) { return getFluid().get().sameType(sample); diff --git a/src/main/java/nova/core/component/fluid/TankSimple.java b/src/main/java/nova/core/component/fluid/TankSimple.java index ec2848eeb..d72bec619 100644 --- a/src/main/java/nova/core/component/fluid/TankSimple.java +++ b/src/main/java/nova/core/component/fluid/TankSimple.java @@ -117,8 +117,8 @@ public Optional removeFluid(int amount, boolean simulate) { } @Override - public int getFluidCapacity() { - return capacity.orElse(Integer.MAX_VALUE); + public OptionalInt getFluidCapacity() { + return capacity; } @Override @@ -138,7 +138,9 @@ public TankSimple setFluid(Optional fluid) { @Override public void save(Data data) { - data.put("capacity", capacity); + if (capacity.isPresent()) { + data.put("capacity", capacity.getAsInt()); + } if (containedFluid.isPresent()) { data.put("fluid", containedFluid.get()); @@ -147,7 +149,11 @@ public void save(Data data) { @Override public void load(Data data) { - setCapacity(data.get("capacity")); + if (data.containsKey("capactiy")) { + setCapacity(data.get("capacity")); + } else { + removeCapacity(); + } if (data.containsKey("fluid")) { containedFluid = Optional.of(data.getStorable("fluid")); From 815d9432736cd317f851a0febd797f8ab2ed07a7 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 8 Apr 2017 08:45:53 +0200 Subject: [PATCH 4/6] Rename FluidHandler to SimpleFluidHandler --- ...idHandler.java => SimpleFluidHandler.java} | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) rename src/main/java/nova/core/component/fluid/{FluidHandler.java => SimpleFluidHandler.java} (83%) diff --git a/src/main/java/nova/core/component/fluid/FluidHandler.java b/src/main/java/nova/core/component/fluid/SimpleFluidHandler.java similarity index 83% rename from src/main/java/nova/core/component/fluid/FluidHandler.java rename to src/main/java/nova/core/component/fluid/SimpleFluidHandler.java index be590119d..a02c184cd 100644 --- a/src/main/java/nova/core/component/fluid/FluidHandler.java +++ b/src/main/java/nova/core/component/fluid/SimpleFluidHandler.java @@ -38,37 +38,37 @@ * @author Calclavia */ @SidedComponent -public class FluidHandler extends Component implements FluidIO, Storable { +public class SimpleFluidHandler extends Component implements FluidIO, Storable { protected Set tanks = new HashSet<>(); @Store protected boolean resizable; - public static FluidHandler singleTank() { - return new FluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME)); + public static SimpleFluidHandler singleTank() { + return new SimpleFluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME)); } - public static FluidHandler singleTank(int capacity) { - return new FluidHandler(false, new TankSimple(capacity)); + public static SimpleFluidHandler singleTank(int capacity) { + return new SimpleFluidHandler(false, new TankSimple(capacity)); } - public static FluidHandler singleTank(Predicate fluidFilter) { - return new FluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME).setFluidFilter(fluidFilter)); + public static SimpleFluidHandler singleTank(Predicate fluidFilter) { + return new SimpleFluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME).setFluidFilter(fluidFilter)); } - public static FluidHandler singleTank(int capacity, Predicate fluidFilter) { - return new FluidHandler(false, new TankSimple(capacity).setFluidFilter(fluidFilter)); + public static SimpleFluidHandler singleTank(int capacity, Predicate fluidFilter) { + return new SimpleFluidHandler(false, new TankSimple(capacity).setFluidFilter(fluidFilter)); } - public FluidHandler() { + public SimpleFluidHandler() { this.resizable = true; } - public FluidHandler(Tank... tanks) { + public SimpleFluidHandler(Tank... tanks) { this(true, tanks); } - public FluidHandler(boolean resizable, Tank... tanks) { + public SimpleFluidHandler(boolean resizable, Tank... tanks) { this.tanks.addAll(Arrays.asList(tanks)); this.resizable = resizable; if (resizable) { From fbe42781aa48ae4b2a75744fbf7a46de64cf81f2 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 8 Apr 2017 08:54:30 +0200 Subject: [PATCH 5/6] Create abstract class FluidHandler --- .../core/component/fluid/FluidHandler.java | 77 +++++++++++++++++++ ...idHandler.java => FluidHandlerSimple.java} | 60 +++++---------- .../core/component/fluid/TankProvider.java | 31 ++++++++ 3 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 src/main/java/nova/core/component/fluid/FluidHandler.java rename src/main/java/nova/core/component/fluid/{SimpleFluidHandler.java => FluidHandlerSimple.java} (70%) create mode 100644 src/main/java/nova/core/component/fluid/TankProvider.java diff --git a/src/main/java/nova/core/component/fluid/FluidHandler.java b/src/main/java/nova/core/component/fluid/FluidHandler.java new file mode 100644 index 000000000..ec170a75b --- /dev/null +++ b/src/main/java/nova/core/component/fluid/FluidHandler.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NOVA. If not, see . + */ +package nova.core.component.fluid; + +import nova.core.component.Component; +import nova.core.retention.Storable; + +import java.util.function.Predicate; + +/** + * @author ExE Boss + */ +public abstract class FluidHandler extends Component implements FluidIO, TankProvider, Storable { + + public static FluidHandler singleTank() { + return FluidHandlerSimple.simpleSingleTank(); + } + + public static FluidHandler singleTank(int capacity) { + return FluidHandlerSimple.simpleSingleTank(capacity); + } + + public static FluidHandler singleTank(Predicate fluidFilter) { + return FluidHandlerSimple.simpleSingleTank(fluidFilter); + } + + public static FluidHandler singleTank(int capacity, Predicate fluidFilter) { + return FluidHandlerSimple.simpleSingleTank(capacity, fluidFilter); + } + + @Override + public int getFluidAmount() { + return getTanks().stream().mapToInt(Tank::getFluidAmount).sum(); + } + + @Override + public boolean isEmpty() { + return getTanks().isEmpty() || getTanks().stream().allMatch(Tank::isEmpty); + } + + @Override + public boolean hasFluid() { + return !getTanks().isEmpty() && getTanks().stream().anyMatch(Tank::hasFluid); + } + + @Override + public boolean hasFluidType(String fluidID) { + return !getTanks().isEmpty() && getTanks().stream().anyMatch(t -> t.hasFluidType(fluidID)); + } + + @Override + public boolean hasFluidType(Fluid sample) { + return !getTanks().isEmpty() && getTanks().stream().anyMatch(t -> t.hasFluidType(sample)); + } + + @Override + public boolean hasFluidType(FluidFactory sample) { + return !getTanks().isEmpty() && getTanks().stream().anyMatch(t -> t.hasFluidType(sample)); + } +} diff --git a/src/main/java/nova/core/component/fluid/SimpleFluidHandler.java b/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java similarity index 70% rename from src/main/java/nova/core/component/fluid/SimpleFluidHandler.java rename to src/main/java/nova/core/component/fluid/FluidHandlerSimple.java index a02c184cd..3a4b39bf0 100644 --- a/src/main/java/nova/core/component/fluid/SimpleFluidHandler.java +++ b/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java @@ -27,6 +27,7 @@ import nova.core.retention.Store; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -38,37 +39,37 @@ * @author Calclavia */ @SidedComponent -public class SimpleFluidHandler extends Component implements FluidIO, Storable { +public class FluidHandlerSimple extends FluidHandler implements Storable { protected Set tanks = new HashSet<>(); @Store protected boolean resizable; - public static SimpleFluidHandler singleTank() { - return new SimpleFluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME)); + static FluidHandlerSimple simpleSingleTank() { + return new FluidHandlerSimple(false, new TankSimple(Fluid.BUCKET_VOLUME)); } - public static SimpleFluidHandler singleTank(int capacity) { - return new SimpleFluidHandler(false, new TankSimple(capacity)); + static FluidHandlerSimple simpleSingleTank(int capacity) { + return new FluidHandlerSimple(false, new TankSimple(capacity)); } - public static SimpleFluidHandler singleTank(Predicate fluidFilter) { - return new SimpleFluidHandler(false, new TankSimple(Fluid.BUCKET_VOLUME).setFluidFilter(fluidFilter)); + static FluidHandlerSimple simpleSingleTank(Predicate fluidFilter) { + return new FluidHandlerSimple(false, new TankSimple(Fluid.BUCKET_VOLUME).setFluidFilter(fluidFilter)); } - public static SimpleFluidHandler singleTank(int capacity, Predicate fluidFilter) { - return new SimpleFluidHandler(false, new TankSimple(capacity).setFluidFilter(fluidFilter)); + static FluidHandlerSimple simpleSingleTank(int capacity, Predicate fluidFilter) { + return new FluidHandlerSimple(false, new TankSimple(capacity).setFluidFilter(fluidFilter)); } - public SimpleFluidHandler() { + public FluidHandlerSimple() { this.resizable = true; } - public SimpleFluidHandler(Tank... tanks) { + public FluidHandlerSimple(Tank... tanks) { this(true, tanks); } - public SimpleFluidHandler(boolean resizable, Tank... tanks) { + public FluidHandlerSimple(boolean resizable, Tank... tanks) { this.tanks.addAll(Arrays.asList(tanks)); this.resizable = resizable; if (resizable) { @@ -76,6 +77,11 @@ public SimpleFluidHandler(boolean resizable, Tank... tanks) { } } + @Override + public Set getTanks() { + return tanks; + } + @Override public int addFluid(Fluid fluid, boolean simulate) { if (fluid.amount() == 0) @@ -174,34 +180,4 @@ public void load(Data data) { tanks.removeIf(t -> t instanceof Storable); tanks.addAll(data.getCollection("tanks")); } - - @Override - public int getFluidAmount() { - return tanks.stream().mapToInt(FluidIO::getFluidAmount).sum(); - } - - @Override - public boolean isEmpty() { - return tanks.isEmpty() || tanks.stream().allMatch(FluidIO::isEmpty); - } - - @Override - public boolean hasFluid() { - return !tanks.isEmpty() && tanks.stream().anyMatch(FluidIO::hasFluid); - } - - @Override - public boolean hasFluidType(String fluidID) { - return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(fluidID)); - } - - @Override - public boolean hasFluidType(Fluid sample) { - return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(sample)); - } - - @Override - public boolean hasFluidType(FluidFactory sample) { - return !tanks.isEmpty() && tanks.stream().anyMatch(t -> t.hasFluidType(sample)); - } } diff --git a/src/main/java/nova/core/component/fluid/TankProvider.java b/src/main/java/nova/core/component/fluid/TankProvider.java new file mode 100644 index 000000000..4613a920b --- /dev/null +++ b/src/main/java/nova/core/component/fluid/TankProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NOVA. If not, see . + */ + +package nova.core.component.fluid; + +import java.util.Set; + +/** + * @author ExE Boss + */ +public interface TankProvider { + + Set getTanks(); +} From fb1e631d50443575d725be34f0a6e9738bc82d29 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Sat, 8 Apr 2017 09:45:17 +0200 Subject: [PATCH 6/6] Implement Tank tagging --- .../core/component/fluid/FluidHandler.java | 4 + .../component/fluid/FluidHandlerSimple.java | 3 +- .../component/fluid/FluidHandlerWrapper.java | 114 ++++++++++++++++++ .../java/nova/core/component/fluid/Tank.java | 3 + .../nova/core/component/fluid/TankSimple.java | 16 +++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nova/core/component/fluid/FluidHandlerWrapper.java diff --git a/src/main/java/nova/core/component/fluid/FluidHandler.java b/src/main/java/nova/core/component/fluid/FluidHandler.java index ec170a75b..847aa999c 100644 --- a/src/main/java/nova/core/component/fluid/FluidHandler.java +++ b/src/main/java/nova/core/component/fluid/FluidHandler.java @@ -45,6 +45,10 @@ public static FluidHandler singleTank(int capacity, Predicate fluidFilter return FluidHandlerSimple.simpleSingleTank(capacity, fluidFilter); } + public static FluidHandler multiTank(Tank... tanks) { + return new FluidHandlerSimple(false, tanks); + } + @Override public int getFluidAmount() { return getTanks().stream().mapToInt(Tank::getFluidAmount).sum(); diff --git a/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java b/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java index 3a4b39bf0..26bbd18e4 100644 --- a/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java +++ b/src/main/java/nova/core/component/fluid/FluidHandlerSimple.java @@ -20,7 +20,6 @@ package nova.core.component.fluid; -import nova.core.component.Component; import nova.core.component.SidedComponent; import nova.core.retention.Data; import nova.core.retention.Storable; @@ -79,7 +78,7 @@ public FluidHandlerSimple(boolean resizable, Tank... tanks) { @Override public Set getTanks() { - return tanks; + return Collections.unmodifiableSet(tanks); } @Override diff --git a/src/main/java/nova/core/component/fluid/FluidHandlerWrapper.java b/src/main/java/nova/core/component/fluid/FluidHandlerWrapper.java new file mode 100644 index 000000000..e36987af0 --- /dev/null +++ b/src/main/java/nova/core/component/fluid/FluidHandlerWrapper.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NOVA. If not, see . + */ +package nova.core.component.fluid; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * @author ExE Boss + */ +public class FluidHandlerWrapper extends FluidHandler { + + private final FluidHandler handler; + private final Predicate tankFilter; + + public FluidHandlerWrapper(FluidHandler handler, Predicate tankFilter) { + this.handler = handler; + this.tankFilter = tankFilter; + } + + @Override + public Optional removeFluid(Fluid fluid, boolean simulate) { + if (fluid.amount() == 0) + return Optional.empty(); + + Fluid f = fluid.withAmount(0); + Fluid r = fluid.clone(); + + for (Tank tank : getTanks()) { + if (!tank.hasFluidType(fluid)) + continue; + + int removed = tank.removeFluid(r).get().amount(); + r.remove(removed); + f.add(removed); + + if (r.amount() == 0) + break; + } + + return Optional.of(f).filter(fl -> fl.amount() > 0); + } + + @Override + public Optional removeFluid(int amount, boolean simulate) { + Optional fluid = getTanks().stream() + .filter(Tank::hasFluid) + .findFirst() + .flatMap(Tank::getFluid) + .map(f -> f.withAmount(0)); + + if (amount == 0 || !fluid.isPresent()) + return fluid; + + Fluid f = fluid.get(); + + for (Tank tank : getTanks()) { + if (!tank.hasFluidType(f)) + continue; + + int removed = tank.removeFluid(amount).get().amount(); + amount -= removed; + f.add(removed); + + if (amount == 0) + break; + } + + return Optional.of(f).filter(fl -> fl.amount() > 0); + } + + @Override + public int addFluid(Fluid fluid, boolean simulate) { + if (fluid.amount() == 0) + return 0; + + Fluid f = fluid.clone(); + int added = 0; + + for (Tank tank : getTanks()) { + int a = tank.addFluid(f, simulate); + added += a; + f.remove(a); + if (f.amount() == 0) + break; + } + + return added; + } + + @Override + public Set getTanks() { + return handler.getTanks().stream().filter(tankFilter).collect(Collectors.toSet()); + } +} diff --git a/src/main/java/nova/core/component/fluid/Tank.java b/src/main/java/nova/core/component/fluid/Tank.java index e39cf08f9..ce003fc43 100644 --- a/src/main/java/nova/core/component/fluid/Tank.java +++ b/src/main/java/nova/core/component/fluid/Tank.java @@ -82,4 +82,7 @@ default boolean hasFluidType(FluidFactory sample) { return false; } + default Optional getTag() { + return Optional.empty(); + } } diff --git a/src/main/java/nova/core/component/fluid/TankSimple.java b/src/main/java/nova/core/component/fluid/TankSimple.java index d72bec619..450465711 100644 --- a/src/main/java/nova/core/component/fluid/TankSimple.java +++ b/src/main/java/nova/core/component/fluid/TankSimple.java @@ -38,6 +38,7 @@ public class TankSimple implements Tank, Storable, Syncable { private Optional containedFluid = Optional.empty(); private OptionalInt capacity; private Predicate fluidFilter = f -> true; + private Optional name = Optional.empty(); public TankSimple() { this.capacity = OptionalInt.empty(); @@ -52,12 +53,22 @@ public TankSimple removeCapacity() { return this; } + public TankSimple removeTag() { + this.name = Optional.empty(); + return this; + } + public TankSimple setCapacity(int capacity) { this.capacity = OptionalInt.of(capacity); setFluid(containedFluid); return this; } + public TankSimple setTag(String name) { + this.name = Optional.of(name); + return this; + } + @Override public int addFluid(Fluid fluid, boolean simulate) { if (fluid.amount() == 0 || !fluidFilter.test(fluid)) @@ -173,4 +184,9 @@ public void read(Packet packet) { public void write(Packet packet) { containedFluid = Optional.of((Fluid) packet.readStorable()); } + + @Override + public Optional getTag() { + return name; + } }