github.com/df-mc/dragonfly@v0.9.13/server/session/handler_beacon.go (about) 1 package session 2 3 import ( 4 "fmt" 5 "github.com/df-mc/dragonfly/server/block" 6 "github.com/df-mc/dragonfly/server/entity/effect" 7 "github.com/df-mc/dragonfly/server/item" 8 "github.com/sandertv/gophertunnel/minecraft/protocol" 9 ) 10 11 // beaconInputSlot is the slot index of the input item in the beacon. 12 const beaconInputSlot = 0x1b 13 14 // handleBeaconPayment handles the selection of effects in a beacon and the removal of the item used to pay 15 // for those effects. 16 func (h *ItemStackRequestHandler) handleBeaconPayment(a *protocol.BeaconPaymentStackRequestAction, s *Session) error { 17 slot := protocol.StackRequestSlotInfo{ 18 ContainerID: protocol.ContainerBeaconPayment, 19 Slot: beaconInputSlot, 20 } 21 // First check if there actually is a beacon opened. 22 if !s.containerOpened.Load() { 23 return fmt.Errorf("no beacon container opened") 24 } 25 pos := s.openedPos.Load() 26 beacon, ok := s.c.World().Block(pos).(block.Beacon) 27 if !ok { 28 return fmt.Errorf("no beacon container opened") 29 } 30 31 // Check if the item present in the beacon slot is valid. 32 payment, _ := h.itemInSlot(slot, s) 33 if payable, ok := payment.Item().(item.BeaconPayment); !ok || !payable.PayableForBeacon() { 34 return fmt.Errorf("item %#v in beacon slot cannot be used as payment", payment) 35 } 36 37 // Check if the effects are valid and allowed for the beacon's level. 38 if !h.validBeaconEffect(a.PrimaryEffect, beacon) { 39 return fmt.Errorf("primary effect selected is not allowed: %v for level %v", a.PrimaryEffect, beacon.Level()) 40 } else if !h.validBeaconEffect(a.SecondaryEffect, beacon) || (beacon.Level() < 4 && a.SecondaryEffect != 0) { 41 return fmt.Errorf("secondary effect selected is not allowed: %v for level %v", a.SecondaryEffect, beacon.Level()) 42 } 43 44 primary, pOk := effect.ByID(int(a.PrimaryEffect)) 45 secondary, sOk := effect.ByID(int(a.SecondaryEffect)) 46 if pOk { 47 beacon.Primary = primary.(effect.LastingType) 48 } 49 if sOk { 50 beacon.Secondary = secondary.(effect.LastingType) 51 } 52 s.c.World().SetBlock(pos, beacon, nil) 53 54 // The client will send a Destroy action after this action, but we can't rely on that because the client 55 // could just not send it. 56 // We just ignore the next Destroy action and set the item to air here. 57 h.setItemInSlot(slot, item.Stack{}, s) 58 h.ignoreDestroy = true 59 return nil 60 } 61 62 // validBeaconEffect checks if the ID passed is a valid beacon effect. 63 func (h *ItemStackRequestHandler) validBeaconEffect(id int32, beacon block.Beacon) bool { 64 switch id { 65 case 1, 3: 66 return beacon.Level() >= 1 67 case 8, 11: 68 return beacon.Level() >= 2 69 case 5: 70 return beacon.Level() >= 3 71 case 10: 72 return beacon.Level() >= 4 73 case 0: 74 return true 75 } 76 return false 77 }