aboutsummaryrefslogtreecommitdiff
path: root/plugin_formspec.go
blob: 780310882bff6b2e8250377eaa5f3505d3b7d12e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package proxy

import (
	"strings"
	"sync"

	"github.com/HimbeerserverDE/mt"
)

var (
	onPlayerReceiveFields     map[string][]func(*ClientConn, []mt.Field)
	onPlayerReceiveFieldsMu   sync.Mutex
	onPlayerReceiveFieldsOnce sync.Once
)

// ShowFormspec opens a formspec on the client.
// The form name should follow the standard minetest naming convention,
// i.e. "pluginname:formname".
// If formname is empty, it reshows the inventory formspec
// without updating it for future opens.
// If formspec is empty, the formspec is closed.
// If formname is empty at the same time, any formspec is closed
// regardless of its name.
func (cc *ClientConn) ShowFormspec(formname string, formspec string) {
	cc.SendCmd(&mt.ToCltShowFormspec{
		Formspec: cc.FormspecPrepend + formspec,
		Formname: formname,
	})
}

// FormspecEscape escapes characters that cannot be used in formspecs.
func FormspecEscape(formspec string) string {
	formspec = strings.ReplaceAll(formspec, "\\", "\\\\")
	formspec = strings.ReplaceAll(formspec, "[", "\\[")
	formspec = strings.ReplaceAll(formspec, "]", "\\]")
	formspec = strings.ReplaceAll(formspec, ";", "\\;")
	formspec = strings.ReplaceAll(formspec, ",", "\\,")
	formspec = strings.ReplaceAll(formspec, "$", "\\$")
	return formspec
}

// RegisterOnPlayerReceiveFields registers a callback that is called
// when a client submits a specific formspec.
// Events triggering this callback include a button being pressed,
// Enter being pressed while a text field is focused,
// a checkbox being toggled, an item being selected in a dropdown list,
// selecting a new tab, changing the selection in a textlist or table,
// selecting an entry in a textlist or table, a scrollbar being moved
// or the form actively being closed by the player.
func RegisterOnPlayerReceiveFields(formname string, handler func(*ClientConn, []mt.Field)) {
	initOnPlayerReceiveFields()

	onPlayerReceiveFieldsMu.Lock()
	defer onPlayerReceiveFieldsMu.Unlock()

	onPlayerReceiveFields[formname] = append(onPlayerReceiveFields[formname], handler)
}

func handleOnPlayerReceiveFields(cc *ClientConn, cmd *mt.ToSrvInvFields) bool {
	onPlayerReceiveFieldsMu.Lock()
	defer onPlayerReceiveFieldsMu.Unlock()

	handlers, ok := onPlayerReceiveFields[cmd.Formname]
	if !ok || len(handlers) == 0 {
		return false
	}

	for _, handler := range handlers {
		handler(cc, cmd.Fields)
	}

	return true
}

func initOnPlayerReceiveFields() {
	onPlayerReceiveFieldsOnce.Do(func() {
		onPlayerReceiveFieldsMu.Lock()
		defer onPlayerReceiveFieldsMu.Unlock()

		onPlayerReceiveFields = make(map[string][]func(*ClientConn, []mt.Field))
	})
}