Matter Recycler, Matter Dust and some fixes

This commit is contained in:
DBotThePony 2022-01-30 13:02:03 +07:00
parent da5aa346fb
commit 8bd6852d10
Signed by: DBot
GPG Key ID: DCC23B5715498507
20 changed files with 598 additions and 67 deletions

View File

@ -350,6 +350,7 @@ object DataGen {
tile(Blocks.MATTER_DECOMPOSER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)
tile(Blocks.MATTER_REPLICATOR, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)
tile(Blocks.MATTER_RECYCLER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)
tile(Blocks.MATTER_SCANNER, TileNbtCopy("container"), *workerTags)
tile(Blocks.PLATE_PRESS, TileNbtCopy("container"), *workerTags)

View File

@ -252,6 +252,7 @@ public class Registry {
public static final ResourceLocation ENERGY_COUNTER = loc("energy_counter"); // есть рецепт
public static final ResourceLocation CHEMICAL_GENERATOR = loc("chemical_generator"); // есть рецепт
public static final ResourceLocation PLATE_PRESS = loc("plate_press"); // есть рецепт
public static final ResourceLocation MATTER_RECYCLER = loc("matter_recycler"); // нужен рецепт
public static final ResourceLocation DEBUG_EXPLOSION_SMALL = loc("debug_explosion_small");
public static final ResourceLocation DEBUG_SPHERE_POINTS = loc("debug_sphere_points");
@ -272,6 +273,7 @@ public class Registry {
// items
public static final ResourceLocation GRAVITATIONAL_DISRUPTOR = loc("gravitational_disruptor");
public static final ResourceLocation MATTER_DUST = loc("matter_dust");
public static final ResourceLocation PILL_ANDROID = loc("pill_android");
public static final ResourceLocation PILL_HUMANE = loc("pill_humane");
@ -415,6 +417,7 @@ public class Registry {
public static final BlockEnergyCounter ENERGY_COUNTER = new BlockEnergyCounter();
public static final BlockChemicalGenerator CHEMICAL_GENERATOR = new BlockChemicalGenerator();
public static final BlockPlatePress PLATE_PRESS = new BlockPlatePress();
public static final BlockMatterRecycler MATTER_RECYCLER = new BlockMatterRecycler();
public static final BlockExplosionDebugger DEBUG_EXPLOSION_SMALL = new BlockExplosionDebugger();
public static final BlockSphereDebugger DEBUG_SPHERE_POINTS = new BlockSphereDebugger();
@ -500,6 +503,7 @@ public class Registry {
ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER);
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
PLATE_PRESS.setRegistryName(Names.PLATE_PRESS);
MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER);
GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER);
GRAVITATION_STABILIZER_LENS.setRegistryName(Names.GRAVITATION_STABILIZER_LENS);
@ -541,6 +545,7 @@ public class Registry {
event.getRegistry().register(PLATE_PRESS);
event.getRegistry().register(GRAVITATION_STABILIZER);
event.getRegistry().register(GRAVITATION_STABILIZER_LENS);
event.getRegistry().register(MATTER_RECYCLER);
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
event.getRegistry().register(DEBUG_SPHERE_POINTS);
@ -590,6 +595,7 @@ public class Registry {
public static final BlockItem ENERGY_COUNTER = new BlockItem(Blocks.ENERGY_COUNTER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final BlockItem CHEMICAL_GENERATOR = new BlockItem(Blocks.CHEMICAL_GENERATOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final BlockItem PLATE_PRESS = new BlockItem(Blocks.PLATE_PRESS, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final BlockItem MATTER_RECYCLER = new BlockItem(Blocks.MATTER_RECYCLER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final BlockItem GRAVITATION_STABILIZER = new BlockItem(Blocks.GRAVITATION_STABILIZER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)) {
@Override
public void appendHoverText(@Nonnull ItemStack p_40572_, @Nullable Level p_40573_, @Nonnull List<Component> p_40574_, @Nonnull TooltipFlag p_40575_) {
@ -605,6 +611,8 @@ public class Registry {
public static final BlockItem DEBUG_EXPLOSION_SMALL = new BlockItem(Blocks.DEBUG_EXPLOSION_SMALL, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final BlockItem DEBUG_SPHERE_POINTS = new BlockItem(Blocks.DEBUG_SPHERE_POINTS, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final ItemMatterDust MATTER_DUST = new ItemMatterDust();
public static final Item TRITANIUM_ORE_CLUMP = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final Item TRITANIUM_INGOT = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
@ -763,6 +771,8 @@ public class Registry {
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
PLATE_PRESS.setRegistryName(Names.PLATE_PRESS);
GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER);
MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER);
MATTER_DUST.setRegistryName(Names.MATTER_DUST);
DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL);
DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS);
@ -855,6 +865,8 @@ public class Registry {
event.getRegistry().register(CHEMICAL_GENERATOR);
event.getRegistry().register(PLATE_PRESS);
event.getRegistry().register(GRAVITATION_STABILIZER);
event.getRegistry().register(MATTER_DUST);
event.getRegistry().register(MATTER_RECYCLER);
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
event.getRegistry().register(DEBUG_SPHERE_POINTS);
@ -958,6 +970,7 @@ public class Registry {
public static final BlockEntityType<BlockEntityChemicalGenerator> CHEMICAL_GENERATOR = BlockEntityType.Builder.of(BlockEntityChemicalGenerator::new, Blocks.CHEMICAL_GENERATOR).build(null);
public static final BlockEntityType<BlockEntityPlatePress> PLATE_PRESS = BlockEntityType.Builder.of(BlockEntityPlatePress::new, Blocks.PLATE_PRESS).build(null);
public static final BlockEntityType<BlockEntityGravitationStabilizer> GRAVITATION_STABILIZER = BlockEntityType.Builder.of(BlockEntityGravitationStabilizer::new, Blocks.GRAVITATION_STABILIZER).build(null);
public static final BlockEntityType<BlockEntityMatterRecycler> MATTER_RECYCLER = BlockEntityType.Builder.of(BlockEntityMatterRecycler::new, Blocks.MATTER_RECYCLER).build(null);
public static final BlockEntityType<BlockEntityExplosionDebugger> DEBUG_EXPLOSION_SMALL = BlockEntityType.Builder.of(BlockEntityExplosionDebugger::new, Blocks.DEBUG_EXPLOSION_SMALL).build(null);
public static final BlockEntityType<BlockEntitySphereDebugger> DEBUG_SPHERE_POINTS = BlockEntityType.Builder.of(BlockEntitySphereDebugger::new, Blocks.DEBUG_SPHERE_POINTS).build(null);
@ -982,6 +995,7 @@ public class Registry {
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
PLATE_PRESS.setRegistryName(Names.PLATE_PRESS);
GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER);
MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER);
DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL);
DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS);
@ -1009,6 +1023,7 @@ public class Registry {
event.getRegistry().register(CHEMICAL_GENERATOR);
event.getRegistry().register(PLATE_PRESS);
event.getRegistry().register(GRAVITATION_STABILIZER);
event.getRegistry().register(MATTER_RECYCLER);
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
event.getRegistry().register(DEBUG_SPHERE_POINTS);
@ -1285,6 +1300,7 @@ public class Registry {
public static final MenuType<MenuEnergyCounter> ENERGY_COUNTER = new MenuType<>(MenuEnergyCounter::new);
public static final MenuType<MenuChemicalGenerator> CHEMICAL_GENERATOR = new MenuType<>(MenuChemicalGenerator::new);
public static final MenuType<MenuPlatePress> PLATE_PRESS = new MenuType<>(MenuPlatePress::new);
public static final MenuType<MenuMatterRecycler> MATTER_RECYCLER = new MenuType<>(MenuMatterRecycler::new);
static {
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
@ -1303,6 +1319,7 @@ public class Registry {
ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER);
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
PLATE_PRESS.setRegistryName(Names.PLATE_PRESS);
MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER);
}
@SubscribeEvent
@ -1324,6 +1341,7 @@ public class Registry {
event.getRegistry().register(ENERGY_COUNTER);
event.getRegistry().register(CHEMICAL_GENERATOR);
event.getRegistry().register(PLATE_PRESS);
event.getRegistry().register(MATTER_RECYCLER);
// OverdriveThatMatters.LOGGER.info("Registered menus");
}
@ -1347,6 +1365,7 @@ public class Registry {
MenuScreens.register(ENERGY_COUNTER, ScreenEnergyCounter::new);
MenuScreens.register(CHEMICAL_GENERATOR, ScreenChemicalGenerator::new);
MenuScreens.register(PLATE_PRESS, ScreenPlatePress::new);
MenuScreens.register(MATTER_RECYCLER, ScreenMatterRecycler::new);
// OverdriveThatMatters.LOGGER.info("Registered screens");
}

View File

@ -1,13 +1,12 @@
package ru.dbotthepony.mc.otm.block.entity.worker;
import net.minecraft.MethodsReturnNonnullByDefault;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.core.ImpreciseFraction;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public record WorkTickContext(MachineJob job, ImpreciseFraction requiredPower, ImpreciseFraction extractedPower, ImpreciseFraction workSpeed) {
public record WorkTickContext(MachineJob job, ImpreciseFraction requiredPower, ImpreciseFraction extractedPower, double ticksAdvanced) {
}

View File

@ -26,6 +26,6 @@ public interface IMatterHandler {
MatterDirection getDirection();
default ImpreciseFraction getMissingMatter() {
return getMaxStoredMatter().minus(getStoredMatter());
return getMaxStoredMatter().minus(getStoredMatter()).moreThanZero();
}
}

View File

@ -0,0 +1,28 @@
package ru.dbotthepony.mc.otm.block
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterRecycler
class BlockMatterRecycler : BlockMatteryRotatable(), EntityBlock {
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
return BlockEntityMatterRecycler(p_153215_, p_153216_)
}
override fun <T : BlockEntity?> getTicker(
p_153212_: Level,
p_153213_: BlockState,
p_153214_: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || p_153214_ !== Registry.BlockEntities.MATTER_RECYCLER)
return null
return BlockEntityTicker { _, _, _, tile -> if (tile is BlockEntityMatterRecycler) tile.tick() }
}
}

View File

@ -43,9 +43,9 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
energy = MatteryMachineEnergyStorage(
this,
MatteryMachineEnergyStorage.MachineType.WORKER,
ImpreciseFraction(400000),
ImpreciseFraction(2000),
ImpreciseFraction(2000)
ENERGY_STORAGE,
MAX_IO,
MAX_IO
)
}
@ -64,12 +64,12 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
// вход, выход
@JvmField
val itemContainer = MatteryContainer(this::setChangedLight, 2)
val container = MatteryContainer(this::setChangedLight, 3)
private val itemHandler = LazyOptional.of<IItemHandler> {
itemContainer.handler(
{ slot: Int, stack: ItemStack -> slot == 0 && canDecompose(stack) },
{ slot: Int, amount: Int, stack: ItemStack -> slot == 1 })
container.handler(
{ slot: Int, stack: ItemStack -> slot == INPUT_SLOT && canDecompose(stack) },
{ slot: Int, _: Int, _: ItemStack -> slot != INPUT_SLOT })
}
override fun getDefaultDisplayName(): Component {
@ -82,7 +82,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["container"] = itemContainer.serializeNBT()
nbt["container"] = container.serializeNBT()
nbt["matter"] = matter.serializeNBT()
}
@ -93,7 +93,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
matter.deserializeNBT(it)
}
itemContainer.deserializeNBT(nbt["container"])
container.deserializeNBT(nbt["container"])
}
override fun reviveCaps() {
@ -119,12 +119,74 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
}
override fun onJobFinish(job: MachineJob): MachineJobStatus {
matter.receiveMatterInner(getMatterValue(job.stack()).value, false)
var matterValue = ImpreciseFraction.deserializeNBT(job.data["value"])
if (job.data.getBoolean("to_dust")) {
val item = Registry.Items.MATTER_DUST
while (matterValue > ImpreciseFraction.ZERO) {
val stack = container[OUTPUT_DUST_MAIN]
// первый слот пустой
if (stack.isEmpty) {
container[OUTPUT_DUST_MAIN] = ItemStack(item, 1).also {
matterValue -= item.addMatterValue(it, matterValue, false)
}
// первый слот не пустой, но мы можем влить туда материю
} else if (!item.isFull(stack) && stack.count == 1) {
matterValue -= item.addMatterValue(stack, matterValue, false)
container.setChanged(OUTPUT_DUST_MAIN)
// первый слот не пустой и мы не можем влить туда материю
} else {
val stack2 = container[OUTPUT_DUST_STACKING]
// второй слот пустой
if (stack2.isEmpty) {
container[OUTPUT_DUST_STACKING] = ItemStack(item, 1).also {
matterValue -= item.addMatterValue(it, matterValue, false)
}
// второй слот не пустой, но мы можем влить туда материю
} else if (!item.isFull(stack2)) {
if (stack2.count != 1) {
job.data["value"] = matterValue.serializeNBT()
return MachineJobStatus(false, 20)
}
matterValue -= item.addMatterValue(stack2, matterValue, false)
container.setChanged(OUTPUT_DUST_STACKING)
}
// можем ли мы стакнуть материю из второго слота в первый?
if (!stack2.isEmpty && item.isFull(stack2)) {
if (ItemStack.isSameItemSameTags(stack, stack2) && container.getMaxStackSizeWithItem(OUTPUT_DUST_MAIN) >= stack.count + 1) {
stack.count++
stack2.count--
container.setChanged(OUTPUT_DUST_MAIN)
container.setChanged(OUTPUT_DUST_STACKING)
} else {
job.data["value"] = matterValue.serializeNBT()
return MachineJobStatus(false, 20)
}
}
}
}
return MachineJobStatus()
}
matterValue -= matter.receiveMatterInner(matterValue, false)
if (matterValue.isPositive) {
job.data["value"] = matterValue.serializeNBT()
return MachineJobStatus(false, 20)
}
return MachineJobStatus()
}
override fun computeNextJob(): MachineJob? {
val stack = itemContainer.getItem(0)
val stack = container[INPUT_SLOT]
if (!stack.isEmpty) {
val copy = stack.copy()
@ -133,9 +195,13 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
if (canDecompose(copy)) {
val matter = getMatterValue(copy)
if (!matter.isZero && this.matter.canReceiveAll(matter.value)) {
stack.shrink(1)
return MachineJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION)
if (!matter.isZero) {
stack.count--
return MachineJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION, CompoundTag().also {
it["to_dust"] = (level?.random?.nextDouble() ?: 1.0) <= 1.0
it["value"] = matter.value.serializeNBT()
})
}
}
}
@ -160,13 +226,13 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
}
fun tick() {
batteryChargeLoop();
workerLoop();
batteryChargeLoop()
workerLoop()
val grid = node.graph as MatterNetworkGraph?
val grid = node.graph as MatterNetworkGraph? ?: return
if (!matter.storedMatter.isZero && grid != null) {
val diff = matter.extractMatterInner(matter.getStoredMatter(), true)
if (!matter.storedMatter.isZero) {
val diff = matter.extractMatterInner(matter.storedMatter, true)
val diff2 = grid.receiveMatter(diff, true)
matter.extractMatterInner(diff2, false)
@ -175,8 +241,15 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
}
companion object {
const val INPUT_SLOT = 0
const val OUTPUT_DUST_MAIN = 1
const val OUTPUT_DUST_STACKING = 2
private val CAPACITY = ImpreciseFraction("20")
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_decomposer")
private val BASE_CONSUMPTION = ImpreciseFraction(240)
private val ENERGY_STORAGE = ImpreciseFraction(400_000)
private val MAX_IO = ImpreciseFraction(2_000)
}
}

View File

@ -0,0 +1,182 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.worker.BlockEntityMatteryWorker
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJobStatus
import ru.dbotthepony.mc.otm.block.entity.worker.WorkTickContext
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.item.ItemMatterDust
import ru.dbotthepony.mc.otm.menu.MenuMatterRecycler
import ru.dbotthepony.mc.otm.set
class BlockEntityMatterRecycler(blockPos: BlockPos, blockState: BlockState)
: BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_RECYCLER, blockPos, blockState), IMatterGraphNode {
val matter = MatterHandlerCapability(this::setChangedLight, IMatterHandler.MatterDirection.EXTRACT, STORAGE)
val container = MatteryContainer(this::setChangedLight, 1)
private val node = Graph6Node<IMatterGraphNode>(this)
private var resolverNode = LazyOptional.of { this }
private var valid = true
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
override fun getMatterHandler(): IMatterHandler {
return matter
}
init {
energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, MAX_POWER)
}
private val itemHandler = container.handler(object : MatteryContainerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.item is ItemMatterDust
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return false
}
})
override fun invalidateCaps() {
super.invalidateCaps()
matter.invalidate()
itemHandler.invalidate()
resolverNode.invalidate()
}
override fun reviveCaps() {
super.reviveCaps()
matter.revive()
itemHandler.revive()
resolverNode = LazyOptional.of { this }
}
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["matter"] = matter.serializeNBT()
nbt["container"] = container.serializeNBT()
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("matter", CompoundTag::class.java, matter::deserializeNBT)
container.deserializeNBT(nbt["container"])
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (!valid)
return super.getCapability(cap, side)
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return itemHandler.get().cast()
} else if (cap === MatteryCapability.MATTER) {
return matter.get().cast()
} else if (cap === MatteryCapability.MATTER_NODE) {
return resolverNode.cast()
}
return super.getCapability(cap, side)
}
override fun getDefaultDisplayName() = NAME
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MenuMatterRecycler(containerID, inventory, this)
}
override fun onJobFinish(job: MachineJob): MachineJobStatus {
// вся логика в onWorkTick
return MachineJobStatus()
}
override fun computeNextJob(): MachineJob? {
if (matter.missingMatter.isZero)
return null
val stack = container[0]
if (stack.isEmpty || stack.item !is ItemMatterDust) {
return null
}
val copy = stack.copy()
copy.count = 1
val dustMatter = (stack.item as ItemMatterDust).getMatterValue(copy) ?: return null
stack.shrink(1)
return MachineJob(copy, dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION)
}
override fun onWorkTick(context: WorkTickContext): MachineJobStatus {
if ((level?.random?.nextDouble() ?: 1.0) <= 0.4)
return MachineJobStatus()
val receive = if (context.ticksAdvanced == 1.0) MATTER_PER_TICK else MATTER_PER_TICK * context.ticksAdvanced
val received = matter.receiveMatterInner(receive, true)
if (receive != received)
return MachineJobStatus(false, 20)
matter.receiveMatterInner(receive, false)
return MachineJobStatus()
}
fun tick() {
basicTicker()
val graph = node.graph as MatterNetworkGraph? ?: return
val received = graph.receiveMatter(matter.storedMatter, false)
if (!received.isZero) {
matter.extractMatterInner(received, false)
}
}
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_recycler")
private val STORAGE = ImpreciseFraction(40)
private val POWER_CONSUMPTION = ImpreciseFraction(80)
private val MAX_POWER = ImpreciseFraction(80_000)
private const val MATTER_TICKS = 200.0
private val MATTER_PER_TICK = ImpreciseFraction(1.0 / MATTER_TICKS)
}
}

View File

@ -7,7 +7,6 @@ import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatteryPowered
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
@ -154,10 +153,24 @@ abstract class BlockEntityMatteryWorker(p_155228_: BlockEntityType<*>, p_155229_
if (workTicks < currentJob.ticks) {
if (!currentJob.power.isZero) {
val extractedPower = energy.extractEnergyInner(currentJob.power, true)
val workSpeed = extractedPower.div(currentJob.power)
// сколько осталось тиков работать
val ticksLeft = currentJob.ticks - workTicks
val requiredPower: ImpreciseFraction
val status = onWorkTick(WorkTickContext(currentJob, currentJob.power, extractedPower, workSpeed))
// запрос энергии на то количество, сколько действительно осталось работать
if (ticksLeft > 1.0) {
requiredPower = currentJob.power
} else {
requiredPower = currentJob.power * ticksLeft
}
val extractedPower = energy.extractEnergyInner(requiredPower, true)
// сколько тиков мы "проработали"
// может быть меньше, чем единица, если недостаточно питания или мы завершаем работу,
// для которой осталось дробное количество тиков
val ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft)
val status = onWorkTick(WorkTickContext(currentJob, requiredPower, extractedPower, ticksAdvanced))
if (!status.valid()) {
throttleTicks += status.throttle
@ -167,32 +180,27 @@ abstract class BlockEntityMatteryWorker(p_155228_: BlockEntityType<*>, p_155229_
workingTicksAnim++
errorTicksAnim = 0
val updatedWorkTicks = workSpeed.toDouble() + workTicks
val updatedWorkTicks = workTicks + ticksAdvanced
if (updatedWorkTicks > currentJob.ticks) {
if (updatedWorkTicks >= currentJob.ticks) {
workTicks = currentJob.ticks
energy.extractEnergyInner(extractedPower * (1.0 - (updatedWorkTicks - currentJob.ticks)), false)
energy.extractEnergyInner(
extractedPower.times(1.0 - (updatedWorkTicks - currentJob.ticks())),
false
)
val finish = onJobFinish(currentJob)
if (finish.valid) {
this.currentJob = null
workTicks = 0.0
} else {
throttleTicks += finish.throttle
}
} else {
workTicks = updatedWorkTicks
energy.extractEnergyInner(extractedPower, false)
if (workTicks >= currentJob.ticks) {
val finish = onJobFinish(currentJob)
if (finish.valid) {
this.currentJob = null
workTicks = 0.0
} else {
throttleTicks += finish.throttle
}
}
}
} else {
val status = onWorkTick(WorkTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ImpreciseFraction.ONE))
val ticksLeft = (currentJob.ticks - workTicks).coerceAtMost(1.0)
val status = onWorkTick(WorkTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ticksLeft))
if (!status.valid) {
throttleTicks += status.throttle()

View File

@ -22,7 +22,8 @@ class ScreenMatterDecomposer(p_97741_: MenuMatterDecomposer, p_97742_: Inventory
SlotPanel(this, frame, menu.input, 56f, PROGRESS_SLOT_TOP)
ProgressGaugePanel(this, frame, menu.progressWidget, 78f, PROGRESS_ARROW_TOP)
SlotPanel(this, frame, menu.output, 104f, PROGRESS_SLOT_TOP)
SlotPanel(this, frame, menu.outputMain, 104f, PROGRESS_SLOT_TOP)
SlotPanel(this, frame, menu.outputStacking, 122f, PROGRESS_SLOT_TOP)
return frame
}

View File

@ -0,0 +1,26 @@
package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.MenuMatterRecycler
class ScreenMatterRecycler(menu: MenuMatterRecycler, inventory: Inventory, title: Component) : MatteryScreen<MenuMatterRecycler>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!!
val m = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT)
SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
ProgressGaugePanel(this, frame, menu.progress, 63f, PROGRESS_ARROW_TOP).flop = true
SlotPanel(this, frame, menu.input, 93f, PROGRESS_SLOT_TOP)
return frame
}
}

View File

@ -14,7 +14,6 @@ class ScreenMatterScanner(p_97741_: MenuMatterScanner, p_97742_: Inventory, p_97
override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!!
val m = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
PatternGaugePanel(this, frame, menu.patterns, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT)

View File

@ -156,6 +156,16 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
open fun getMaxStackSize(slot: Int) = maxStackSize
open fun getMaxStackSizeWithItem(slot: Int): Int {
val item = this[slot]
if (!item.isEmpty) {
return Math.min(getMaxStackSize(slot), item.maxStackSize)
}
return getMaxStackSize(slot)
}
@JvmOverloads
fun addItem(stack: ItemStack, start: Int = 0, end: Int = size - 1, simulate: Boolean = false): ItemStack {
if (stack.isEmpty || start < 0 || end >= size || start > end)

View File

@ -155,6 +155,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
operator fun minus(other: ImpreciseFraction) = ImpreciseFraction(whole - other.whole, decimal - other.decimal)
operator fun times(other: ImpreciseFraction): ImpreciseFraction {
if (other == ONE)
return this
else if (other == MINUS_ONE)
return -this
val a = whole
val c = other.whole
@ -226,6 +231,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
}
operator fun div(other: ImpreciseFraction): ImpreciseFraction {
if (other == ONE)
return this
else if (other == MINUS_ONE)
return -this
if (isZero && other.isZero)
return this
@ -269,7 +279,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
operator fun div(other: Long): ImpreciseFraction = div(ImpreciseFraction(other))
operator fun unaryMinus(): ImpreciseFraction {
return ImpreciseFraction(-whole, decimal)
return ImpreciseFraction(-whole, -decimal)
}
override fun equals(other: Any?): Boolean {
@ -285,7 +295,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
fun equalsStrict(other: Any?): Boolean {
if (isNaN)
return false
return other is ImpreciseFraction && other.isNaN // ибо hashCode() так требует
if (other is ImpreciseFraction) {
return other.whole == whole && other.decimal == decimal
@ -298,7 +308,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
if (isNaN)
return Double.NaN.hashCode()
return 31 * decimal.hashCode() + whole.hashCode()
return 31 * (decimal - decimal % EPSILON).hashCode() + whole.hashCode()
}
fun toString(decimals: Int): String {
@ -346,7 +356,10 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
return sign
}
return if (decimal > 0.0) 1 else if (decimal < 0.0) -1 else 0
if (cmpDouble(decimal, 0.0))
return 0
return if (decimal > 0.0) 1 else -1
}
override fun compareTo(other: ImpreciseFraction): Int {
@ -409,6 +422,8 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
}
val isZero get() = cmpDouble(decimal, 0.0) && isZero(whole)
val isPositive get() = this > ZERO
val isNegative get() = this < ZERO
fun moreThanZero(): ImpreciseFraction {
if (signum() >= 0)
@ -537,6 +552,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
return ZERO
}
@JvmStatic
fun deserializeNBT(input: ByteArrayTag): ImpreciseFraction {
return fromByteArray(input.asByteArray)
}
@JvmStatic
fun read(buff: FriendlyByteBuf): ImpreciseFraction {
val len = unsignedInt(buff.readByte())

View File

@ -0,0 +1,75 @@
package ru.dbotthepony.mc.otm.item
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.matter.IMatterItem
import ru.dbotthepony.mc.otm.matter.MatterTuple
import ru.dbotthepony.mc.otm.set
class ItemMatterDust : Item(Properties().tab(OverdriveThatMatters.CREATIVE_TAB).stacksTo(64)), IMatterItem {
private fun matter(stack: ItemStack): ImpreciseFraction {
return stack.tag?.get("matter")?.let { return@let ImpreciseFraction.deserializeNBT(it) } ?: return ImpreciseFraction.ZERO
}
private fun matter(stack: ItemStack, matter: ImpreciseFraction) {
stack.orCreateTag["matter"] = matter.serializeNBT()
}
override fun getMatterValue(stack: ItemStack): MatterTuple? {
val value = stack.tag?.get("matter") ?: return null
return MatterTuple(ImpreciseFraction.deserializeNBT(value), 0.0)
}
override fun canDecompose(stack: ItemStack) = false
override fun appendHoverText(
p_41421_: ItemStack,
p_41422_: Level?,
p_41423_: MutableList<Component>,
p_41424_: TooltipFlag
) {
super.appendHoverText(p_41421_, p_41422_, p_41423_, p_41424_)
val matter = this.getMatterValue(p_41421_)
if (matter == null) {
p_41423_.add(DESC)
}
p_41423_.add(DESC2)
}
fun addMatterValue(stack: ItemStack, matter: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (stack.count != 1)
return ImpreciseFraction.ZERO
val matterThis = matter(stack)
if (matterThis >= MAX_MATTER_IN_ITEM)
return ImpreciseFraction.ZERO
val newMatter = (matterThis + matter).min(MAX_MATTER_IN_ITEM)
val diff = newMatter - matterThis
if (!simulate)
matter(stack, newMatter)
return diff
}
fun isFull(stack: ItemStack): Boolean {
return matter(stack) >= MAX_MATTER_IN_ITEM
}
companion object {
private val DESC = TranslatableComponent("item.overdrive_that_matters.matter_dust.desc").withStyle(ChatFormatting.DARK_GRAY)
private val DESC2 = TranslatableComponent("item.overdrive_that_matters.matter_dust.desc2").withStyle(ChatFormatting.GRAY)
val MAX_MATTER_IN_ITEM = ImpreciseFraction(4)
}
}

View File

@ -33,6 +33,12 @@ interface MatterTuplePredicate {
fun accept(item: Item): MatterTuple?
}
interface IMatterItem {
fun getMatterValue(stack: ItemStack): MatterTuple?
fun hasMatterValue(stack: ItemStack) = getMatterValue(stack) != null
fun canDecompose(stack: ItemStack): Boolean
}
private val rootEntries = HashMap<Item, MatterTuple>()
private val derivedEntries = HashMap<Item, MatterTuple>()
@ -123,26 +129,48 @@ val derivedEntriesAccess = object : MutableMap<Item, MatterTuple> by derivedEntr
}
fun getMatterValue(item: Item): MatterTuple {
if (item is IMatterItem)
return item.getMatterValue(ItemStack.EMPTY) ?: MatterTuple.ZERO
return rootEntries[item] ?: derivedEntries[item] ?: MatterTuple.ZERO
}
fun getMatterValueNullable(item: Item): MatterTuple? {
if (item is IMatterItem)
return item.getMatterValue(ItemStack.EMPTY)
return rootEntries[item] ?: derivedEntries[item]
}
fun hasMatterValue(item: Item): Boolean {
if (item is IMatterItem)
return item.hasMatterValue(ItemStack.EMPTY)
return !getMatterValue(item).isZero
}
fun hasMatterValue(stack: ItemStack): Boolean {
val item = stack.item
if (item is IMatterItem)
return item.hasMatterValue(stack)
return !getMatterValue(stack).isZero
}
fun canDecompose(item: Item): Boolean {
if (item is IMatterItem)
return item.canDecompose(ItemStack.EMPTY)
return hasMatterValue(item)
}
fun canDecompose(stack: ItemStack): Boolean {
val item = stack.item
if (item is IMatterItem)
return item.canDecompose(stack)
return canDecompose(stack.item) &&
(stack.getCapability(MatteryCapability.MATTER).orNull()?.storedMatter ?: ImpreciseFraction.ZERO).isZero &&
(stack.getCapability(MatteryCapability.DRIVE).orNull()?.storedCount ?: ImpreciseFraction.ZERO).isZero
@ -157,10 +185,10 @@ private fun getMatterValue(stack: ItemStack, level: Int): MatterTuple {
var matter = getMatterValue(stack.item)
if (matter.isZero)
return matter
if (stack.item is IMatterItem)
matter = (stack.item as IMatterItem).getMatterValue(stack) ?: MatterTuple.ZERO
if (stack.isDamageableItem) {
if (!matter.isZero && stack.isDamageableItem) {
val severity = stack.damageValue.toDouble() / stack.maxDamage.toDouble()
matter = MatterTuple(matter.value * severity, matter.complexity * (1.0 - severity / 2))
}
@ -225,11 +253,15 @@ fun tooltipEvent(event: ItemTooltipEvent) {
val matter = getMatterValue(event.itemStack)
if (!matter.isZero) {
event.toolTip.add(
TranslatableComponent("otm.gui.matter.format_and_complexity",
FormattingHelper.formatMatterValue(matter.value),
"%.3f".format(matter.complexity)
).withStyle(ChatFormatting.AQUA))
if (matter.complexity >= 1.0E-3) {
event.toolTip.add(
TranslatableComponent("otm.gui.matter.format_and_complexity",
FormattingHelper.formatMatterValue(matter.value),
"%.3f".format(matter.complexity)
).withStyle(ChatFormatting.AQUA))
} else {
event.toolTip.add(FormattingHelper.formatMatterValue(matter.value).withStyle(ChatFormatting.AQUA))
}
}
}
}
@ -260,6 +292,7 @@ data class MatterTuple(val value: ImpreciseFraction, val complexity: Double): Co
}
val isZero get() = value.isZero
val isZeroComplexity get() = complexity <= 0.0
companion object {
@JvmField val ZERO = MatterTuple(ImpreciseFraction.ZERO, 0.0)

View File

@ -18,25 +18,27 @@ class MenuMatterDecomposer @JvmOverloads constructor(
tile: BlockEntityMatterDecomposer? = null
) : MenuMatteryPowered(Registry.Menus.MATTER_DECOMPOSER, containerID, inventory, tile) {
val input: MatterySlot
val output: MachineOutputSlot
val outputMain: MachineOutputSlot
val outputStacking: MachineOutputSlot
val progressWidget: ProgressGaugeWidget
val matterWidget: LevelGaugeWidget
init {
val container = tile?.itemContainer ?: SimpleContainer(2)
val container = tile?.container ?: SimpleContainer(3)
// Вход
input = object : MatterySlot(container, 0, 61, 36) {
override fun mayPlace(p_40231_: ItemStack): Boolean {
return canDecompose(p_40231_)
}
input = object : MatterySlot(container, 0) {
override fun mayPlace(p_40231_: ItemStack) = canDecompose(p_40231_)
}
addSlot(input)
// Выход
output = MachineOutputSlot(container, 1, 61 + 18 + 10 + 3 + 22, 36)
addSlot(output)
outputMain = MachineOutputSlot(container, 1)
outputStacking = MachineOutputSlot(container, 2)
addSlot(outputMain)
addSlot(outputStacking)
matterWidget = LevelGaugeWidget(this, tile?.getCapability(MatteryCapability.MATTER)?.orNull())
@ -54,6 +56,6 @@ class MenuMatterDecomposer @JvmOverloads constructor(
}
override fun getWorkingSlotEnd(): Int {
return 2
return 3
}
}

View File

@ -0,0 +1,47 @@
package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterRecycler
import ru.dbotthepony.mc.otm.item.ItemMatterDust
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
class MenuMatterRecycler @JvmOverloads constructor(
containerID: Int,
inventory: Inventory,
tile: BlockEntityMatterRecycler? = null
) : MenuMatteryPowered(Registry.Menus.MATTER_RECYCLER, containerID, inventory, tile) {
val input: MatterySlot
val progress: ProgressGaugeWidget
val matter = LevelGaugeWidget(this, tile?.matter)
init {
val container = tile?.container ?: SimpleContainer(1)
input = object : MatterySlot(container, 0) {
override fun mayPlace(p_40231_: ItemStack): Boolean {
return p_40231_.item is ItemMatterDust && (p_40231_.item as ItemMatterDust).getMatterValue(p_40231_) != null
}
}
if (tile == null) {
progress = ProgressGaugeWidget(this)
} else {
progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess)
}
addSlot(input)
addInventorySlots()
}
override fun getWorkingSlotStart(): Int {
return 0
}
override fun getWorkingSlotEnd(): Int {
return 2
}
}

View File

@ -198,6 +198,8 @@
"block.overdrive_that_matters.gravitation_stabilizer.desc3": "Keep in mind the effect of multiple stabilizers produce exponentially increasing result",
"block.overdrive_that_matters.gravitation_stabilizer.desc4": "Too weak gravitation field will cause singularity to melt and evaporate away very fast",
"block.overdrive_that_matters.matter_recycler": "Matter Recycler",
"otm.container.matter_panel.number_input": "Input replication task count",
"otm.container.matter_panel.increase_by": "+%s",
@ -230,6 +232,10 @@
"item.overdrive_that_matters.pill_oblivion": "Android Factory Reset Pill",
"item.overdrive_that_matters.pill_heal": "Medical Pill",
"item.overdrive_that_matters.matter_dust": "Matter Dust",
"item.overdrive_that_matters.matter_dust.desc": "This item is product of failed decomposition or replication attempt",
"item.overdrive_that_matters.matter_dust.desc2": "Throw into matter recycler to get some of it's value back!",
"item.overdrive_that_matters.portable_condensation_drive": "Portable Condensation Drive",
"item.overdrive_that_matters.portable_dense_condensation_drive": "Portable Dense Condensation Drive",

View File

@ -12,6 +12,7 @@
"overdrive_that_matters:matter_replicator",
"overdrive_that_matters:matter_bottler",
"overdrive_that_matters:drive_viewer",
"overdrive_that_matters:matter_recycler",
"overdrive_that_matters:tritanium_block",
"overdrive_that_matters:tritanium_striped_block",

View File

@ -12,6 +12,7 @@
"overdrive_that_matters:matter_replicator",
"overdrive_that_matters:matter_bottler",
"overdrive_that_matters:drive_viewer",
"overdrive_that_matters:matter_recycler",
"overdrive_that_matters:tritanium_block",
"overdrive_that_matters:tritanium_striped_block",