From 5016a973da91ad0c43148ef4630070d902125fe9 Mon Sep 17 00:00:00 2001 From: abimek Date: Thu, 8 Sep 2022 07:20:04 -0400 Subject: [PATCH 1/9] Implementation of NPC Dialogues using their own api instead of the Forms api. --- server/player/dialogue/button.go | 29 +++++++++++ server/player/dialogue/button_type.go | 48 +++++++++++++++++ server/player/dialogue/dialogue.go | 9 ++++ server/player/dialogue/menu.go | 75 +++++++++++++++++++++++++++ server/player/dialogue/submit.go | 14 +++++ server/player/player.go | 15 ++++++ server/session/controllable.go | 2 + server/session/entity_metadata.go | 4 ++ server/session/handle_npc_request.go | 46 ++++++++++++++++ server/session/player.go | 52 +++++++++++++++++++ server/session/session.go | 2 + server/world/entity.go | 7 +++ 12 files changed, 303 insertions(+) create mode 100644 server/player/dialogue/button.go create mode 100644 server/player/dialogue/button_type.go create mode 100644 server/player/dialogue/dialogue.go create mode 100644 server/player/dialogue/menu.go create mode 100644 server/player/dialogue/submit.go create mode 100644 server/session/handle_npc_request.go diff --git a/server/player/dialogue/button.go b/server/player/dialogue/button.go new file mode 100644 index 000000000..48a20329b --- /dev/null +++ b/server/player/dialogue/button.go @@ -0,0 +1,29 @@ +package dialogue + +import "encoding/json" + +// Button represents a Button added to Menu. A button contains Name as well as an activation type and a general type. +type Button struct { + // Name is the name of the button and is displayed to the user. + Name string + // Activation is the specific method of activation required by the button. CLICK = 0, CLOSE = 1, ENTER = 2. + Activation ActivationType + // Type is the type of button / action it takes. + Type ButtonType +} + +// NewButton returns a new Button with the name, activationType, and buttonType passed. +func NewButton(name string, activationType ActivationType, buttonType ButtonType) Button { + return Button{Name: name, Activation: activationType, Type: buttonType} +} + +// MarshalJSON ... +func (b Button) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "button_name": b.Name, + "text": "", // Buttons don't work if this value isn't sent. + "mode": b.Activation.Uint8(), + "type": b.Type.Uint8(), + } + return json.Marshal(data) +} diff --git a/server/player/dialogue/button_type.go b/server/player/dialogue/button_type.go new file mode 100644 index 000000000..fcd5469bb --- /dev/null +++ b/server/player/dialogue/button_type.go @@ -0,0 +1,48 @@ +package dialogue + +type activation uint8 + +// ActivationType represents a specific type of activation on a Button. The different types are Click, Close, and Enter. +type ActivationType struct { + activation +} + +func (a activation) Uint8() uint8 { + return uint8(a) +} + +// ActivationClick specifies on activating a button when its clicked. +func ActivationClick() ActivationType { + return ActivationType{0} +} + +// ActivationClose is the close activation. +func ActivationClose() ActivationType { + return ActivationType{1} +} + +// ActivationEnter is the enter activation type. +func ActivationEnter() ActivationType { + return ActivationType{2} +} + +type button uint8 + +// ButtonType represents the type of Button. URL, COMMAND, and UNKNOWN are all the button types. +type ButtonType struct { + button +} + +func (b button) Uint8() uint8 { + return uint8(b) +} + +// CommandButton is a button meant to execute a command. +func CommandButton() ButtonType { + return ButtonType{1} +} + +// UnknownButton has unknown behaviour as of the moment. +func UnknownButton() ButtonType { + return ButtonType{2} +} diff --git a/server/player/dialogue/dialogue.go b/server/player/dialogue/dialogue.go new file mode 100644 index 000000000..ccf5db4e4 --- /dev/null +++ b/server/player/dialogue/dialogue.go @@ -0,0 +1,9 @@ +package dialogue + +// Dialogue represents a singular dialog scene. Scenes are used to within NewMenu to create a new Dialog Menu. Submit is +// called when a button is submitted by a Submitter. +type Dialogue interface { + Menu() Menu + // Submit is called when a Submitter submits a Button on the specified Menu. + Submit(submitter Submitter, pressed Button) +} diff --git a/server/player/dialogue/menu.go b/server/player/dialogue/menu.go new file mode 100644 index 000000000..e7edb0985 --- /dev/null +++ b/server/player/dialogue/menu.go @@ -0,0 +1,75 @@ +package dialogue + +import ( + "encoding/json" + "fmt" + "github.com/df-mc/dragonfly/server/world" + "strings" +) + +// Menu represents a npc dialogue. It contains a title, body, entity, and a number of buttons no more than +// 6. +type Menu struct { + title, body string + // action represents the action this menu is executing. This value is either packet.NPCDialogueActionOpen or + // packet.NPCDialogueActionClose. + npc world.NPC + buttons []Button +} + +// NewMenu creates a new Menu with the Dialogue passed. Title is formatted with accordance to the rules of fmt.Sprintln. +func NewMenu(npc world.NPC, title ...any) Menu { + return Menu{ + title: format(title), + npc: npc, + } +} + +// WithButtons creates a copy of the dialogue Menu and appends the buttons passed to the existing buttons, after +// which the new dialogue Menu is returned. If the count of the buttons passed and the buttons already within the Menu +// pass the threshold of 6, it will return an empty Menu and an error. +func (m Menu) WithButtons(buttons ...Button) (Menu, error) { + if len(m.buttons)+len(buttons) > 6 { + return Menu{}, fmt.Errorf("menu has %v buttons, an addition of %v will pass the 6 buttons threashold", len(m.buttons), len(buttons)) + } + m.buttons = append(m.buttons, buttons...) + return m, nil +} + +// WithBody creates a copy of the dialogue Menu and replaces the existing body with the body passed, after which the +// new dialogue Menu is returned. The text is formatted following the rules of fmt.Sprintln. +func (m Menu) WithBody(body ...any) Menu { + m.body = format(body) + return m +} + +// NPC returns the entity associated with this Menu. +func (m Menu) NPC() world.Entity { + return m.npc +} + +// Body returns the formatted body passed to Menu by WithBody() +func (m Menu) Body() string { + return m.body +} + +// Buttons will return all the buttons passed to Menu by WithButtons(). +func (m Menu) Buttons() []Button { + return m.buttons +} + +// Title returns the formatted body passed to Menu from NewMenu() +func (m Menu) Title() string { + return m.title +} + +// MarshalJSON ... +func (m Menu) MarshalJSON() ([]byte, error) { + return json.Marshal(m.Buttons()) +} + +// format is a utility function to format a list of values to have spaces between them, but no newline at the +// end. +func format(a []any) string { + return strings.TrimSuffix(strings.TrimSuffix(fmt.Sprintln(a...), "\n"), "\n") +} diff --git a/server/player/dialogue/submit.go b/server/player/dialogue/submit.go new file mode 100644 index 000000000..47cb4cbc6 --- /dev/null +++ b/server/player/dialogue/submit.go @@ -0,0 +1,14 @@ +package dialogue + +// Submitter is an entity that is able to open a dialog and submit it by clicking a button. The entity can also have +// a dialogue force closed upon it by the server. +type Submitter interface { + SendDialogue(d Dialogue) + CloseDialogue(d Dialogue) +} + +// Closer represents a scene that has special logic when the dialogue scene is closed. +type Closer interface { + // Close gets called when a Submitter closes a dialogue. + Close(submitter Submitter) +} diff --git a/server/player/player.go b/server/player/player.go index ad6cf606e..f87e2da91 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -2,6 +2,7 @@ package player import ( "fmt" + "github.com/df-mc/dragonfly/server/player/dialogue" "math" "math/rand" "net" @@ -389,6 +390,20 @@ func (p *Player) SendForm(f form.Form) { p.session().SendForm(f) } +// SendDialogue sends a dialogue to the player for the client to fill out. Once the client fills it out, the Submit +// method of the form will be called. +// Note that the client may also close the form instead of filling it out, which will result in the Close method to be +// called on the dialogue if it implements dialogue.Closer. +func (p *Player) SendDialogue(d dialogue.Dialogue) { + p.session().SendDialogue(d) +} + +// CloseDialogue closes any dialogue that may be open to a user. Note that when this method is closed, if the dialogue +// implements dialogue.Closer the Close method will still execute. +func (p *Player) CloseDialogue(d dialogue.Dialogue) { + p.session().CloseDialogue(d) +} + // ShowCoordinates enables the vanilla coordinates for the player. func (p *Player) ShowCoordinates() { p.session().EnableCoordinates(true) diff --git a/server/session/controllable.go b/server/session/controllable.go index 6dab37815..f806c1c78 100644 --- a/server/session/controllable.go +++ b/server/session/controllable.go @@ -7,6 +7,7 @@ import ( "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/item/inventory" "github.com/df-mc/dragonfly/server/player/chat" + "github.com/df-mc/dragonfly/server/player/dialogue" "github.com/df-mc/dragonfly/server/player/form" "github.com/df-mc/dragonfly/server/player/skin" "github.com/df-mc/dragonfly/server/world" @@ -22,6 +23,7 @@ type Controllable interface { world.Entity item.User form.Submitter + dialogue.Submitter cmd.Source chat.Subscriber diff --git a/server/session/entity_metadata.go b/server/session/entity_metadata.go index 2e1922d83..111f3cbff 100644 --- a/server/session/entity_metadata.go +++ b/server/session/entity_metadata.go @@ -28,6 +28,9 @@ func (s *Session) parseEntityMetadata(e world.Entity) entityMetadata { m.setFlag(dataKeyFlags, dataFlagAffectedByGravity) m.setFlag(dataKeyFlags, dataFlagCanClimb) + if npc, ok := e.(world.NPC); ok && npc.NPC() { + m[dataKeyHasNpcComponent] = boolByte(npc.NPC()) + } if sn, ok := e.(sneaker); ok && sn.Sneaking() { m.setFlag(dataKeyFlags, dataFlagSneaking) } @@ -175,6 +178,7 @@ const ( dataKeyCustomDisplay = 18 dataKeyPotionAuxValue = 36 dataKeyScale = 38 + dataKeyHasNpcComponent = 39 dataKeyMaxAir = 42 dataKeyBoundingBoxWidth = 53 dataKeyBoundingBoxHeight = 54 diff --git a/server/session/handle_npc_request.go b/server/session/handle_npc_request.go new file mode 100644 index 000000000..6bdfa26d8 --- /dev/null +++ b/server/session/handle_npc_request.go @@ -0,0 +1,46 @@ +package session + +import ( + "fmt" + "github.com/df-mc/dragonfly/server/player/dialogue" + "github.com/sandertv/gophertunnel/minecraft/protocol/packet" + "sync" +) + +// NpcRequestHandler handles the NpcRequest packet. +type NpcRequestHandler struct { + mu sync.Mutex + dialogues map[string]dialogue.Dialogue +} + +// Handle ... +func (h *NpcRequestHandler) Handle(p packet.Packet, s *Session) error { + pk := p.(*packet.NPCRequest) + h.mu.Lock() + d, ok := h.dialogues[s.c.XUID()] + h.mu.Unlock() + if !ok { + return fmt.Errorf("no dialogue menu for player with xuid %v", s.c.XUID()) + } + m := d.Menu() + switch pk.RequestType { + case packet.NPCRequestActionExecuteAction: + buttons := m.Buttons() + index := int(pk.ActionType) + if index >= len(buttons) { + return fmt.Errorf("error submitting dialogue, button index points to inexistent button: %v (only %v buttons present)", index, len(buttons)) + } + d.Submit(s.Controllable(), buttons[index]) + // We close the dialogue because if we don't close it here and the api implementor forgets to close it the + // client permanently stuck in the dialogue UI being unable to close it or submit a button. + s.Controllable().CloseDialogue(d) + case packet.NPCRequestActionExecuteClosingCommands: + if c, ok := d.(dialogue.Closer); ok { + c.Close(s.Controllable()) + } + h.mu.Lock() + delete(h.dialogues, s.c.XUID()) + h.mu.Unlock() + } + return nil +} diff --git a/server/session/player.go b/server/session/player.go index 2fa4ed044..69e35f852 100644 --- a/server/session/player.go +++ b/server/session/player.go @@ -12,6 +12,7 @@ import ( "github.com/df-mc/dragonfly/server/item/creative" "github.com/df-mc/dragonfly/server/item/inventory" "github.com/df-mc/dragonfly/server/item/recipe" + "github.com/df-mc/dragonfly/server/player/dialogue" "github.com/df-mc/dragonfly/server/player/form" "github.com/df-mc/dragonfly/server/player/skin" "github.com/df-mc/dragonfly/server/world" @@ -328,6 +329,57 @@ func (s *Session) SendForm(f form.Form) { }) } +// SendDialogue shows a npc dialogue to the client of the connection. The Submit method of the dialogue is called when +// the client clicks a button or closes the menu. +func (s *Session) SendDialogue(d dialogue.Dialogue) { + h := s.handlers[packet.IDNPCRequest].(*NpcRequestHandler) + + m := d.Menu() + h.mu.Lock() + h.dialogues[s.c.XUID()] = d + h.mu.Unlock() + + s.entityMutex.Lock() + RID := s.entityRuntimeIDs[m.NPC()] + s.entityMutex.Unlock() + + aj, _ := json.Marshal(m) + s.writePacket(&packet.NPCDialogue{ + EntityUniqueID: RID, + ActionType: packet.NPCDialogueActionOpen, + Dialogue: m.Body(), + SceneName: "default", + NPCName: m.Title(), + ActionJSON: string(aj), + }) +} + +// CloseDialogue forcefully closes the users current dialogue. The Close method of dialogue.Closer is called when the +// form closes on the client. +func (s *Session) CloseDialogue(d dialogue.Dialogue) { + h := s.handlers[packet.IDNPCRequest].(*NpcRequestHandler) + + m := d.Menu() + s.entityMutex.Lock() + RID := s.entityRuntimeIDs[m.NPC()] + s.entityMutex.Unlock() + + h.mu.Lock() + _, ok := h.dialogues[s.c.XUID()] + h.mu.Unlock() + if !ok { + return + } + s.writePacket(&packet.NPCDialogue{ + EntityUniqueID: RID, + ActionType: packet.NPCDialogueActionClose, + Dialogue: m.Body(), + SceneName: "default", + NPCName: m.Title(), + ActionJSON: "", + }) +} + // Transfer transfers the player to a server with the IP and port passed. func (s *Session) Transfer(ip net.IP, port int) { s.writePacket(&packet.Transfer{ diff --git a/server/session/session.go b/server/session/session.go index 18fb2ab06..110bec6a1 100644 --- a/server/session/session.go +++ b/server/session/session.go @@ -12,6 +12,7 @@ import ( "github.com/df-mc/dragonfly/server/item/inventory" "github.com/df-mc/dragonfly/server/item/recipe" "github.com/df-mc/dragonfly/server/player/chat" + "github.com/df-mc/dragonfly/server/player/dialogue" "github.com/df-mc/dragonfly/server/player/form" "github.com/df-mc/dragonfly/server/world" "github.com/go-gl/mathgl/mgl64" @@ -446,6 +447,7 @@ func (s *Session) registerHandlers() { packet.IDMobEquipment: &MobEquipmentHandler{}, packet.IDModalFormResponse: &ModalFormResponseHandler{forms: make(map[uint32]form.Form)}, packet.IDMovePlayer: nil, + packet.IDNPCRequest: &NpcRequestHandler{dialogues: make(map[string]dialogue.Dialogue)}, packet.IDPlayerAction: &PlayerActionHandler{}, packet.IDPlayerAuthInput: &PlayerAuthInputHandler{}, packet.IDPlayerSkin: &PlayerSkinHandler{}, diff --git a/server/world/entity.go b/server/world/entity.go index c8bfd25de..938633fbf 100644 --- a/server/world/entity.go +++ b/server/world/entity.go @@ -33,6 +33,13 @@ type Entity interface { World() *World } +// NPC represents an entity can be seen within Npc Dialogues. Only entities that implement NPC can be used to create +// dialogue forms. +type NPC interface { + Entity + NPC() bool +} + // TickerEntity represents an entity that has a Tick method which should be called every time the entity is // ticked every 20th of a second. type TickerEntity interface { From 12a796c83e94c8158cacd58fc0a6babdd30ce646 Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:15:00 -0500 Subject: [PATCH 2/9] Update server/player/player.go Co-authored-by: Flonja <20887403+Flonja@users.noreply.github.com> --- server/player/player.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/player/player.go b/server/player/player.go index f87e2da91..b1f6d9bac 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -398,7 +398,7 @@ func (p *Player) SendDialogue(d dialogue.Dialogue) { p.session().SendDialogue(d) } -// CloseDialogue closes any dialogue that may be open to a user. Note that when this method is closed, if the dialogue +// CloseDialogue closes any dialogue that may be open to a user. Note that when this dialogue is closed, if the dialogue // implements dialogue.Closer the Close method will still execute. func (p *Player) CloseDialogue(d dialogue.Dialogue) { p.session().CloseDialogue(d) From b279b5a0b8886777725c9a61944cec576742249f Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:15:10 -0500 Subject: [PATCH 3/9] Update server/player/dialogue/menu.go Co-authored-by: Flonja <20887403+Flonja@users.noreply.github.com> --- server/player/dialogue/menu.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/player/dialogue/menu.go b/server/player/dialogue/menu.go index e7edb0985..142175d5e 100644 --- a/server/player/dialogue/menu.go +++ b/server/player/dialogue/menu.go @@ -30,7 +30,7 @@ func NewMenu(npc world.NPC, title ...any) Menu { // pass the threshold of 6, it will return an empty Menu and an error. func (m Menu) WithButtons(buttons ...Button) (Menu, error) { if len(m.buttons)+len(buttons) > 6 { - return Menu{}, fmt.Errorf("menu has %v buttons, an addition of %v will pass the 6 buttons threashold", len(m.buttons), len(buttons)) + return Menu{}, fmt.Errorf("menu has %v buttons, an addition of %v will pass the 6 buttons threshold", len(m.buttons), len(buttons)) } m.buttons = append(m.buttons, buttons...) return m, nil From 6885aba61119428aa3f1091ff98bfe47e7b222e4 Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:20:40 -0500 Subject: [PATCH 4/9] removed dangling documentation --- server/player/dialogue/menu.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/server/player/dialogue/menu.go b/server/player/dialogue/menu.go index 142175d5e..826823bc4 100644 --- a/server/player/dialogue/menu.go +++ b/server/player/dialogue/menu.go @@ -11,10 +11,8 @@ import ( // 6. type Menu struct { title, body string - // action represents the action this menu is executing. This value is either packet.NPCDialogueActionOpen or - // packet.NPCDialogueActionClose. - npc world.NPC - buttons []Button + npc world.NPC + buttons []Button } // NewMenu creates a new Menu with the Dialogue passed. Title is formatted with accordance to the rules of fmt.Sprintln. From f9796a704481ed5bd8f9368d1b2c4e9a9536b01b Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:24:45 -0500 Subject: [PATCH 5/9] documentation confusion --- server/player/player.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/player/player.go b/server/player/player.go index b1f6d9bac..15b7d25a3 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -398,7 +398,7 @@ func (p *Player) SendDialogue(d dialogue.Dialogue) { p.session().SendDialogue(d) } -// CloseDialogue closes any dialogue that may be open to a user. Note that when this dialogue is closed, if the dialogue +// CloseDialogue closes any dialogue that may be open to a user. Note that when this method is called, if the dialogue // implements dialogue.Closer the Close method will still execute. func (p *Player) CloseDialogue(d dialogue.Dialogue) { p.session().CloseDialogue(d) From e8a89b3a42eb93dd0d9bfde0e45d4fcd2bc43086 Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:29:57 -0500 Subject: [PATCH 6/9] removal of nonessential documentation as well as ill exposed Unknown Button type --- server/player/dialogue/button.go | 2 +- server/player/dialogue/button_type.go | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/server/player/dialogue/button.go b/server/player/dialogue/button.go index 48a20329b..db51140f0 100644 --- a/server/player/dialogue/button.go +++ b/server/player/dialogue/button.go @@ -6,7 +6,7 @@ import "encoding/json" type Button struct { // Name is the name of the button and is displayed to the user. Name string - // Activation is the specific method of activation required by the button. CLICK = 0, CLOSE = 1, ENTER = 2. + // Activation is the specific method of activation required by the button. Activation ActivationType // Type is the type of button / action it takes. Type ButtonType diff --git a/server/player/dialogue/button_type.go b/server/player/dialogue/button_type.go index fcd5469bb..1b8005e6a 100644 --- a/server/player/dialogue/button_type.go +++ b/server/player/dialogue/button_type.go @@ -41,8 +41,3 @@ func (b button) Uint8() uint8 { func CommandButton() ButtonType { return ButtonType{1} } - -// UnknownButton has unknown behaviour as of the moment. -func UnknownButton() ButtonType { - return ButtonType{2} -} From 2bc43c90e49d385e8c7d5a547d64791dbba96a7b Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:35:06 -0500 Subject: [PATCH 7/9] removal of excessive button enum as the only one used is Command button --- server/player/dialogue/button.go | 8 +++----- server/player/dialogue/button_type.go | 16 ---------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/server/player/dialogue/button.go b/server/player/dialogue/button.go index db51140f0..9b35b7bf6 100644 --- a/server/player/dialogue/button.go +++ b/server/player/dialogue/button.go @@ -8,13 +8,11 @@ type Button struct { Name string // Activation is the specific method of activation required by the button. Activation ActivationType - // Type is the type of button / action it takes. - Type ButtonType } // NewButton returns a new Button with the name, activationType, and buttonType passed. -func NewButton(name string, activationType ActivationType, buttonType ButtonType) Button { - return Button{Name: name, Activation: activationType, Type: buttonType} +func NewButton(name string, activationType ActivationType) Button { + return Button{Name: name, Activation: activationType} } // MarshalJSON ... @@ -23,7 +21,7 @@ func (b Button) MarshalJSON() ([]byte, error) { "button_name": b.Name, "text": "", // Buttons don't work if this value isn't sent. "mode": b.Activation.Uint8(), - "type": b.Type.Uint8(), + "type": 1, } return json.Marshal(data) } diff --git a/server/player/dialogue/button_type.go b/server/player/dialogue/button_type.go index 1b8005e6a..87e0c09f4 100644 --- a/server/player/dialogue/button_type.go +++ b/server/player/dialogue/button_type.go @@ -25,19 +25,3 @@ func ActivationClose() ActivationType { func ActivationEnter() ActivationType { return ActivationType{2} } - -type button uint8 - -// ButtonType represents the type of Button. URL, COMMAND, and UNKNOWN are all the button types. -type ButtonType struct { - button -} - -func (b button) Uint8() uint8 { - return uint8(b) -} - -// CommandButton is a button meant to execute a command. -func CommandButton() ButtonType { - return ButtonType{1} -} From 97cc347d121f103b0d369388edcbf5c5f05bfecb Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 19:37:41 -0500 Subject: [PATCH 8/9] rename button_type to activation_type.go and do some string formatting for sebs eyes --- server/player/dialogue/{button_type.go => activation_type.go} | 0 server/player/dialogue/menu.go | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) rename server/player/dialogue/{button_type.go => activation_type.go} (100%) diff --git a/server/player/dialogue/button_type.go b/server/player/dialogue/activation_type.go similarity index 100% rename from server/player/dialogue/button_type.go rename to server/player/dialogue/activation_type.go diff --git a/server/player/dialogue/menu.go b/server/player/dialogue/menu.go index 826823bc4..e5fa3a428 100644 --- a/server/player/dialogue/menu.go +++ b/server/player/dialogue/menu.go @@ -7,8 +7,7 @@ import ( "strings" ) -// Menu represents a npc dialogue. It contains a title, body, entity, and a number of buttons no more than -// 6. +// Menu represents a npc dialogue. It contains a title, body, entity, and a number of buttons no more than 6. type Menu struct { title, body string npc world.NPC From ad7ba51366d310255979c48018da5aa0f1d66e2d Mon Sep 17 00:00:00 2001 From: Abi <82734267+abimek@users.noreply.github.com> Date: Sun, 5 Feb 2023 20:07:25 -0500 Subject: [PATCH 9/9] removed map for handle_npc_request and other minor changes --- server/session/handle_npc_request.go | 14 ++++---------- server/session/player.go | 21 ++++----------------- server/session/session.go | 3 +-- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/server/session/handle_npc_request.go b/server/session/handle_npc_request.go index 6bdfa26d8..6d34c4e6e 100644 --- a/server/session/handle_npc_request.go +++ b/server/session/handle_npc_request.go @@ -4,24 +4,20 @@ import ( "fmt" "github.com/df-mc/dragonfly/server/player/dialogue" "github.com/sandertv/gophertunnel/minecraft/protocol/packet" - "sync" ) // NpcRequestHandler handles the NpcRequest packet. type NpcRequestHandler struct { - mu sync.Mutex - dialogues map[string]dialogue.Dialogue + dialogues dialogue.Dialogue } // Handle ... func (h *NpcRequestHandler) Handle(p packet.Packet, s *Session) error { pk := p.(*packet.NPCRequest) - h.mu.Lock() - d, ok := h.dialogues[s.c.XUID()] - h.mu.Unlock() - if !ok { + if h.dialogues == nil { return fmt.Errorf("no dialogue menu for player with xuid %v", s.c.XUID()) } + d := h.dialogues m := d.Menu() switch pk.RequestType { case packet.NPCRequestActionExecuteAction: @@ -38,9 +34,7 @@ func (h *NpcRequestHandler) Handle(p packet.Packet, s *Session) error { if c, ok := d.(dialogue.Closer); ok { c.Close(s.Controllable()) } - h.mu.Lock() - delete(h.dialogues, s.c.XUID()) - h.mu.Unlock() + h.dialogues = nil } return nil } diff --git a/server/session/player.go b/server/session/player.go index 69e35f852..bbe08fbb9 100644 --- a/server/session/player.go +++ b/server/session/player.go @@ -335,13 +335,9 @@ func (s *Session) SendDialogue(d dialogue.Dialogue) { h := s.handlers[packet.IDNPCRequest].(*NpcRequestHandler) m := d.Menu() - h.mu.Lock() - h.dialogues[s.c.XUID()] = d - h.mu.Unlock() + h.dialogues = d - s.entityMutex.Lock() - RID := s.entityRuntimeIDs[m.NPC()] - s.entityMutex.Unlock() + RID := s.entityRuntimeID(m.NPC()) aj, _ := json.Marshal(m) s.writePacket(&packet.NPCDialogue{ @@ -360,23 +356,14 @@ func (s *Session) CloseDialogue(d dialogue.Dialogue) { h := s.handlers[packet.IDNPCRequest].(*NpcRequestHandler) m := d.Menu() - s.entityMutex.Lock() - RID := s.entityRuntimeIDs[m.NPC()] - s.entityMutex.Unlock() + RID := s.entityRuntimeID(m.NPC()) - h.mu.Lock() - _, ok := h.dialogues[s.c.XUID()] - h.mu.Unlock() - if !ok { + if h.dialogues == nil { return } s.writePacket(&packet.NPCDialogue{ EntityUniqueID: RID, ActionType: packet.NPCDialogueActionClose, - Dialogue: m.Body(), - SceneName: "default", - NPCName: m.Title(), - ActionJSON: "", }) } diff --git a/server/session/session.go b/server/session/session.go index 110bec6a1..57e736423 100644 --- a/server/session/session.go +++ b/server/session/session.go @@ -12,7 +12,6 @@ import ( "github.com/df-mc/dragonfly/server/item/inventory" "github.com/df-mc/dragonfly/server/item/recipe" "github.com/df-mc/dragonfly/server/player/chat" - "github.com/df-mc/dragonfly/server/player/dialogue" "github.com/df-mc/dragonfly/server/player/form" "github.com/df-mc/dragonfly/server/world" "github.com/go-gl/mathgl/mgl64" @@ -447,7 +446,7 @@ func (s *Session) registerHandlers() { packet.IDMobEquipment: &MobEquipmentHandler{}, packet.IDModalFormResponse: &ModalFormResponseHandler{forms: make(map[uint32]form.Form)}, packet.IDMovePlayer: nil, - packet.IDNPCRequest: &NpcRequestHandler{dialogues: make(map[string]dialogue.Dialogue)}, + packet.IDNPCRequest: &NpcRequestHandler{dialogues: nil}, packet.IDPlayerAction: &PlayerActionHandler{}, packet.IDPlayerAuthInput: &PlayerAuthInputHandler{}, packet.IDPlayerSkin: &PlayerSkinHandler{},