up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
package block
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/item/inventory"
|
||||
"github.com/df-mc/dragonfly/server/item/recipe"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/sound"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// brewer is a struct that may be embedded by blocks that can brew potions, such as brewing stands.
|
||||
type brewer struct {
|
||||
mu sync.Mutex
|
||||
|
||||
viewers map[ContainerViewer]struct{}
|
||||
inventory *inventory.Inventory
|
||||
|
||||
duration time.Duration
|
||||
fuelAmount int32
|
||||
fuelTotal int32
|
||||
}
|
||||
|
||||
// newBrewer creates a new initialised brewer. The inventory is properly initialised.
|
||||
func newBrewer() *brewer {
|
||||
b := &brewer{viewers: make(map[ContainerViewer]struct{})}
|
||||
b.inventory = inventory.New(5, func(slot int, _, item item.Stack) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
for viewer := range b.viewers {
|
||||
viewer.ViewSlotChange(slot, item)
|
||||
}
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// InsertItem ...
|
||||
func (b *brewer) InsertItem(h Hopper, pos cube.Pos, tx *world.Tx) bool {
|
||||
for sourceSlot, sourceStack := range h.inventory.Slots() {
|
||||
var slot int
|
||||
|
||||
if sourceStack.Empty() {
|
||||
continue
|
||||
}
|
||||
|
||||
if h.Facing == cube.FaceDown {
|
||||
if !recipe.ValidBrewingReagent(sourceStack.Item()) {
|
||||
// This item is not a valid brewing reagent.
|
||||
continue
|
||||
}
|
||||
slot = 0
|
||||
} else if _, ok := sourceStack.Item().(item.BlazePowder); ok {
|
||||
slot = 4
|
||||
} else {
|
||||
_, okPotion := sourceStack.Item().(item.Potion)
|
||||
_, okSplash := sourceStack.Item().(item.SplashPotion)
|
||||
_, okLingering := sourceStack.Item().(item.LingeringPotion)
|
||||
_, okBottle := sourceStack.Item().(item.GlassBottle)
|
||||
if !okPotion && !okSplash && !okLingering && !okBottle {
|
||||
continue
|
||||
}
|
||||
for brewingSlot, brewingStack := range b.inventory.Slots() {
|
||||
if brewingSlot == 0 || brewingSlot == 4 {
|
||||
continue
|
||||
}
|
||||
if brewingStack.Count() == brewingStack.MaxCount() || !brewingStack.Comparable(sourceStack) {
|
||||
continue
|
||||
}
|
||||
|
||||
slot = brewingSlot
|
||||
break
|
||||
}
|
||||
// Could not find an empty slot
|
||||
if slot == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
stack := sourceStack.Grow(-sourceStack.Count() + 1)
|
||||
it, _ := b.Inventory(tx, pos).Item(slot)
|
||||
|
||||
if !sourceStack.Comparable(it) {
|
||||
// The items are not the same.
|
||||
continue
|
||||
}
|
||||
if it.Count() == it.MaxCount() {
|
||||
// The item has the maximum count that the stack is able to hold.
|
||||
continue
|
||||
}
|
||||
if !it.Empty() {
|
||||
stack = it.Grow(1)
|
||||
}
|
||||
|
||||
_ = b.Inventory(tx, pos).SetItem(slot, stack)
|
||||
_ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1))
|
||||
return true
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ExtractItem ...
|
||||
func (b *brewer) ExtractItem(h Hopper, pos cube.Pos, tx *world.Tx) bool {
|
||||
for sourceSlot, sourceStack := range b.inventory.Slots() {
|
||||
if sourceStack.Empty() || sourceSlot == 0 || sourceSlot == 4 {
|
||||
continue
|
||||
}
|
||||
_, err := h.inventory.AddItem(sourceStack.Grow(-sourceStack.Count() + 1))
|
||||
if err != nil {
|
||||
// The hopper is full.
|
||||
continue
|
||||
}
|
||||
_ = b.Inventory(tx, pos).SetItem(sourceSlot, sourceStack.Grow(-1))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Duration returns the remaining duration of the brewing process.
|
||||
func (b *brewer) Duration() time.Duration {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.duration
|
||||
}
|
||||
|
||||
// Fuel returns the fuel and maximum fuel of the brewer.
|
||||
func (b *brewer) Fuel() (fuel, maxFuel int32) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.fuelAmount, b.fuelTotal
|
||||
}
|
||||
|
||||
// Inventory returns the inventory of the brewer.
|
||||
func (b *brewer) Inventory(*world.Tx, cube.Pos) *inventory.Inventory {
|
||||
return b.inventory
|
||||
}
|
||||
|
||||
// AddViewer adds a viewer to the brewer, so that it is updated whenever the inventory of the brewer is changed.
|
||||
func (b *brewer) AddViewer(v ContainerViewer, _ *world.Tx, _ cube.Pos) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.viewers[v] = struct{}{}
|
||||
}
|
||||
|
||||
// RemoveViewer removes a viewer from the brewer, so that slot updates in the inventory are no longer sent to
|
||||
// it.
|
||||
func (b *brewer) RemoveViewer(v ContainerViewer, _ *world.Tx, _ cube.Pos) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
delete(b.viewers, v)
|
||||
}
|
||||
|
||||
// setDuration sets the brew duration of the brewer to the given duration.
|
||||
func (b *brewer) setDuration(duration time.Duration) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.duration = duration
|
||||
}
|
||||
|
||||
// setFuel sets the fuel of the brewer to the given fuel and maximum fuel.
|
||||
func (b *brewer) setFuel(fuel, maxFuel int32) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.fuelAmount, b.fuelTotal = fuel, maxFuel
|
||||
}
|
||||
|
||||
// tickBrewing ticks the brewer, ensuring the necessary items exist in the brewer, and then processing all inputted
|
||||
// items for the necessary duration.
|
||||
func (b *brewer) tickBrewing(block string, pos cube.Pos, tx *world.Tx) {
|
||||
b.mu.Lock()
|
||||
|
||||
// Get each item in the brewer. We don't need to validate errors here since we know the bounds of the brewer.
|
||||
left, _ := b.inventory.Item(1)
|
||||
middle, _ := b.inventory.Item(2)
|
||||
right, _ := b.inventory.Item(3)
|
||||
|
||||
// Keep track of our past durations, since if any of them change, we need to be able to tell they did and then
|
||||
// update the viewers on the change.
|
||||
prevDuration := b.duration
|
||||
prevFuelAmount := b.fuelAmount
|
||||
prevFuelTotal := b.fuelTotal
|
||||
|
||||
// If we need fuel, try and burn some.
|
||||
fuel, _ := b.inventory.Item(4)
|
||||
|
||||
if _, ok := fuel.Item().(item.BlazePowder); ok && b.fuelAmount <= 0 {
|
||||
defer b.inventory.SetItem(4, fuel.Grow(-1))
|
||||
b.fuelAmount, b.fuelTotal = 20, 20
|
||||
}
|
||||
|
||||
// Now get the ingredient item.
|
||||
ingredient, _ := b.inventory.Item(0)
|
||||
|
||||
// Check each input and see if it is affected by the ingredient.
|
||||
leftOutput, leftAffected := recipe.Perform(block, left.Item(), ingredient.Item())
|
||||
middleOutput, middleAffected := recipe.Perform(block, middle.Item(), ingredient.Item())
|
||||
rightOutput, rightAffected := recipe.Perform(block, right.Item(), ingredient.Item())
|
||||
|
||||
// Ensure that we have enough fuel to continue.
|
||||
if b.fuelAmount > 0 {
|
||||
// Now make sure that we have at least one potion that is affected by the ingredient.
|
||||
if leftAffected || middleAffected || rightAffected {
|
||||
// Tick our duration. If we have no brew duration, set it to the default of twenty seconds.
|
||||
if b.duration == 0 {
|
||||
b.duration = time.Second * 20
|
||||
}
|
||||
b.duration -= time.Millisecond * 50
|
||||
|
||||
// If we have no duration, we are done.
|
||||
if b.duration <= 0 {
|
||||
// Create the output items.
|
||||
if leftAffected {
|
||||
defer b.inventory.SetItem(1, leftOutput[0])
|
||||
}
|
||||
if middleAffected {
|
||||
defer b.inventory.SetItem(2, middleOutput[0])
|
||||
}
|
||||
if rightAffected {
|
||||
defer b.inventory.SetItem(3, rightOutput[0])
|
||||
}
|
||||
|
||||
// Reduce the ingredient by one.
|
||||
defer b.inventory.SetItem(0, ingredient.Grow(-1))
|
||||
tx.PlaySound(pos.Vec3Centre(), sound.PotionBrewed{})
|
||||
|
||||
// Decrement the fuel, and reset the duration.
|
||||
b.fuelAmount--
|
||||
b.duration = 0
|
||||
}
|
||||
} else {
|
||||
// None of the potions are affected by the ingredient, so reset the duration.
|
||||
b.duration = 0
|
||||
}
|
||||
} else {
|
||||
// We don't have enough fuel, so reset our progress.
|
||||
b.duration, b.fuelAmount, b.fuelTotal = 0, 0, 0
|
||||
}
|
||||
|
||||
// Update the viewers on the new durations.
|
||||
for v := range b.viewers {
|
||||
v.ViewBrewingUpdate(prevDuration, b.duration, prevFuelAmount, b.fuelAmount, prevFuelTotal, b.fuelTotal)
|
||||
}
|
||||
|
||||
b.mu.Unlock()
|
||||
}
|
||||
Reference in New Issue
Block a user