Compare commits

...

10 Commits

Author SHA1 Message Date
0bc2eb8b07 1.1.11
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-08-11 17:50:32 -04:00
37fe78675e Merge pull request 'Added Simplified Chinese Localization' (#11) from Samekichi/ModUpdater:samekichi-patch-1 into master
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-08-11 21:48:34 +00:00
64d94e4d68 1.1.10
Some checks failed
ModUpdater/pipeline/head There was a failure building this commit
2020-08-11 17:25:20 -04:00
Samekichi
a58350f0ce 添加 'src/main/resources/assets/modupdater/lang/zh_cn.json' 2020-08-11 21:13:04 +00:00
0a2afee6ee 1.16.2
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-08-11 16:46:15 -04:00
47ac38726f Merge pull request 'update to 1.16.2' (#10) from Giselbaer/ModUpdater:master into master
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-08-11 20:43:55 +00:00
Guntram Blohm
bed078867d update to 1.16.2 2020-08-11 22:24:28 +02:00
1d4494d905 1.1.9
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-08-05 13:06:45 -04:00
2f140c4a60 1.1.8
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-07-25 14:10:06 -04:00
4d4facdf50 Update Documentation
All checks were successful
ModUpdater/pipeline/head This commit looks good
2020-06-29 12:43:20 -04:00
19 changed files with 182 additions and 31 deletions

View File

@ -1,5 +1,18 @@
# Changelog # Changelog
**1.1.11**
* Add Translations
**1.1.10**
* Improve
**1.1.9**
* Add ```modupdater``` Entry-Point
**1.1.8**
* Strict Minecraft Version Checking by Default
* Print Message To Log Showing All Scanned Mods
**1.1.7** **1.1.7**
* Disable SemVer In JSON Strategy * Disable SemVer In JSON Strategy

13
Jenkinsfile vendored
View File

@ -15,5 +15,18 @@ pipeline {
} }
} }
} }
stage('Publish') {
when {
expression {
return sh(returnStdout: true, script: 'git tag --contains').trim().length() > 0
}
}
steps {
sh './gradlew publish'
withCredentials([string(credentialsId: 'curseforge_key', variable: 'CURSEFORGE_KEY')]) {
sh './gradlew -Pcurseforge.api_key="${CURSEFORGE_KEY}" curseforge'
}
}
}
} }
} }

View File

@ -17,6 +17,7 @@ This update strategy uses the CurseForge API to check for updates.
``` ```
- Requires Semantic Versioning - Requires Semantic Versioning
- In Loose Versioning Mode, Can Infer File's Supported Minecraft version From CurseForge Metadata
- [Requires ```build.gradle``` modification](#build-gradle-modification) - [Requires ```build.gradle``` modification](#build-gradle-modification)
## GitHub Releases ## GitHub Releases
@ -87,7 +88,8 @@ This update strategy uses the specified JSON file to check for updates.
} }
``` ```
- Does Not Require Semantic Versioning - Does Not Use Semantic Versioning
- A mod is marked as out-of-date if the version in the JSON is different from the current version, so if the current version is newer than the one in the JSON, it will still be marked as out-of-date.
- ```build.gradle``` Modification Is Not Required - ```build.gradle``` Modification Is Not Required
## ```build.gradle``` Modification ## ```build.gradle``` Modification
@ -107,4 +109,31 @@ If you prefer hyphens you can also use:
version = "${project.mod_version}-${project.minecraft_version}" version = "${project.mod_version}-${project.minecraft_version}"
``` ```
You can also just use the major version of Minecraft instead of the full version (like ```1.16``` instead of ```1.16.1``` or ```20w20a```). ## Loose VS Strict Versioning Mode
### Strict (Default)
In strict mode it only marks a file as compatibleif the Minecraft version is identical.
### Loose
```json
{
"custom": {
"modupdater": {
"strict": false
}
}
}
```
In loose mode, it will also mark a file as compatible if it has the same release target.
## Custom Version Compatibility Checking
You can also specify the ```modupdater``` entry-point as a ```ModUpdaterEntryPoint``` to check if a version is compatible with the current MC version.
```gradle
repositories {
maven { url 'https://maven.thebrokenrail.com' }
}
dependencies {
modCompileOnly 'com.thebrokenrail:modupdater:VERSION'
// VERSION = "<Mod Version>+<MC Version>", for example "1.2.4+20w12a"
}
```

View File

@ -9,7 +9,7 @@ Created For [ModFest 1.16](https://modfest.net/1.16)
Go to the Mod Menu and click the configure icon to show the ModUpdater GUI or use the ```/modupdater``` command. Go to the Mod Menu and click the configure icon to show the ModUpdater GUI or use the ```/modupdater``` command.
## Mod Developers ## Mod Developers
[View Mod Developers](MOD_DEVELOPERS.md) [View Mod Developers](MOD_DEVELOPER.md)
## Changelog ## Changelog
[View Changelog](CHANGELOG.md) [View Changelog](CHANGELOG.md)

View File

@ -1,6 +1,7 @@
plugins { plugins {
id 'fabric-loom' version '0.4-SNAPSHOT' id 'fabric-loom' version '0.4-SNAPSHOT'
id 'com.matthewprenger.cursegradle' version '1.4.0' id 'com.matthewprenger.cursegradle' version '1.4.0'
id 'maven-publish'
} }
compileJava { compileJava {
@ -99,4 +100,19 @@ if (project.hasProperty('curseforge.api_key')) {
forgeGradleIntegration = false forgeGradleIntegration = false
} }
} }
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact(remapJar) {
builtBy remapJar
}
}
}
repositories {
maven {
url '/data/maven'
}
}
} }

View File

@ -2,17 +2,17 @@
org.gradle.jvmargs = -Xmx1G org.gradle.jvmargs = -Xmx1G
# Fabric Properties # Fabric Properties
minecraft_version = 1.16.1 minecraft_version = 1.16.2-rc2
curseforge_id = 391583 curseforge_id = 391583
simple_minecraft_version = 1.16.1 simple_minecraft_version = 1.16.2
yarn_build = 1 yarn_build = 1
fabric_loader_version = 0.8.8+build.202 fabric_loader_version = 0.9.1+build.205
# Mod Properties # Mod Properties
mod_version = 1.1.7 mod_version = 1.1.11
maven_group = com.thebrokenrail maven_group = com.thebrokenrail
# Dependencies # Dependencies
fabric_api_version = 0.13.1+build.370-1.16 fabric_api_version = 0.17.2+build.396-1.16
modmenu_version = 1.12.2+build.16 modmenu_version = 1.14.6+build.31
moshi_version = 1.9.2 moshi_version = 1.9.2

View File

@ -5,6 +5,8 @@ public interface ConfigObject {
int getInt(String str) throws MissingValueException; int getInt(String str) throws MissingValueException;
boolean getBoolean(String str) throws MissingValueException;
class MissingValueException extends Exception { class MissingValueException extends Exception {
private static final String MISSING_MSG = "Missing Configuration Property: %s"; private static final String MISSING_MSG = "Missing Configuration Property: %s";
private static final String INVALID_MSG = "Invalid Configuration Property: %s"; private static final String INVALID_MSG = "Invalid Configuration Property: %s";

View File

@ -6,5 +6,13 @@ import javax.annotation.Nullable;
public interface UpdateStrategy { public interface UpdateStrategy {
@Nullable @Nullable
ModUpdate run(ConfigObject obj, String oldVersion, String name); ModUpdate run(ConfigObject obj, String oldVersion, String name, String id);
default boolean isStrict(ConfigObject obj) {
try {
return obj.getBoolean("strict");
} catch (ConfigObject.MissingValueException e) {
return true;
}
}
} }

View File

@ -0,0 +1,5 @@
package com.thebrokenrail.modupdater.api.entrypoint;
public interface ModUpdaterEntryPoint {
boolean isVersionCompatible(String version);
}

View File

@ -35,4 +35,17 @@ public class ConfigObjectCustom implements ConfigObject {
throw new MissingValueException(false, str); throw new MissingValueException(false, str);
} }
} }
@Override
public boolean getBoolean(String str) throws MissingValueException {
if (obj.containsKey(str)) {
try {
return obj.get(str).getAsBoolean();
} catch (ClassCastException e) {
throw new MissingValueException(true, str);
}
} else {
throw new MissingValueException(false, str);
}
}
} }

View File

@ -36,4 +36,17 @@ public class ConfigObjectHardcoded implements ConfigObject {
throw new MissingValueException(false, str); throw new MissingValueException(false, str);
} }
} }
@Override
public boolean getBoolean(String str) throws MissingValueException {
if (map.containsKey(str)) {
try {
return (Boolean) map.get(str);
} catch (ClassCastException e) {
throw new MissingValueException(true, str);
}
} else {
throw new MissingValueException(false, str);
}
}
} }

View File

@ -26,7 +26,7 @@ public class ModUpdaterCommand {
ModUpdate[] updates = ModUpdater.getUpdates(); ModUpdate[] updates = ModUpdater.getUpdates();
assert updates != null; assert updates != null;
for (ModUpdate update : updates) { for (ModUpdate update : updates) {
context.getSource().sendFeedback(new LiteralText(update.text).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, update.downloadURL)).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslatableText("commands." + ModUpdater.NAMESPACE + ".hover")))), false); context.getSource().sendFeedback(new LiteralText(update.text).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, update.downloadURL)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslatableText("commands." + ModUpdater.NAMESPACE + ".hover")))), false);
} }
return updates.length; return updates.length;
})) }))

View File

@ -10,7 +10,7 @@ import com.thebrokenrail.modupdater.api.UpdateStrategy;
import com.thebrokenrail.modupdater.data.ModUpdate; import com.thebrokenrail.modupdater.data.ModUpdate;
import com.thebrokenrail.modupdater.util.Util; import com.thebrokenrail.modupdater.util.Util;
import net.fabricmc.loader.api.SemanticVersion; import net.fabricmc.loader.api.SemanticVersion;
import net.fabricmc.loader.util.version.VersionParsingException; import net.fabricmc.loader.api.VersionParsingException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
@ -33,7 +33,7 @@ public class CurseForgeStrategy implements UpdateStrategy {
@Override @Override
@Nullable @Nullable
public ModUpdate run(ConfigObject obj, String oldVersion, String name) { public ModUpdate run(ConfigObject obj, String oldVersion, String name, String id) {
int projectID; int projectID;
try { try {
projectID = obj.getInt("projectID"); projectID = obj.getInt("projectID");
@ -65,16 +65,18 @@ public class CurseForgeStrategy implements UpdateStrategy {
String versionStr; String versionStr;
GameVersion version = Util.getMinecraftVersion(); GameVersion version = Util.getMinecraftVersion();
if (version.isStable()) { if (version.isStable()) {
versionStr = version.getName(); versionStr = version.getId();
} else { } else {
versionStr = version.getReleaseTarget() + "-Snapshot"; versionStr = version.getReleaseTarget() + "-Snapshot";
} }
boolean strict = isStrict(obj);
CurseForgeFile newestFile = null; CurseForgeFile newestFile = null;
for (CurseForgeFile file : files) { for (CurseForgeFile file : files) {
if (Util.isFileCompatible(file.fileName)) { if (Util.isFileCompatible(file.fileName)) {
String fileVersion = Util.getVersionFromFileName(file.fileName); String fileVersion = Util.getVersionFromFileName(file.fileName);
if (Arrays.asList(file.gameVersion).contains(versionStr) || Util.isVersionCompatible(fileVersion)) { if ((Arrays.asList(file.gameVersion).contains(versionStr) && !strict) || Util.isVersionCompatible(id, fileVersion, strict)) {
if (newestFile != null) { if (newestFile != null) {
String newestFileVersion = Util.getVersionFromFileName(newestFile.fileName); String newestFileVersion = Util.getVersionFromFileName(newestFile.fileName);
try { try {

View File

@ -9,7 +9,7 @@ import com.thebrokenrail.modupdater.api.UpdateStrategy;
import com.thebrokenrail.modupdater.data.ModUpdate; import com.thebrokenrail.modupdater.data.ModUpdate;
import com.thebrokenrail.modupdater.util.Util; import com.thebrokenrail.modupdater.util.Util;
import net.fabricmc.loader.api.SemanticVersion; import net.fabricmc.loader.api.SemanticVersion;
import net.fabricmc.loader.util.version.VersionParsingException; import net.fabricmc.loader.api.VersionParsingException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
@ -35,7 +35,7 @@ public class GitHubReleasesStrategy implements UpdateStrategy {
@Override @Override
@Nullable @Nullable
public ModUpdate run(ConfigObject obj, String oldVersion, String name) { public ModUpdate run(ConfigObject obj, String oldVersion, String name, String id) {
String owner; String owner;
String repo; String repo;
try { try {
@ -66,12 +66,14 @@ public class GitHubReleasesStrategy implements UpdateStrategy {
return null; return null;
} }
boolean strict = isStrict(obj);
GitHubReleaseAsset newestFile = null; GitHubReleaseAsset newestFile = null;
for (GitHubRelease release : releases) { for (GitHubRelease release : releases) {
for (GitHubReleaseAsset asset : release.assets) { for (GitHubReleaseAsset asset : release.assets) {
if (Util.isFileCompatible(asset.name)) { if (Util.isFileCompatible(asset.name)) {
String fileVersion = Util.getVersionFromFileName(asset.name); String fileVersion = Util.getVersionFromFileName(asset.name);
if (Util.isVersionCompatible(fileVersion)) { if (Util.isVersionCompatible(id, fileVersion, strict)) {
if (newestFile != null) { if (newestFile != null) {
try { try {
if (SemanticVersion.parse(fileVersion).compareTo(SemanticVersion.parse(fileVersion)) > 0) { if (SemanticVersion.parse(fileVersion).compareTo(SemanticVersion.parse(fileVersion)) > 0) {

View File

@ -32,7 +32,7 @@ public class JSONStrategy implements UpdateStrategy {
@Override @Override
@Nullable @Nullable
public ModUpdate run(ConfigObject obj, String oldVersion, String name) { public ModUpdate run(ConfigObject obj, String oldVersion, String name, String id) {
String url; String url;
try { try {
url = obj.getString("url"); url = obj.getString("url");
@ -61,7 +61,7 @@ public class JSONStrategy implements UpdateStrategy {
return null; return null;
} }
String version = Util.getMinecraftVersion().getName(); String version = Util.getMinecraftVersion().getId();
if (map.containsKey(version)) { if (map.containsKey(version)) {
LatestVersionEntry entry = map.get(version); LatestVersionEntry entry = map.get(version);
if (!oldVersion.equals(entry.version)) { if (!oldVersion.equals(entry.version)) {

View File

@ -6,7 +6,7 @@ import com.thebrokenrail.modupdater.api.UpdateStrategy;
import com.thebrokenrail.modupdater.data.ModUpdate; import com.thebrokenrail.modupdater.data.ModUpdate;
import com.thebrokenrail.modupdater.util.Util; import com.thebrokenrail.modupdater.util.Util;
import net.fabricmc.loader.api.SemanticVersion; import net.fabricmc.loader.api.SemanticVersion;
import net.fabricmc.loader.util.version.VersionParsingException; import net.fabricmc.loader.api.VersionParsingException;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -40,7 +40,7 @@ public class MavenStrategy implements UpdateStrategy {
@Override @Override
@Nullable @Nullable
public ModUpdate run(ConfigObject obj, String oldVersion, String name) { public ModUpdate run(ConfigObject obj, String oldVersion, String name, String id) {
String repository; String repository;
String group; String group;
String artifact; String artifact;
@ -80,12 +80,14 @@ public class MavenStrategy implements UpdateStrategy {
return null; return null;
} }
boolean strict = isStrict(obj);
String newestVersion = null; String newestVersion = null;
for (int i = 0; i < versions.getLength(); i++) { for (int i = 0; i < versions.getLength(); i++) {
Node node = versions.item(i); Node node = versions.item(i);
String version = node.getTextContent(); String version = node.getTextContent();
if (Util.isVersionCompatible(version)) { if (Util.isVersionCompatible(id, version, strict)) {
if (newestVersion != null) { if (newestVersion != null) {
try { try {
if (SemanticVersion.parse(version).compareTo(SemanticVersion.parse(newestVersion)) > 0) { if (SemanticVersion.parse(version).compareTo(SemanticVersion.parse(newestVersion)) > 0) {

View File

@ -14,10 +14,11 @@ import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class UpdateStrategyRunner { public class UpdateStrategyRunner {
@Nullable @Nullable
private static ModUpdate checkModForUpdate(ModMetadata metadata) { private static ModUpdate checkModForUpdate(ModMetadata metadata, Consumer<String> scan) {
String name = metadata.getName() + " (" + metadata.getId() + ')'; String name = metadata.getName() + " (" + metadata.getId() + ')';
ConfigObject obj; ConfigObject obj;
@ -51,13 +52,16 @@ public class UpdateStrategyRunner {
return null; return null;
} }
return strategyObj.run(obj, oldVersion, name); scan.accept(name);
return strategyObj.run(obj, oldVersion, name, metadata.getId());
} }
public static ModUpdate[] checkAllModsForUpdates() { public static ModUpdate[] checkAllModsForUpdates() {
ModUpdater.logInfo("Checking For Mod Updates..."); ModUpdater.logInfo("Checking For Mod Updates...");
List<ModUpdate> updates = new ArrayList<>(); List<ModUpdate> updates = new ArrayList<>();
List<String> scannedMods = new ArrayList<>();
AtomicInteger remaining = new AtomicInteger(0); AtomicInteger remaining = new AtomicInteger(0);
@ -66,7 +70,11 @@ public class UpdateStrategyRunner {
try { try {
ModMetadata metadata = mod.getMetadata(); ModMetadata metadata = mod.getMetadata();
ModUpdate update = checkModForUpdate(metadata); ModUpdate update = checkModForUpdate(metadata, name -> {
synchronized (scannedMods) {
scannedMods.add(name);
}
});
if (update != null) { if (update != null) {
ModUpdater.logInfo(update.text + " (" + update.downloadURL + ')'); ModUpdater.logInfo(update.text + " (" + update.downloadURL + ')');
@ -100,6 +108,8 @@ public class UpdateStrategyRunner {
ModUpdater.logInfo(updates.size() + String.format(" Mod Update%s Found", updates.size() == 1 ? "" : "s")); ModUpdater.logInfo(updates.size() + String.format(" Mod Update%s Found", updates.size() == 1 ? "" : "s"));
ModUpdater.logInfo("Scanned " + scannedMods.size() + " Mods: " + String.join(", ", scannedMods));
return updates.toArray(new ModUpdate[0]); return updates.toArray(new ModUpdate[0]);
} }
} }

View File

@ -1,10 +1,13 @@
package com.thebrokenrail.modupdater.util; package com.thebrokenrail.modupdater.util;
import com.mojang.bridge.game.GameVersion; import com.mojang.bridge.game.GameVersion;
import com.thebrokenrail.modupdater.ModUpdater;
import com.thebrokenrail.modupdater.api.ConfigObject; import com.thebrokenrail.modupdater.api.ConfigObject;
import com.thebrokenrail.modupdater.api.entrypoint.ModUpdaterEntryPoint;
import com.thebrokenrail.modupdater.api.impl.ConfigObjectHardcoded; import com.thebrokenrail.modupdater.api.impl.ConfigObjectHardcoded;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
import net.minecraft.MinecraftVersion; import net.minecraft.MinecraftVersion;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -12,6 +15,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -71,17 +75,24 @@ public class Util {
if (parts.length > 1) { if (parts.length > 1) {
return String.format("%s.%s", parts[0], parts[1]); return String.format("%s.%s", parts[0], parts[1]);
} else { } else {
return minecraftVersion.getName(); return minecraftVersion.getId();
} }
} }
private static boolean isVersionCompatible(String versionStr, char prefix) { private static boolean isVersionCompatible(String versionStr, char prefix, boolean strict) {
updateMinecraftVersion(); updateMinecraftVersion();
return versionStr.endsWith(prefix + minecraftVersionSemantic) || versionStr.endsWith(prefix + minecraftVersion.getReleaseTarget()) || versionStr.endsWith(prefix + getMajorVersion()); return versionStr.endsWith(prefix + minecraftVersionSemantic) || versionStr.endsWith(prefix + minecraftVersion.getId()) || (!strict && (versionStr.endsWith(prefix + minecraftVersion.getReleaseTarget()) || versionStr.endsWith(prefix + getMajorVersion())));
} }
public static boolean isVersionCompatible(String versionStr) { public static boolean isVersionCompatible(String id, String versionStr, boolean strict) {
return isVersionCompatible(versionStr, '+') || isVersionCompatible(versionStr, '-'); List<EntrypointContainer<ModUpdaterEntryPoint>> list = FabricLoader.getInstance().getEntrypointContainers(ModUpdater.NAMESPACE, ModUpdaterEntryPoint.class);
for (EntrypointContainer<ModUpdaterEntryPoint> container : list) {
if (container.getProvider().getMetadata().getId().equals(id)) {
return container.getEntrypoint().isVersionCompatible(versionStr);
}
}
return isVersionCompatible(versionStr, '+', strict) || isVersionCompatible(versionStr, '-', strict);
} }
public static boolean isFileCompatible(String fileName) { public static boolean isFileCompatible(String fileName) {
@ -99,12 +110,14 @@ public class Util {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("strategy", "curseforge"); map.put("strategy", "curseforge");
map.put("projectID", 306612); map.put("projectID", 306612);
map.put("strict", false);
return new ConfigObjectHardcoded(map); return new ConfigObjectHardcoded(map);
} }
case "modmenu": { case "modmenu": {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("strategy", "curseforge"); map.put("strategy", "curseforge");
map.put("projectID", 308702); map.put("projectID", 308702);
map.put("strict", false);
return new ConfigObjectHardcoded(map); return new ConfigObjectHardcoded(map);
} }
default: { default: {

View File

@ -0,0 +1,10 @@
{
"gui.modupdater.title": "可用的模组更新",
"gui.modupdater.download": "下载",
"gui.modupdater.refresh": "刷新",
"gui.modupdater.loading": "加载中...",
"commands.modupdater.not_loaded": "模组更新加载时无法进行其它操作",
"commands.modupdater.refresh_start": "刷新模组更新列表中",
"commands.modupdater.hover": "点击下载",
"commands.modupdater.list_title": "可用的模组更新:"
}