5 "github.com/anon55555/mt"
6 "github.com/dragonfireclient/hydra-dragonfire/tolua"
7 "github.com/yuin/gopher-lua"
12 type clientState uint8
15 csNew clientState = iota
20 type Component interface {
21 create(client *Client, l *lua.LState)
34 subscribed map[string]struct{}
35 components map[string]Component
36 userdata *lua.LUserData
39 var clientFuncs = map[string]lua.LGFunction{
40 "address": l_client_address,
41 "state": l_client_state,
42 "connect": l_client_connect,
43 "poll": l_client_poll,
44 "disconnect": l_client_disconnect,
45 "enable": l_client_enable,
46 "subscribe": l_client_subscribe,
47 "unsubscribe": l_client_unsubscribe,
48 "wildcard": l_client_wildcard,
51 func getClient(l *lua.LState) *Client {
52 return l.CheckUserData(1).Value.(*Client)
55 func getClients(l *lua.LState) []*Client {
56 tbl := l.CheckTable(1)
59 clients := make([]*Client, 0, n)
60 for i := 1; i <= n; i++ {
61 clients = append(clients, l.RawGetInt(tbl, i).(*lua.LUserData).Value.(*Client))
67 func getStrings(l *lua.LState) []string {
70 strs := make([]string, 0, n-1)
71 for i := 2; i <= n; i++ {
72 strs = append(strs, l.CheckString(i))
78 func (client *Client) disconnect() {
80 defer client.mu.Unlock()
82 if client.state == csConnected {
87 func l_client(l *lua.LState) int {
90 client.address = l.CheckString(1)
92 client.wildcard = false
93 client.subscribed = map[string]struct{}{}
94 client.components = map[string]Component{}
95 client.userdata = l.NewUserData()
96 client.userdata.Value = client
97 l.SetMetatable(client.userdata, l.GetTypeMetatable("hydra.client"))
99 l.Push(client.userdata)
103 func l_client_index(l *lua.LState) int {
104 client := getClient(l)
105 key := l.CheckString(2)
107 if fun, exists := clientFuncs[key]; exists {
108 l.Push(l.NewFunction(fun))
109 } else if component, exists := client.components[key]; exists {
110 l.Push(component.tolua())
118 func l_client_address(l *lua.LState) int {
119 client := getClient(l)
120 l.Push(lua.LString(client.address))
124 func l_client_state(l *lua.LState) int {
125 client := getClient(l)
126 switch client.state {
128 l.Push(lua.LString("new"))
130 l.Push(lua.LString("connected"))
132 l.Push(lua.LString("disconnected"))
137 func l_client_connect(l *lua.LState) int {
138 client := getClient(l)
140 if client.state != csNew {
141 panic("can't reconnect")
144 addr, err := net.ResolveUDPAddr("udp", client.address)
149 conn, err := net.DialUDP("udp", nil, addr)
154 client.state = csConnected
155 client.conn = mt.Connect(conn)
156 client.queue = make(chan *mt.Pkt, 1024)
160 pkt, err := client.conn.Recv()
165 for _, component := range client.components {
166 component.process(&pkt)
169 if _, exists := client.subscribed[string(tolua.PktType(&pkt))]; exists || client.wildcard {
174 } else if errors.Is(err, net.ErrClosed) {
182 for _, component := range client.components {
190 func l_client_poll(l *lua.LState) int {
191 client := getClient(l)
192 _, pkt, timeout := doPoll(l, []*Client{client})
194 l.Push(tolua.Pkt(l, pkt))
195 l.Push(lua.LBool(timeout))
199 func l_client_disconnect(l *lua.LState) int {
200 client := getClient(l)
205 func l_client_enable(l *lua.LState) int {
206 client := getClient(l)
208 defer client.mu.Unlock()
210 for _, compname := range getStrings(l) {
211 if component, exists := client.components[compname]; !exists {
216 panic("invalid component: " + compname)
219 client.components[compname] = component
220 component.create(client, l)
227 func l_client_subscribe(l *lua.LState) int {
228 client := getClient(l)
230 defer client.mu.Unlock()
232 for _, pkt := range getStrings(l) {
233 client.subscribed[pkt] = struct{}{}
239 func l_client_unsubscribe(l *lua.LState) int {
240 client := getClient(l)
242 defer client.mu.Unlock()
244 for _, pkt := range getStrings(l) {
245 delete(client.subscribed, pkt)
251 func l_client_wildcard(l *lua.LState) int {
252 client := getClient(l)
253 client.wildcard = l.ToBool(2)
259 func l_client_send(l *lua.LState) int {
260 client := getClient(l)
261 pkt := fromlua.Pkt(l.CheckTable(2))
264 defer client.mu.Unlock()
266 if client.state == csConnected {
267 client.conn.Send(pkt)