commit
ee77906613
4
chat.go
4
chat.go
|
@ -9,6 +9,10 @@ import (
|
||||||
"github.com/anon55555/mt"
|
"github.com/anon55555/mt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ChatCmdTimeout is the time needed until a user is warned
|
||||||
|
// about a chat command that's taking long to execute.
|
||||||
|
var ChatCmdTimeout = 10 * time.Second
|
||||||
|
|
||||||
// SendChatMsg sends a chat message to the ClientConn.
|
// SendChatMsg sends a chat message to the ClientConn.
|
||||||
func (cc *ClientConn) SendChatMsg(msg ...string) {
|
func (cc *ClientConn) SendChatMsg(msg ...string) {
|
||||||
cc.SendCmd(&mt.ToCltChatMsg{
|
cc.SendCmd(&mt.ToCltChatMsg{
|
||||||
|
|
96
config.go
96
config.go
|
@ -2,6 +2,7 @@ package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -25,7 +26,10 @@ var loadConfigOnce sync.Once
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Name string
|
Name string
|
||||||
Addr string
|
Addr string
|
||||||
|
MediaPool string
|
||||||
Fallbacks []string
|
Fallbacks []string
|
||||||
|
|
||||||
|
dynamic bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Config contains information from the configuration file
|
// A Config contains information from the configuration file
|
||||||
|
@ -87,34 +91,78 @@ func Conf() Config {
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddServer appends a server to the list of configured servers.
|
// PoolServers returns all media pools and their member servers.
|
||||||
func AddServer(server Server) bool {
|
func PoolServers() map[string][]Server {
|
||||||
|
var srvs = make(map[string][]Server)
|
||||||
|
conf := Conf()
|
||||||
|
|
||||||
|
// map all to.. map of slices
|
||||||
|
for _, srv := range conf.Servers {
|
||||||
|
srvs[srv.MediaPool] = append(srvs[srv.MediaPool], srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return srvs
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServer dynamically configures a new Server at runtime.
|
||||||
|
// Servers added in this way are ephemeral and will be lost
|
||||||
|
// when the proxy shuts down.
|
||||||
|
// The server must be part of a media pool with at least one
|
||||||
|
// other member. At least one of the other members always
|
||||||
|
// needs to be reachable.
|
||||||
|
func AddServer(s Server) bool {
|
||||||
configMu.Lock()
|
configMu.Lock()
|
||||||
defer configMu.Unlock()
|
defer configMu.Unlock()
|
||||||
|
|
||||||
|
s.dynamic = true
|
||||||
|
|
||||||
for _, srv := range config.Servers {
|
for _, srv := range config.Servers {
|
||||||
if srv.Name == server.Name {
|
if srv.Name == s.Name {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Servers = append(config.Servers, server)
|
var poolMembers bool
|
||||||
|
for _, srv := range config.Servers {
|
||||||
|
if srv.MediaPool == s.MediaPool {
|
||||||
|
poolMembers = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !poolMembers {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Servers = append(config.Servers, s)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelServer removes a server based on name.
|
// RmServer deletes a Server from the Config at runtime.
|
||||||
func DelServer(name string) bool {
|
// Only servers added using AddServer can be deleted at runtime.
|
||||||
|
// Returns true on success or if the server doesn't exist.
|
||||||
|
func RmServer(name string) bool {
|
||||||
configMu.Lock()
|
configMu.Lock()
|
||||||
defer configMu.Unlock()
|
defer configMu.Unlock()
|
||||||
|
|
||||||
for i, srv := range config.Servers {
|
for i, srv := range config.Servers {
|
||||||
if srv.Name == name {
|
if srv.Name == name {
|
||||||
|
if srv.dynamic {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't remove server if players are connected to it
|
||||||
|
for cc := range Clts() {
|
||||||
|
if cc.ServerName() == name {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.Servers = append(config.Servers[:i], config.Servers[1+i:]...)
|
config.Servers = append(config.Servers[:i], config.Servers[1+i:]...)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FallbackServers returns a slice of server names that
|
// FallbackServers returns a slice of server names that
|
||||||
|
@ -185,6 +233,40 @@ func LoadConfig() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dynamic servers shouldn't be deleted silently.
|
||||||
|
DynLoop:
|
||||||
|
for _, srv := range oldConf.Servers {
|
||||||
|
if srv.dynamic {
|
||||||
|
config.Servers = append(config.Servers, srv)
|
||||||
|
} else {
|
||||||
|
for _, s := range config.Servers {
|
||||||
|
if srv.Name == s.Name {
|
||||||
|
continue DynLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for cc := range Clts() {
|
||||||
|
if cc.ServerName() == srv.Name {
|
||||||
|
config = oldConf
|
||||||
|
return fmt.Errorf("can't delete server %s with players", srv.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, srv := range config.Servers {
|
||||||
|
for _, s := range config.Servers {
|
||||||
|
if srv.Name == s.Name {
|
||||||
|
config = oldConf
|
||||||
|
return fmt.Errorf("duplicate server %s", s.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if srv.MediaPool == "" {
|
||||||
|
config.Servers[i].MediaPool = srv.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Print("load config")
|
log.Print("load config")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
27
connect.go
27
connect.go
|
@ -17,13 +17,21 @@ func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
|
||||||
}
|
}
|
||||||
cc.mu.RUnlock()
|
cc.mu.RUnlock()
|
||||||
|
|
||||||
prefix := fmt.Sprintf("[server %s] ", name)
|
var mediaPool string
|
||||||
|
for _, srv := range Conf().Servers {
|
||||||
|
if srv.Name == name {
|
||||||
|
mediaPool = srv.MediaPool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logPrefix := fmt.Sprintf("[server %s] ", name)
|
||||||
sc := &ServerConn{
|
sc := &ServerConn{
|
||||||
Peer: mt.Connect(conn),
|
Peer: mt.Connect(conn),
|
||||||
logger: log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix),
|
logger: log.New(logWriter, logPrefix, log.LstdFlags|log.Lmsgprefix),
|
||||||
initCh: make(chan struct{}),
|
initCh: make(chan struct{}),
|
||||||
clt: cc,
|
clt: cc,
|
||||||
name: name,
|
name: name,
|
||||||
|
mediaPool: mediaPool,
|
||||||
aos: make(map[mt.AOID]struct{}),
|
aos: make(map[mt.AOID]struct{}),
|
||||||
particleSpawners: make(map[mt.ParticleSpawnerID]struct{}),
|
particleSpawners: make(map[mt.ParticleSpawnerID]struct{}),
|
||||||
sounds: make(map[mt.SoundID]struct{}),
|
sounds: make(map[mt.SoundID]struct{}),
|
||||||
|
@ -40,14 +48,15 @@ func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectContent(conn net.Conn, name, userName string) (*contentConn, error) {
|
func connectContent(conn net.Conn, name, userName, mediaPool string) (*contentConn, error) {
|
||||||
prefix := fmt.Sprintf("[content %s] ", name)
|
logPrefix := fmt.Sprintf("[content %s] ", name)
|
||||||
cc := &contentConn{
|
cc := &contentConn{
|
||||||
Peer: mt.Connect(conn),
|
Peer: mt.Connect(conn),
|
||||||
logger: log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix),
|
logger: log.New(logWriter, logPrefix, log.LstdFlags|log.Lmsgprefix),
|
||||||
doneCh: make(chan struct{}),
|
doneCh: make(chan struct{}),
|
||||||
name: name,
|
name: name,
|
||||||
userName: userName,
|
userName: userName,
|
||||||
|
mediaPool: mediaPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cc.addDefaultTextures(); err != nil {
|
if err := cc.addDefaultTextures(); err != nil {
|
||||||
|
|
102
content.go
102
content.go
|
@ -45,6 +45,8 @@ type contentConn struct {
|
||||||
salt, srpA, a, srpK []byte
|
salt, srpA, a, srpK []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaPool string
|
||||||
|
|
||||||
itemDefs []mt.ItemDef
|
itemDefs []mt.ItemDef
|
||||||
aliases []struct{ Alias, Orig string }
|
aliases []struct{ Alias, Orig string }
|
||||||
|
|
||||||
|
@ -357,21 +359,21 @@ func muxItemDefs(conns []*contentConn) ([]mt.ItemDef, []struct{ Alias, Orig stri
|
||||||
def.Name = "hand"
|
def.Name = "hand"
|
||||||
}
|
}
|
||||||
|
|
||||||
prepend(cc.name, &def.Name)
|
prepend(cc.mediaPool, &def.Name)
|
||||||
prependTexture(cc.name, &def.InvImg)
|
prependTexture(cc.mediaPool, &def.InvImg)
|
||||||
prependTexture(cc.name, &def.WieldImg)
|
prependTexture(cc.mediaPool, &def.WieldImg)
|
||||||
prepend(cc.name, &def.PlacePredict)
|
prepend(cc.mediaPool, &def.PlacePredict)
|
||||||
prepend(cc.name, &def.PlaceSnd.Name)
|
prepend(cc.mediaPool, &def.PlaceSnd.Name)
|
||||||
prepend(cc.name, &def.PlaceFailSnd.Name)
|
prepend(cc.mediaPool, &def.PlaceFailSnd.Name)
|
||||||
prependTexture(cc.name, &def.Palette)
|
prependTexture(cc.mediaPool, &def.Palette)
|
||||||
prependTexture(cc.name, &def.InvOverlay)
|
prependTexture(cc.mediaPool, &def.InvOverlay)
|
||||||
prependTexture(cc.name, &def.WieldOverlay)
|
prependTexture(cc.mediaPool, &def.WieldOverlay)
|
||||||
itemDefs = append(itemDefs, def)
|
itemDefs = append(itemDefs, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, alias := range cc.aliases {
|
for _, alias := range cc.aliases {
|
||||||
prepend(cc.name, &alias.Alias)
|
prepend(cc.mediaPool, &alias.Alias)
|
||||||
prepend(cc.name, &alias.Orig)
|
prepend(cc.mediaPool, &alias.Orig)
|
||||||
|
|
||||||
aliases = append(aliases, struct{ Alias, Orig string }{
|
aliases = append(aliases, struct{ Alias, Orig string }{
|
||||||
Alias: alias.Alias,
|
Alias: alias.Alias,
|
||||||
|
@ -429,25 +431,25 @@ func muxNodeDefs(conns []*contentConn) (nodeDefs []mt.NodeDef, p0Map param0Map,
|
||||||
}
|
}
|
||||||
|
|
||||||
def.Param0 = param0
|
def.Param0 = param0
|
||||||
prepend(cc.name, &def.Name)
|
prepend(cc.mediaPool, &def.Name)
|
||||||
prepend(cc.name, &def.Mesh)
|
prepend(cc.mediaPool, &def.Mesh)
|
||||||
for i := range def.Tiles {
|
for i := range def.Tiles {
|
||||||
prependTexture(cc.name, &def.Tiles[i].Texture)
|
prependTexture(cc.mediaPool, &def.Tiles[i].Texture)
|
||||||
}
|
}
|
||||||
for i := range def.OverlayTiles {
|
for i := range def.OverlayTiles {
|
||||||
prependTexture(cc.name, &def.OverlayTiles[i].Texture)
|
prependTexture(cc.mediaPool, &def.OverlayTiles[i].Texture)
|
||||||
}
|
}
|
||||||
for i := range def.SpecialTiles {
|
for i := range def.SpecialTiles {
|
||||||
prependTexture(cc.name, &def.SpecialTiles[i].Texture)
|
prependTexture(cc.mediaPool, &def.SpecialTiles[i].Texture)
|
||||||
}
|
}
|
||||||
prependTexture(cc.name, &def.Palette)
|
prependTexture(cc.mediaPool, &def.Palette)
|
||||||
for k, v := range def.ConnectTo {
|
for k, v := range def.ConnectTo {
|
||||||
def.ConnectTo[k] = p0Map[cc.name][v]
|
def.ConnectTo[k] = p0Map[cc.name][v]
|
||||||
}
|
}
|
||||||
prepend(cc.name, &def.FootstepSnd.Name)
|
prepend(cc.mediaPool, &def.FootstepSnd.Name)
|
||||||
prepend(cc.name, &def.DiggingSnd.Name)
|
prepend(cc.mediaPool, &def.DiggingSnd.Name)
|
||||||
prepend(cc.name, &def.DugSnd.Name)
|
prepend(cc.mediaPool, &def.DugSnd.Name)
|
||||||
prepend(cc.name, &def.DigPredict)
|
prepend(cc.mediaPool, &def.DigPredict)
|
||||||
nodeDefs = append(nodeDefs, def)
|
nodeDefs = append(nodeDefs, def)
|
||||||
|
|
||||||
param0++
|
param0++
|
||||||
|
@ -466,7 +468,7 @@ func muxMedia(conns []*contentConn) []mediaFile {
|
||||||
for _, cc := range conns {
|
for _, cc := range conns {
|
||||||
<-cc.done()
|
<-cc.done()
|
||||||
for _, f := range cc.media {
|
for _, f := range cc.media {
|
||||||
prepend(cc.name, &f.name)
|
prepend(cc.mediaPool, &f.name)
|
||||||
media = append(media, f)
|
media = append(media, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,27 +496,37 @@ func muxRemotes(conns []*contentConn) []string {
|
||||||
|
|
||||||
func muxContent(userName string) (itemDefs []mt.ItemDef, aliases []struct{ Alias, Orig string }, nodeDefs []mt.NodeDef, p0Map param0Map, p0SrvMap param0SrvMap, media []mediaFile, remotes []string, err error) {
|
func muxContent(userName string) (itemDefs []mt.ItemDef, aliases []struct{ Alias, Orig string }, nodeDefs []mt.NodeDef, p0Map param0Map, p0SrvMap param0SrvMap, media []mediaFile, remotes []string, err error) {
|
||||||
var conns []*contentConn
|
var conns []*contentConn
|
||||||
for _, srv := range Conf().Servers {
|
|
||||||
|
PoolLoop:
|
||||||
|
for _, pool := range PoolServers() {
|
||||||
var addr *net.UDPAddr
|
var addr *net.UDPAddr
|
||||||
addr, err = net.ResolveUDPAddr("udp", srv.Addr)
|
|
||||||
if err != nil {
|
for _, srv := range pool {
|
||||||
return
|
addr, err = net.ResolveUDPAddr("udp", srv.Addr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn *net.UDPConn
|
||||||
|
conn, err = net.DialUDP("udp", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var cc *contentConn
|
||||||
|
cc, err = connectContent(conn, srv.Name, userName, srv.MediaPool)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
conns = append(conns, cc)
|
||||||
|
continue PoolLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
var conn *net.UDPConn
|
// There's a pool with no reachable servers.
|
||||||
conn, err = net.DialUDP("udp", nil, addr)
|
// We can't safely let clients join.
|
||||||
if err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var cc *contentConn
|
|
||||||
cc, err = connectContent(conn, srv.Name, userName)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer cc.Close()
|
|
||||||
|
|
||||||
conns = append(conns, cc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itemDefs, aliases = muxItemDefs(conns)
|
itemDefs, aliases = muxItemDefs(conns)
|
||||||
|
@ -594,7 +606,7 @@ func prependTexture(prep string, t *mt.Texture) {
|
||||||
func (sc *ServerConn) prependInv(inv mt.Inv) {
|
func (sc *ServerConn) prependInv(inv mt.Inv) {
|
||||||
for k, l := range inv {
|
for k, l := range inv {
|
||||||
for i := range l.Stacks {
|
for i := range l.Stacks {
|
||||||
prepend(sc.name, &inv[k].InvList.Stacks[i].Name)
|
prepend(sc.mediaPool, &inv[k].InvList.Stacks[i].Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,28 +615,28 @@ func (sc *ServerConn) prependHUD(t mt.HUDType, cmdIface mt.ToCltCmd) {
|
||||||
pa := func(cmd *mt.ToCltAddHUD) {
|
pa := func(cmd *mt.ToCltAddHUD) {
|
||||||
switch t {
|
switch t {
|
||||||
case mt.StatbarHUD:
|
case mt.StatbarHUD:
|
||||||
prepend(sc.name, &cmd.Text2)
|
prepend(sc.mediaPool, &cmd.Text2)
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgHUD:
|
case mt.ImgHUD:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgWaypointHUD:
|
case mt.ImgWaypointHUD:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgWaypointHUD + 1:
|
case mt.ImgWaypointHUD + 1:
|
||||||
prepend(sc.name, &cmd.Text)
|
prepend(sc.mediaPool, &cmd.Text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := func(cmd *mt.ToCltChangeHUD) {
|
pc := func(cmd *mt.ToCltChangeHUD) {
|
||||||
switch t {
|
switch t {
|
||||||
case mt.StatbarHUD:
|
case mt.StatbarHUD:
|
||||||
prepend(sc.name, &cmd.Text2)
|
prepend(sc.mediaPool, &cmd.Text2)
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgHUD:
|
case mt.ImgHUD:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgWaypointHUD:
|
case mt.ImgWaypointHUD:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mt.ImgWaypointHUD + 1:
|
case mt.ImgWaypointHUD + 1:
|
||||||
prepend(sc.name, &cmd.Text)
|
prepend(sc.mediaPool, &cmd.Text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,15 @@ Default: ""
|
||||||
Description: The network address and port of an internal server.
|
Description: The network address and port of an internal server.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> `Server.MediaPool`
|
||||||
|
```
|
||||||
|
Type: string
|
||||||
|
Default: Server.Name
|
||||||
|
Description: The media pool this server will be part of.
|
||||||
|
See [media_pools.md](https://github.com/HimbeerserverDE/mt-multiserver-proxy/blob/main/doc/media_pools.md)
|
||||||
|
for more information.
|
||||||
|
```
|
||||||
|
|
||||||
> `Server.Fallback`
|
> `Server.Fallback`
|
||||||
```
|
```
|
||||||
Type: []string
|
Type: []string
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Media Pools
|
||||||
|
|
||||||
|
All servers must be part of a media pool. By default the name of the server
|
||||||
|
is used.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
When the proxy sends any content-related packets to the client,
|
||||||
|
it prefixes any content names such as node names or media file names
|
||||||
|
with the media pool of the current server and an underscore.
|
||||||
|
The purpose of this is to allow servers to have different media
|
||||||
|
with the same name and to avoid some other multiplexing issues.
|
||||||
|
|
||||||
|
## When to use media pools?
|
||||||
|
In general, custom media pools are not required.
|
||||||
|
There are reasons to use them:
|
||||||
|
- reducing memory and storage usage on the client
|
||||||
|
- dynamically adding servers
|
||||||
|
|
||||||
|
### Reducing RAM and disk usage
|
||||||
|
The client has to store all media it receives in memory and in its cache.
|
||||||
|
Minetest doesn't do this very efficiently: Identical files with different
|
||||||
|
names will not share memory, a copy will be made. Even if they did share
|
||||||
|
memory the references would still consume memory themselves but that would
|
||||||
|
probably be negligable.
|
||||||
|
|
||||||
|
This may not look like a big issue but it is. Many machines, especially
|
||||||
|
phones, still only have 4 GB of RAM or even less. It's quite easy to
|
||||||
|
exceed this limit even with lightweight or basic subgames. This will make
|
||||||
|
devices that don't have enough memory unable to connect. The game will crash
|
||||||
|
while downloading media.
|
||||||
|
|
||||||
|
The unnecessarily redundant caching will fill the permanent storage with
|
||||||
|
unneeded files too. This isn't as big of a problem as the cache isn't
|
||||||
|
(or at least shouldn't) be required for the engine to work. However
|
||||||
|
inexperienced players are going to wonder where their disk space is going.
|
||||||
|
|
||||||
|
### Dynamic servers
|
||||||
|
These are a whole other mess but all you need to know is that they won't work
|
||||||
|
without media pools. The reason is that connected clients can't get the new
|
||||||
|
content without reconnecting due to engine restrictions. Media pools are
|
||||||
|
pushed to the client when it connects. This requires the first server of the
|
||||||
|
media pool to be reachable. This means you can make a dummy server for the
|
||||||
|
media and prevent players from connecting to it, or just use a hub server
|
||||||
|
as the media master.
|
||||||
|
|
||||||
|
## How to use media pools?
|
||||||
|
Simply specify the name of the media pool you'd like the server to be part of
|
||||||
|
in the MediaPool field of the server definition. All server you do this for
|
||||||
|
will be part of the pool. Alternatively you can specify the name of another
|
||||||
|
server if that server doesn't have a custom media pool set or if it's the same
|
||||||
|
as its name. This will result in the servers being in a media pool that has
|
||||||
|
the same name as that server. You can use it to your advantage when creating
|
||||||
|
and naming dummy servers.
|
|
@ -13,7 +13,7 @@ func (sc *ServerConn) prependFormspec(fs *string) {
|
||||||
|
|
||||||
for i, sub := range subs {
|
for i, sub := range subs {
|
||||||
if textureName.MatchString(sub) && !strings.Contains(sub, " ") {
|
if textureName.MatchString(sub) && !strings.Contains(sub, " ") {
|
||||||
prepend(sc.name, &subs[i])
|
prepend(sc.mediaPool, &subs[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
process.go
45
process.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/HimbeerserverDE/srp"
|
"github.com/HimbeerserverDE/srp"
|
||||||
"github.com/anon55555/mt"
|
"github.com/anon55555/mt"
|
||||||
|
@ -441,14 +442,28 @@ func (cc *ClientConn) process(pkt mt.Pkt) {
|
||||||
srv.swapAOID(&cmd.Pointed.(*mt.PointedAO).ID)
|
srv.swapAOID(&cmd.Pointed.(*mt.PointedAO).ID)
|
||||||
}
|
}
|
||||||
case *mt.ToSrvChatMsg:
|
case *mt.ToSrvChatMsg:
|
||||||
go func() {
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func(done chan<- struct{}) {
|
||||||
|
|
||||||
result, isCmd := onChatMsg(cc, cmd)
|
result, isCmd := onChatMsg(cc, cmd)
|
||||||
if !isCmd {
|
if !isCmd {
|
||||||
forward(pkt)
|
forward(pkt)
|
||||||
} else if result != "" {
|
} else if result != "" {
|
||||||
cc.SendChatMsg(result)
|
cc.SendChatMsg(result)
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
close(done)
|
||||||
|
}(done)
|
||||||
|
|
||||||
|
go func(done <-chan struct{}) {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(ChatCmdTimeout):
|
||||||
|
cmdName := strings.Split(cmd.Msg, " ")[0]
|
||||||
|
cc.SendChatMsg("Command", cmdName, "is taking suspiciously long to execute.")
|
||||||
|
}
|
||||||
|
}(done)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -616,7 +631,7 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
|
|
||||||
handStack := mt.Stack{
|
handStack := mt.Stack{
|
||||||
Item: mt.Item{
|
Item: mt.Item{
|
||||||
Name: sc.name + "_hand",
|
Name: sc.mediaPool + "_hand",
|
||||||
},
|
},
|
||||||
Count: 1,
|
Count: 1,
|
||||||
}
|
}
|
||||||
|
@ -734,7 +749,7 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
prepend(sc.name, &cmd.Filename)
|
prepend(sc.mediaPool, &cmd.Filename)
|
||||||
if cmd.ShouldCache {
|
if cmd.ShouldCache {
|
||||||
cacheMedia(mediaFile{
|
cacheMedia(mediaFile{
|
||||||
name: cmd.Filename,
|
name: cmd.Filename,
|
||||||
|
@ -744,17 +759,17 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
}
|
}
|
||||||
case *mt.ToCltSkyParams:
|
case *mt.ToCltSkyParams:
|
||||||
for i := range cmd.Textures {
|
for i := range cmd.Textures {
|
||||||
prependTexture(sc.name, &cmd.Textures[i])
|
prependTexture(sc.mediaPool, &cmd.Textures[i])
|
||||||
}
|
}
|
||||||
case *mt.ToCltSunParams:
|
case *mt.ToCltSunParams:
|
||||||
prependTexture(sc.name, &cmd.Texture)
|
prependTexture(sc.mediaPool, &cmd.Texture)
|
||||||
prependTexture(sc.name, &cmd.ToneMap)
|
prependTexture(sc.mediaPool, &cmd.ToneMap)
|
||||||
prependTexture(sc.name, &cmd.Rise)
|
prependTexture(sc.mediaPool, &cmd.Rise)
|
||||||
case *mt.ToCltMoonParams:
|
case *mt.ToCltMoonParams:
|
||||||
prependTexture(sc.name, &cmd.Texture)
|
prependTexture(sc.mediaPool, &cmd.Texture)
|
||||||
prependTexture(sc.name, &cmd.ToneMap)
|
prependTexture(sc.mediaPool, &cmd.ToneMap)
|
||||||
case *mt.ToCltSetHotbarParam:
|
case *mt.ToCltSetHotbarParam:
|
||||||
prependTexture(sc.name, &cmd.Img)
|
prependTexture(sc.mediaPool, &cmd.Img)
|
||||||
case *mt.ToCltUpdatePlayerList:
|
case *mt.ToCltUpdatePlayerList:
|
||||||
if !clt.playerListInit {
|
if !clt.playerListInit {
|
||||||
clt.playerListInit = true
|
clt.playerListInit = true
|
||||||
|
@ -772,7 +787,7 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *mt.ToCltSpawnParticle:
|
case *mt.ToCltSpawnParticle:
|
||||||
prependTexture(sc.name, &cmd.Texture)
|
prependTexture(sc.mediaPool, &cmd.Texture)
|
||||||
sc.globalParam0(&cmd.NodeParam0)
|
sc.globalParam0(&cmd.NodeParam0)
|
||||||
case *mt.ToCltBlkData:
|
case *mt.ToCltBlkData:
|
||||||
for i := range cmd.Blk.Param0 {
|
for i := range cmd.Blk.Param0 {
|
||||||
|
@ -791,14 +806,14 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
case *mt.ToCltAddNode:
|
case *mt.ToCltAddNode:
|
||||||
sc.globalParam0(&cmd.Node.Param0)
|
sc.globalParam0(&cmd.Node.Param0)
|
||||||
case *mt.ToCltAddParticleSpawner:
|
case *mt.ToCltAddParticleSpawner:
|
||||||
prependTexture(sc.name, &cmd.Texture)
|
prependTexture(sc.mediaPool, &cmd.Texture)
|
||||||
sc.swapAOID(&cmd.AttachedAOID)
|
sc.swapAOID(&cmd.AttachedAOID)
|
||||||
sc.globalParam0(&cmd.NodeParam0)
|
sc.globalParam0(&cmd.NodeParam0)
|
||||||
sc.particleSpawners[cmd.ID] = struct{}{}
|
sc.particleSpawners[cmd.ID] = struct{}{}
|
||||||
case *mt.ToCltDelParticleSpawner:
|
case *mt.ToCltDelParticleSpawner:
|
||||||
delete(sc.particleSpawners, cmd.ID)
|
delete(sc.particleSpawners, cmd.ID)
|
||||||
case *mt.ToCltPlaySound:
|
case *mt.ToCltPlaySound:
|
||||||
prepend(sc.name, &cmd.Name)
|
prepend(sc.mediaPool, &cmd.Name)
|
||||||
sc.swapAOID(&cmd.SrcAOID)
|
sc.swapAOID(&cmd.SrcAOID)
|
||||||
if cmd.Loop {
|
if cmd.Loop {
|
||||||
sc.sounds[cmd.ID] = struct{}{}
|
sc.sounds[cmd.ID] = struct{}{}
|
||||||
|
@ -823,7 +838,7 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
|
||||||
sc.prependFormspec(&cmd.Formspec)
|
sc.prependFormspec(&cmd.Formspec)
|
||||||
case *mt.ToCltMinimapModes:
|
case *mt.ToCltMinimapModes:
|
||||||
for i := range cmd.Modes {
|
for i := range cmd.Modes {
|
||||||
prependTexture(sc.name, &cmd.Modes[i].Texture)
|
prependTexture(sc.mediaPool, &cmd.Modes[i].Texture)
|
||||||
}
|
}
|
||||||
case *mt.ToCltNodeMetasChanged:
|
case *mt.ToCltNodeMetasChanged:
|
||||||
for k := range cmd.Changed {
|
for k := range cmd.Changed {
|
||||||
|
|
2
proxy.go
2
proxy.go
|
@ -16,7 +16,7 @@ import (
|
||||||
const (
|
const (
|
||||||
latestSerializeVer = 28
|
latestSerializeVer = 28
|
||||||
latestProtoVer = 39
|
latestProtoVer = 39
|
||||||
versionString = "5.4.1-dev-b2596eda3"
|
versionString = "5.4.1"
|
||||||
maxPlayerNameLen = 20
|
maxPlayerNameLen = 20
|
||||||
bytesPerMediaBunch = 5000
|
bytesPerMediaBunch = 5000
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,6 +29,8 @@ type ServerConn struct {
|
||||||
salt, srpA, a, srpK []byte
|
salt, srpA, a, srpK []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaPool string
|
||||||
|
|
||||||
inv mt.Inv
|
inv mt.Inv
|
||||||
detachedInvs []string
|
detachedInvs []string
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue