Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
generateGradleTokenClass =
generateGradleTokenClass = glowredman.defaultserverlist.Tags

# Name of the token containing the project's current version to generate/replace.
gradleTokenVersion =
gradleTokenVersion = VERSION

# [DEPRECATED] Mod ID replacement token.
gradleTokenModId =
Expand Down Expand Up @@ -106,7 +106,7 @@ coreModClass = LoadingPlugin

# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly = false
containsMixinsAndOrCoreModOnly = true

# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins = false
Expand Down
208 changes: 140 additions & 68 deletions src/main/java/glowredman/defaultserverlist/Config.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package glowredman.defaultserverlist;

import static net.minecraftforge.common.config.Configuration.CATEGORY_GENERAL;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
Expand All @@ -15,92 +16,169 @@
import java.util.Map;

import net.minecraft.client.multiplayer.ServerData;
import net.minecraftforge.common.config.Configuration;

import org.apache.commons.io.IOUtils;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;

import cpw.mods.fml.common.FMLLog;

public class Config {

public static ConfigObj config = new ConfigObj();
public static final List<ServerData> SERVERS = new ArrayList<>();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static Path configPath;

public static void preInit(File configDir) {
Reader fileReader = null;
try {
configPath = configDir.toPath().resolve("defaultserverlist.json");

if (!Files.exists(configPath)) {
saveConfig(config);
} else {
fileReader = Files.newBufferedReader(configPath, StandardCharsets.UTF_8);
config = GSON.fromJson(fileReader, ConfigObj.class);
public static boolean allowModifications;
private static Configuration config;

/*
* spotless:off
*
* NOTE: There are three different representations for server list entries:
* - String array: The entries are in the format ip|name. This is used for the new configs.
* - Map<String, String>: The key is the name, the value is the ip. This is used for remote server lists.
* - List<ServerData>: This is used by Minecraft.
*
* spotless:on
*/

public static void init(File configDir) {

// Setup
File configFile = new File(configDir, "defaultserverlist.cfg");
Path legacyConfigPath = configDir.toPath().resolve("defaultserverlist.json");
boolean migrate = !configFile.exists() && Files.exists(legacyConfigPath);
Gson gson = new Gson();
config = new Configuration(configFile);

// Migrate to new config file if needed.
if (migrate) {
LoadingPlugin.LOGGER.info("Found legacy config, attempting to migrate...");
try (Reader fileReader = Files.newBufferedReader(legacyConfigPath)) {
ConfigObj legacyConfig = gson.fromJson(fileReader, ConfigObj.class);
config.get(CATEGORY_GENERAL, "useURL", false).set(legacyConfig.useURL);
config.get(CATEGORY_GENERAL, "allowModifications", true).set(legacyConfig.allowModifications);
config.get(CATEGORY_GENERAL, "url", "").set(legacyConfig.url);
config.get(CATEGORY_GENERAL, "servers", new String[0]).set(toArray(legacyConfig.servers));
config.get(CATEGORY_GENERAL, "prevDefaultServers", new String[0])
.set(legacyConfig.prevDefaultServers.toArray(new String[0]));
Files.delete(legacyConfigPath);
LoadingPlugin.LOGGER.info("Migration successful!");
} catch (Exception e) {
LoadingPlugin.LOGGER.error("Migration failed!", e);
}
}

if (config.useURL) {
try {
// servers that are currently at the remote location
Map<String, String> remoteDefaultServers = GSON.fromJson(
IOUtils.toString(new URL(config.url), StandardCharsets.UTF_8),
new TypeToken<LinkedHashMap<String, String>>() {

private static final long serialVersionUID = -1786059589535074931L;
}.getType());

if (config.allowModifications) {
// servers that were added to the remote location since the last time the list was fetched
Map<String, String> diff = new LinkedHashMap<>();

// calculate diff
remoteDefaultServers.forEach((name, ip) -> {
if (!config.prevDefaultServers.contains(ip)) {
diff.put(name, ip);
}
});

// save if the remote location was updated
if (!diff.isEmpty()) {
config.servers.putAll(diff);
config.prevDefaultServers = remoteDefaultServers.values();
saveConfig(config);
// get config values and convert them to a usable format. This also adds comments to the properties.
boolean useURL = config.getBoolean(
"useURL",
CATEGORY_GENERAL,
false,
"Whether or not the default servers should be fetched from a remote location.");
allowModifications = config.getBoolean(
"allowModifications",
CATEGORY_GENERAL,
true,
"Whether or not the user should be able to delete, modify or change the order of the default servers.");
String url = config.getString(
"url",
CATEGORY_GENERAL,
"",
"The remote location to fetch the default servers from. The returned content must be in JSON format (formatted as a map where the keys are the server names and the values the corresponding ip-adresses).");
Map<String, String> servers = toMap(
config.getStringList(
"servers",
CATEGORY_GENERAL,
new String[0],
"The default servers. Format: ip|name"));
String[] prevDefaultServersArray = config
.getStringList("prevDefaultServers", CATEGORY_GENERAL, new String[0], "DO NOT EDIT!");
Collection<String> prevDefaultServers = new ArrayList<>(prevDefaultServersArray.length);
Arrays.stream(prevDefaultServersArray).forEachOrdered(prevDefaultServers::add);

// Fetch servers from the specified remote location.
if (useURL) {
try {
// servers that are currently at the remote location
Map<String, String> remoteDefaultServers = gson.fromJson(
IOUtils.toString(new URL(url), StandardCharsets.UTF_8),
new TypeToken<LinkedHashMap<String, String>>() {

private static final long serialVersionUID = -1786059589535074931L;
}.getType());

if (allowModifications) {
// servers that were added to the remote location since the last time the list was fetched
Map<String, String> diff = new LinkedHashMap<>();

// calculate diff
for (Map.Entry<String, String> entry : remoteDefaultServers.entrySet()) {
String ip = entry.getValue();
if (!prevDefaultServers.contains(ip)) {
diff.put(entry.getKey(), ip);
}
}

} else {
config.servers = remoteDefaultServers;
saveConfig(config);
// save if the remote location was updated
if (!diff.isEmpty()) {
servers.putAll(diff);
prevDefaultServers = remoteDefaultServers.values();
setStringList("servers", toArray(servers));
setStringList("prevDefaultServers", prevDefaultServers.toArray(new String[0]));
}
} catch (Exception e) {
FMLLog.warning(
"Could not get default server list from default location! Are you connected to the internet?");
e.printStackTrace();

} else {
servers = remoteDefaultServers;
setStringList("servers", toArray(servers));
}
} catch (Exception e) {
LoadingPlugin.LOGGER
.error("Could not get default server list from {}! Are you connected to the internet?", url, e);
}
}

// save the config if it changed.
if (config.hasChanged()) {
config.save();
}

config.servers.forEach((name, ip) -> SERVERS.add(new ServerData(name, ip)));
// Convert from Map<String, String> to List<ServerData>
servers.forEach((name, ip) -> SERVERS.add(new ServerData(name, ip)));
}

} catch (Exception e) {
FMLLog.severe("Could not parse default server list!");
e.printStackTrace();
} finally {
IOUtils.closeQuietly(fileReader);
private static String[] toArray(Map<String, String> map) {
String[] array = new String[map.size()];
int i = 0;
for (Map.Entry<String, String> entry : map.entrySet()) {
array[i] = entry.getValue() + '|' + entry.getKey();
i++;
}
return array;
}

public static void saveConfig(ConfigObj config) throws IOException {
File f = configPath.toFile();
if (f.exists()) {
f.delete();
private static Map<String, String> toMap(String[] array) {
Map<String, String> map = new LinkedHashMap<>(array.length);
for (String entry : array) {
String[] parts = entry.split("\\|", 2);
if (parts.length < 2) {
LoadingPlugin.LOGGER.warn("Could not parse entry {} because not '|' was found!", entry);
continue;
}
map.put(parts[1], parts[0]);
}
Files.write(configPath, Arrays.asList(GSON.toJson(config)), StandardCharsets.UTF_8);
return map;
}

public static void saveServers(String[] servers) {
setStringList("servers", servers);
config.save();
}

private static void setStringList(String key, String[] values) {
// config.get(CATEGORY_GENERAL, key, new String[0]).set(values); resets the comment so we can't use that here
config.getCategory(CATEGORY_GENERAL).get(key).set(values);
}

@Deprecated
public static final class ConfigObj {

public boolean useURL = false;
Expand All @@ -110,11 +188,5 @@ public static final class ConfigObj {

@SerializedName("DO_NOT_EDIT_prevDefaultServers")
public Collection<String> prevDefaultServers = new ArrayList<>();

public ConfigObj() {}

public ConfigObj(Map<String, String> servers) {
this.servers = servers;
}
}
}
17 changes: 14 additions & 3 deletions src/main/java/glowredman/defaultserverlist/LoadingPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import java.util.Map;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;

import cpw.mods.fml.relauncher.FMLLaunchHandler;
Expand All @@ -16,10 +19,14 @@
import cpw.mods.fml.relauncher.Side;

@MCVersion("1.7.10")
@Name("DefaultServerList")
@Name("DefaultServerList Core")
@TransformerExclusions("glowredman.defaultserverlist.LoadingPlugin")
public class LoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader {

public static final Logger LOGGER = LogManager.getLogger("DefaultServerList");

static File location;

@Override
public String getMixinConfig() {
return "mixins.defaultserverlist.early.json";
Expand All @@ -40,6 +47,9 @@ public String[] getASMTransformerClass() {

@Override
public String getModContainerClass() {
if (FMLLaunchHandler.side() == Side.CLIENT) {
return ModContainer.class.getName();
}
return null;
}

Expand All @@ -50,8 +60,9 @@ public String getSetupClass() {

@Override
public void injectData(Map<String, Object> data) {
if (FMLLaunchHandler.side() == Side.CLIENT) {
Config.preInit(new File((File) data.get("mcLocation"), "config"));
location = (File) data.get("coremodLocation");
if (location == null) {
location = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
}
}

Expand Down
59 changes: 59 additions & 0 deletions src/main/java/glowredman/defaultserverlist/ModContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package glowredman.defaultserverlist;

import java.io.File;
import java.util.Collections;
import java.util.Set;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.LoadController;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;
import cpw.mods.fml.common.versioning.VersionRange;

public class ModContainer extends DummyModContainer {

public ModContainer() {
super(new ModMetadata());
ModMetadata md = this.getMetadata();

// NOTE: If you change this, change mcmod.info too!
md.authorList = Collections.singletonList("glowredman");
md.description = "Add default servers to the multiplayer screen.";
md.modId = "defaultserverlist";
md.name = "DefaultServerList";
md.updateUrl = "https://files.data-hole.de/mods/defaultserverlist/updates.json";
md.url = "https://github.com/glowredman/DefaultServerList";
md.version = Tags.VERSION;
}

@Override
public VersionRange acceptableMinecraftVersionRange() {
return VersionParser.parseRange("[1.7.10]");
}

@Override
public Set<ArtifactVersion> getRequirements() {
return Collections.singleton(VersionParser.parseVersionReference("gtnhmixins"));
}

@Override
public File getSource() {
return LoadingPlugin.location;
}

@Override
public boolean registerBus(EventBus bus, LoadController controller) {
bus.register(this);
return true;
}

@Subscribe
public void preInit(FMLPreInitializationEvent event) {
Config.init(event.getModConfigurationDirectory());
}
}
Loading
Loading