package net.md_5.bungee.conf;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.Util;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ConfigurationAdapter;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
public class YamlConfig implements ConfigurationAdapter
{
/**
* The default tab list options available for picking.
*/
@RequiredArgsConstructor
private enum DefaultTabList
{
GLOBAL(), GLOBAL_PING(), SERVER();
}
private final Yaml yaml;
private Map config;
private final File file = new File( "config.yml" );
public YamlConfig()
{
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
yaml = new Yaml( options );
}
@Override
public void load()
{
try
{
file.createNewFile();
try ( InputStream is = new FileInputStream( file ) )
{
config = (Map) yaml.load( is );
}
if ( config == null )
{
config = new CaseInsensitiveMap();
} else
{
config = new CaseInsensitiveMap( config );
}
} catch ( IOException ex )
{
throw new RuntimeException( "Could not load configuration!", ex );
}
Map<String, Object> permissions = get( "permissions", new HashMap<String, Object>() );
if ( permissions.isEmpty() )
{
permissions.put( "default", Arrays.asList( new String[]
{
"bungeecord.command.server", "bungeecord.command.list"
} ) );
permissions.put( "admin", Arrays.asList( new String[]
{
"bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload"
} ) );
}
Map<String, Object> groups = get( "groups", new HashMap<String, Object>() );
if ( groups.isEmpty() )
{
groups.put( "md_5", Collections.singletonList( "admin" ) );
}
}
private <T> T get(String path, T def)
{
return get( path, def, config );
}
@SuppressWarnings("unchecked")
private <T> T get(String path, T def, Map submap)
{
int index = path.indexOf( '.' );
if ( index == -1 )
{
Object val = submap.get( path );
if ( val == null && def != null )
{
val = def;
submap.put( path, def );
save();
}
return (T) val;
} else
{
String first = path.substring( 0, index );
String second = path.substring( index + 1, path.length() );
Map sub = (Map) submap.get( first );
if ( sub == null )
{
sub = new LinkedHashMap();
submap.put( first, sub );
}
return get( second, def, sub );
}
}
private void save()
{
try
{
try ( FileWriter wr = new FileWriter( file ) )
{
yaml.dump( config, wr );
}
} catch ( IOException ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save config", ex );
}
}
@Override
public int getInt(String path, int def)
{
return get( path, def );
}
@Override
public String getString(String path, String def)
{
return get( path, def );
}
@Override
public boolean getBoolean(String path, boolean def)
{
return get( path, def );
}
@Override
@SuppressWarnings("unchecked")
public Map<String, ServerInfo> getServers()
{
Map<String, Map<String, Object>> base = get( "servers", (Map) Collections.singletonMap( "lobby", new HashMap<>() ) );
Map<String, ServerInfo> ret = new HashMap<>();
for ( Map.Entry<String, Map<String, Object>> entry : base.entrySet() )
{
Map<String, Object> val = entry.getValue();
String name = entry.getKey();
String addr = get( "address", "localhost:25565", val );
String motd = ChatColor.translateAlternateColorCodes( '&', get( "motd", "&1Just another BungeeCord - Forced Host", val ) );
boolean restricted = get( "restricted", false, val );
InetSocketAddress address = Util.getAddr( addr );
ServerInfo info = ProxyServer.getInstance().constructServerInfo( name, address, motd, restricted );
ret.put( name, info );
}
return ret;
}
@Override
@SuppressWarnings("unchecked")
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
public Collection<ListenerInfo> getListeners()
{
Collection<Map<String, Object>> base = get( "listeners", (Collection) Arrays.asList( new Map[]
{
new HashMap()
} ) );
Map<String, String> forcedDef = new HashMap<>();
forcedDef.put( "pvp.md-5.net", "pvp" );
Collection<ListenerInfo> ret = new HashSet<>();
for ( Map<String, Object> val : base )
{
String motd = get( "motd", "&1Another Bungee server", val );
motd = ChatColor.translateAlternateColorCodes( '&', motd );
int maxPlayers = get( "max_players", 1, val );
String defaultServer = get( "default_server", "lobby", val );
String fallbackServer = get( "fallback_server", defaultServer, val );
boolean forceDefault = get( "force_default_server", false, val );
String host = get( "host", "0.0.0.0:25577", val );
int tabListSize = get( "tab_size", 60, val );
InetSocketAddress address = Util.getAddr( host );
Map<String, String> forced = new CaseInsensitiveMap<>( get( "forced_hosts", forcedDef, val ) );
String tabListName = get( "tab_list", "GLOBAL_PING", val );
DefaultTabList value = DefaultTabList.valueOf( tabListName.toUpperCase() );
if ( value == null )
{
value = DefaultTabList.GLOBAL_PING;
}
boolean setLocalAddress = get( "bind_local_address", true, val );
boolean pingPassthrough = get( "ping_passthrough", false, val );
boolean query = get( "query_enabled", false, val );
int queryPort = get( "query_port", 25577, val );
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, value.toString(), setLocalAddress, pingPassthrough, queryPort, query );
ret.add( info );
}
return ret;
}
@Override
@SuppressWarnings("unchecked")
public Collection<String> getGroups(String player)
{
Collection<String> groups = get( "groups." + player, null );
Collection<String> ret = ( groups == null ) ? new HashSet<String>() : new HashSet<>( groups );
ret.add( "default" );
return ret;
}
@Override
public Collection<?> getList(String path, Collection<?> def)
{
return get( path, def );
}
@Override
@SuppressWarnings("unchecked")
public Collection<String> getPermissions(String group)
{
Collection<String> permissions = get( "permissions." + group, null );
return ( permissions == null ) ? Collections.EMPTY_SET : permissions;
}
}