func RegisterServerType(typeName string, srv ServerType) {
	if _, ok := serverTypes[typeName]; ok {
		panic("server type already registered")
	}
	serverTypes[typeName] = srv
}
RegisterServerType registers a server type srv by its
name, typeName.
package casket
import (
	"fmt"
	"log"
	"net"
	"sort"
	"sync"
	"github.com/tmpim/casket/casketfile"
)
var (
	serverTypes = make(map[string]ServerType)
	plugins = make(map[string]map[string]Plugin)
	eventHooks = &sync.Map{}
	parsingCallbacks = make(map[string]map[string][]ParsingCallback)
	casketfileLoaders []casketfileLoader
)
func DescribePlugins() string {
	pl := ListPlugins()
	str := "Server types:\n"
	for _, name := range pl["server_types"] {
		str += "  " + name + "\n"
	}
	str += "\nCasketfile loaders:\n"
	for _, name := range pl["casketfile_loaders"] {
		str += "  " + name + "\n"
	}
	if len(pl["event_hooks"]) > 0 {
		str += "\nEvent hook plugins:\n"
		for _, name := range pl["event_hooks"] {
			str += "  hook." + name + "\n"
		}
	}
	if len(pl["clustering"]) > 0 {
		str += "\nClustering plugins:\n"
		for _, name := range pl["clustering"] {
			str += "  " + name + "\n"
		}
	}
	str += "\nOther plugins:\n"
	for _, name := range pl["others"] {
		str += "  " + name + "\n"
	}
	return str
}
func ListPlugins() map[string][]string {
	p := make(map[string][]string)
	for name := range serverTypes {
		p["server_types"] = append(p["server_types"], name)
	}
	for _, loader := range casketfileLoaders {
		p["casketfile_loaders"] = append(p["casketfile_loaders"], loader.name)
	}
	if defaultCasketfileLoader.name != "" {
		p["casketfile_loaders"] = append(p["casketfile_loaders"], defaultCasketfileLoader.name)
	}
	eventHooks.Range(func(k, _ interface{}) bool {
		p["event_hooks"] = append(p["event_hooks"], k.(string))
		return true
	})
	var others []string
	for stype, stypePlugins := range plugins {
		for name := range stypePlugins {
			var s string
			if stype != "" {
				s = stype + "."
			}
			s += name
			others = append(others, s)
		}
	}
	sort.Strings(others)
	for _, name := range others {
		p["others"] = append(p["others"], name)
	}
	return p
}
func ValidDirectives(serverType string) []string {
	stype, err := getServerType(serverType)
	if err != nil {
		return nil
	}
	return stype.Directives()
}
type ServerListener struct {
	server   Server
	listener net.Listener
	packet   net.PacketConn
}
func (s ServerListener) LocalAddr() net.Addr {
	if s.packet == nil {
		return nil
	}
	return s.packet.LocalAddr()
}
func (s ServerListener) Addr() net.Addr {
	if s.listener == nil {
		return nil
	}
	return s.listener.Addr()
}
type Context interface {
	InspectServerBlocks(string, []casketfile.ServerBlock) ([]casketfile.ServerBlock, error)
	MakeServers() ([]Server, error)
}