Compare commits
18 Commits
1.1.3+1.16
...
master
Author | SHA1 | Date | |
---|---|---|---|
0bc2eb8b07 | |||
37fe78675e | |||
64d94e4d68 | |||
|
a58350f0ce | ||
0a2afee6ee | |||
47ac38726f | |||
|
bed078867d | ||
1d4494d905 | |||
2f140c4a60 | |||
4d4facdf50 | |||
74c97537b6 | |||
fedd2fe2d8 | |||
7b43cf36bb | |||
4f6bc2c108 | |||
c3c2b47b67 | |||
9c9f759ab5 | |||
bafa2723c2 | |||
b78675db11 |
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,5 +1,31 @@
|
||||||
# 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**
|
||||||
|
* Disable SemVer In JSON Strategy
|
||||||
|
|
||||||
|
**1.1.6**
|
||||||
|
* Drop Dom4j Dependency
|
||||||
|
|
||||||
|
**1.1.5**
|
||||||
|
* Add JSON Strategy
|
||||||
|
|
||||||
|
**1.1.4**
|
||||||
|
* Add Refresh Button To GUI
|
||||||
|
* Add ``/modupdater`` Command
|
||||||
|
|
||||||
**1.1.3**
|
**1.1.3**
|
||||||
* Swap Buttons In GUI
|
* Swap Buttons In GUI
|
||||||
|
|
||||||
|
|
13
Jenkinsfile
vendored
13
Jenkinsfile
vendored
|
@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
MOD_DEVELOPER.md
Normal file
139
MOD_DEVELOPER.md
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
# Mod Developers
|
||||||
|
To opt-in a mod for ModUpdater, you must select an update strategy in ```fabric.mod.json```.
|
||||||
|
|
||||||
|
## CurseForge
|
||||||
|
This update strategy uses the CurseForge API to check for updates.
|
||||||
|
|
||||||
|
### ```fabric.mod.json```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"custom": {
|
||||||
|
"modupdater": {
|
||||||
|
"strategy": "curseforge",
|
||||||
|
"projectID": 306612
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Requires Semantic Versioning
|
||||||
|
- In Loose Versioning Mode, Can Infer File's Supported Minecraft version From CurseForge Metadata
|
||||||
|
- [Requires ```build.gradle``` modification](#build-gradle-modification)
|
||||||
|
|
||||||
|
## GitHub Releases
|
||||||
|
This update strategy uses the GitHub Releases API to check for updates.
|
||||||
|
|
||||||
|
### ```fabric.mod.json```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"custom": {
|
||||||
|
"modupdater": {
|
||||||
|
"strategy": "github",
|
||||||
|
"owner": "Repository Owner",
|
||||||
|
"repository": "Repository Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Requires Semantic Versioning
|
||||||
|
- [Requires ```build.gradle``` Modification](#build-gradle-modification)
|
||||||
|
|
||||||
|
## Maven
|
||||||
|
This update strategy uses the specified Maven repository to check for updates.
|
||||||
|
|
||||||
|
### ```fabric.mod.json```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"custom": {
|
||||||
|
"modupdater": {
|
||||||
|
"strategy": "maven",
|
||||||
|
"repository": "https://maven.fabricmc.net",
|
||||||
|
"group": "net.fabricmc.fabric-api",
|
||||||
|
"artifact": "fabric-api"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Requires Semantic Versioning
|
||||||
|
- [Requires ```build.gradle``` Modification](#build-gradle-modification)
|
||||||
|
|
||||||
|
## JSON
|
||||||
|
This update strategy uses the specified JSON file to check for updates.
|
||||||
|
|
||||||
|
### ```fabric.mod.json```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"custom": {
|
||||||
|
"modupdater": {
|
||||||
|
"strategy": "json",
|
||||||
|
"url": "https://example.com/thing.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Format
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"1.16.1": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"downloadUrl": "https://example.com/thing2.jar"
|
||||||
|
},
|
||||||
|
"20w20a": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"downloadUrl": "https://example.com/thing.jar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 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
|
||||||
|
Multiple update strategies require the Minecraft version to be appended to the end of the JAR version to detect what Minecraft version a JAR supports.
|
||||||
|
|
||||||
|
Replace:
|
||||||
|
```gradle
|
||||||
|
version = project.mod_version
|
||||||
|
```
|
||||||
|
with:
|
||||||
|
```gradle
|
||||||
|
version = "${project.mod_version}+${project.minecraft_version}"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you prefer hyphens you can also use:
|
||||||
|
```gradle
|
||||||
|
version = "${project.mod_version}-${project.minecraft_version}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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"
|
||||||
|
}
|
||||||
|
```
|
54
README.md
54
README.md
|
@ -6,60 +6,10 @@ Created For [ModFest 1.16](https://modfest.net/1.16)
|
||||||
**NOTE:** This is only able to scan mods that have opted-in!
|
**NOTE:** This is only able to scan mods that have opted-in!
|
||||||
|
|
||||||
## Mod Users
|
## Mod Users
|
||||||
Go to the Mod Menu and click the configure icon for ModUpdater to view available updates.
|
Go to the Mod Menu and click the configure icon to show the ModUpdater GUI or use the ```/modupdater``` command.
|
||||||
|
|
||||||
## Mod Developers
|
## Mod Developers
|
||||||
Both ```fabric.mod.json``` and ```build.gradle``` must be modified to opt-in to ModUpdater.
|
[View Mod Developers](MOD_DEVELOPER.md)
|
||||||
|
|
||||||
### ```fabric.mod.json```
|
|
||||||
**Maven**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"custom": {
|
|
||||||
"modupdater": {
|
|
||||||
"strategy": "maven",
|
|
||||||
"repository": "https://maven.fabricmc.net",
|
|
||||||
"group": "net.fabricmc.fabric-api",
|
|
||||||
"artifact": "fabric-api"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**CurseForge**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"custom": {
|
|
||||||
"modupdater": {
|
|
||||||
"strategy": "curseforge",
|
|
||||||
"projectID": 306612
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**GitHub Releases**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"custom": {
|
|
||||||
"modupdater": {
|
|
||||||
"strategy": "github",
|
|
||||||
"owner": "Repository Owner",
|
|
||||||
"repository": "Repository Name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ```build.gradle```
|
|
||||||
Replace:
|
|
||||||
```gradle
|
|
||||||
version = project.mod_version
|
|
||||||
```
|
|
||||||
with this:
|
|
||||||
```gradle
|
|
||||||
version = "${project.mod_version}+${project.minecraft_version}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
[View Changelog](CHANGELOG.md)
|
[View Changelog](CHANGELOG.md)
|
||||||
|
|
19
build.gradle
19
build.gradle
|
@ -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 {
|
||||||
|
@ -30,9 +31,6 @@ dependencies {
|
||||||
implementation "com.squareup.moshi:moshi:${project.moshi_version}"
|
implementation "com.squareup.moshi:moshi:${project.moshi_version}"
|
||||||
includeTransitive "com.squareup.moshi:moshi:${project.moshi_version}"
|
includeTransitive "com.squareup.moshi:moshi:${project.moshi_version}"
|
||||||
|
|
||||||
implementation "org.dom4j:dom4j:${project.dom4j_version}"
|
|
||||||
includeTransitive "org.dom4j:dom4j:${project.dom4j_version}"
|
|
||||||
|
|
||||||
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
|
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,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'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,18 +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.3
|
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
|
||||||
dom4j_version = 2.1.3
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package com.thebrokenrail.modupdater;
|
package com.thebrokenrail.modupdater;
|
||||||
|
|
||||||
import com.thebrokenrail.modupdater.strategy.util.UpdateStrategyRunner;
|
import com.thebrokenrail.modupdater.command.ModUpdaterCommand;
|
||||||
import com.thebrokenrail.modupdater.data.ModUpdate;
|
import com.thebrokenrail.modupdater.data.ModUpdate;
|
||||||
|
import com.thebrokenrail.modupdater.strategy.util.UpdateStrategyRunner;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@ -25,10 +26,11 @@ public class ModUpdater implements ModInitializer {
|
||||||
getLogger().info(info);
|
getLogger().info(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static volatile ModUpdate[] updates;
|
private static volatile ModUpdate[] updates = null;
|
||||||
|
|
||||||
public static void findUpdates() {
|
public static void findUpdates() {
|
||||||
updates = UpdateStrategyRunner.checkAllModsForUpdates();
|
updates = null;
|
||||||
|
new Thread(() -> updates = UpdateStrategyRunner.checkAllModsForUpdates()).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -38,7 +40,7 @@ public class ModUpdater implements ModInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
Thread updateThread = new Thread(ModUpdater::findUpdates);
|
findUpdates();
|
||||||
updateThread.start();
|
ModUpdaterCommand.register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,11 @@ package com.thebrokenrail.modupdater.api;
|
||||||
|
|
||||||
public interface ConfigObject {
|
public interface ConfigObject {
|
||||||
String getString(String str) throws MissingValueException;
|
String getString(String str) throws MissingValueException;
|
||||||
|
|
||||||
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";
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.thebrokenrail.modupdater.api.entrypoint;
|
||||||
|
|
||||||
|
public interface ModUpdaterEntryPoint {
|
||||||
|
boolean isVersionCompatible(String version);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ import java.util.Arrays;
|
||||||
public class ModUpdateScreen extends Screen {
|
public class ModUpdateScreen extends Screen {
|
||||||
public ModUpdateListWidget list;
|
public ModUpdateListWidget list;
|
||||||
private ButtonWidget download;
|
private ButtonWidget download;
|
||||||
|
private ButtonWidget refresh;
|
||||||
private final Screen parent;
|
private final Screen parent;
|
||||||
|
|
||||||
|
private static final int BOTTOM_ROW = 60;
|
||||||
|
|
||||||
public ModUpdateScreen(Screen parent) {
|
public ModUpdateScreen(Screen parent) {
|
||||||
super(new TranslatableText("gui." + ModUpdater.NAMESPACE + ".title"));
|
super(new TranslatableText("gui." + ModUpdater.NAMESPACE + ".title"));
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -31,25 +34,31 @@ public class ModUpdateScreen extends Screen {
|
||||||
protected void init() {
|
protected void init() {
|
||||||
list = new ModUpdateListWidget(client, this);
|
list = new ModUpdateListWidget(client, this);
|
||||||
children.add(list);
|
children.add(list);
|
||||||
|
int buttonHeight = 20;
|
||||||
|
int padding = 2;
|
||||||
|
int actionRowY = height - BOTTOM_ROW / 2 - padding - buttonHeight;
|
||||||
|
int doneY = height - BOTTOM_ROW / 2 + padding;
|
||||||
int buttonWidth = 150;
|
int buttonWidth = 150;
|
||||||
int paddingX = 5;
|
int refreshX = width / 2 - buttonWidth - padding;
|
||||||
int downloadX = width / 2 - buttonWidth - paddingX;
|
int downloadX = width / 2 + padding;
|
||||||
int doneX = width / 2 + paddingX;
|
int doneX = width / 2 - buttonWidth / 2;
|
||||||
addButton(new ButtonWidget(doneX, height - 30, buttonWidth, 20, ScreenTexts.DONE, buttonWidget -> {
|
refresh = addButton(new ButtonWidget(refreshX, actionRowY, buttonWidth, buttonHeight, new TranslatableText("gui." + ModUpdater.NAMESPACE + ".refresh"), buttonWidget -> ModUpdater.findUpdates()));
|
||||||
assert client != null;
|
download = addButton(new ButtonWidget(downloadX, actionRowY, buttonWidth, buttonHeight, new TranslatableText("gui." + ModUpdater.NAMESPACE + ".download"), buttonWidget -> {
|
||||||
client.openScreen(parent);
|
|
||||||
}));
|
|
||||||
download = addButton(new ButtonWidget(downloadX, height - 30, buttonWidth, 20, new TranslatableText("gui." + ModUpdater.NAMESPACE + ".download"), buttonWidget -> {
|
|
||||||
if (list.getSelected() != null) {
|
if (list.getSelected() != null) {
|
||||||
Util.getOperatingSystem().open(list.getSelected().update.downloadURL);
|
Util.getOperatingSystem().open(list.getSelected().update.downloadURL);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
download.active = false;
|
addButton(new ButtonWidget(doneX, doneY, buttonWidth, buttonHeight, ScreenTexts.DONE, buttonWidget -> {
|
||||||
|
assert client != null;
|
||||||
|
client.openScreen(parent);
|
||||||
|
}));
|
||||||
super.init();
|
super.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||||
|
refresh.active = ModUpdater.getUpdates() != null;
|
||||||
|
download.active = list.getSelected() != null;
|
||||||
list.render(matrices, mouseX, mouseY, delta);
|
list.render(matrices, mouseX, mouseY, delta);
|
||||||
drawCenteredText(matrices, textRenderer, title, width / 2, 16, 16777215);
|
drawCenteredText(matrices, textRenderer, title, width / 2, 16, 16777215);
|
||||||
super.render(matrices, mouseX, mouseY, delta);
|
super.render(matrices, mouseX, mouseY, delta);
|
||||||
|
@ -61,7 +70,7 @@ public class ModUpdateScreen extends Screen {
|
||||||
private ModUpdate[] updates = null;
|
private ModUpdate[] updates = null;
|
||||||
|
|
||||||
private ModUpdateListWidget(MinecraftClient client, ModUpdateScreen screen) {
|
private ModUpdateListWidget(MinecraftClient client, ModUpdateScreen screen) {
|
||||||
super(client, screen.width, screen.height, 32, screen.height - 40, 18);
|
super(client, screen.width, screen.height, 32, screen.height - BOTTOM_ROW, 18);
|
||||||
this.screen = screen;
|
this.screen = screen;
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
|
@ -71,6 +80,7 @@ public class ModUpdateScreen extends Screen {
|
||||||
ModUpdate[] newUpdates = ModUpdater.getUpdates();
|
ModUpdate[] newUpdates = ModUpdater.getUpdates();
|
||||||
if (!Arrays.equals(updates, newUpdates)) {
|
if (!Arrays.equals(updates, newUpdates)) {
|
||||||
clearEntries();
|
clearEntries();
|
||||||
|
setSelected(null);
|
||||||
if (newUpdates != null) {
|
if (newUpdates != null) {
|
||||||
for (ModUpdate update : newUpdates) {
|
for (ModUpdate update : newUpdates) {
|
||||||
addEntry(new ModUpdateEntry(update, screen, this));
|
addEntry(new ModUpdateEntry(update, screen, this));
|
||||||
|
@ -99,9 +109,6 @@ public class ModUpdateScreen extends Screen {
|
||||||
super.setSelected(entry);
|
super.setSelected(entry);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
NarratorManager.INSTANCE.narrate(new TranslatableText("narrator.select", entry.update.text).asString());
|
NarratorManager.INSTANCE.narrate(new TranslatableText("narrator.select", entry.update.text).asString());
|
||||||
screen.download.active = true;
|
|
||||||
} else {
|
|
||||||
screen.download.active = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +127,7 @@ public class ModUpdateScreen extends Screen {
|
||||||
reload();
|
reload();
|
||||||
super.render(matrices, mouseX, mouseY, delta);
|
super.render(matrices, mouseX, mouseY, delta);
|
||||||
if (updates == null) {
|
if (updates == null) {
|
||||||
drawCenteredText(matrices, screen.textRenderer, new TranslatableText("gui.modupdater.loading"), width / 2, height / 2 - screen.textRenderer.fontHeight, 16777215);
|
drawCenteredText(matrices, screen.textRenderer, new TranslatableText("gui.modupdater.loading"), width / 2, (bottom - top) / 2 - screen.textRenderer.fontHeight + top, 16777215);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.thebrokenrail.modupdater.command;
|
||||||
|
|
||||||
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
|
import com.thebrokenrail.modupdater.data.ModUpdate;
|
||||||
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
|
import net.minecraft.command.CommandException;
|
||||||
|
import net.minecraft.server.command.CommandManager;
|
||||||
|
import net.minecraft.text.ClickEvent;
|
||||||
|
import net.minecraft.text.HoverEvent;
|
||||||
|
import net.minecraft.text.LiteralText;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
|
||||||
|
public class ModUpdaterCommand {
|
||||||
|
private static void checkLoaded() throws CommandException {
|
||||||
|
if (ModUpdater.getUpdates() == null) {
|
||||||
|
throw new CommandException(new TranslatableText("commands." + ModUpdater.NAMESPACE + ".not_loaded"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, isDedicated) -> dispatcher.register(CommandManager.literal(ModUpdater.NAMESPACE)
|
||||||
|
.then(CommandManager.literal("list").executes(context -> {
|
||||||
|
checkLoaded();
|
||||||
|
context.getSource().sendFeedback(new TranslatableText("commands." + ModUpdater.NAMESPACE + ".list_title").formatted(Formatting.YELLOW), false);
|
||||||
|
ModUpdate[] updates = ModUpdater.getUpdates();
|
||||||
|
assert updates != null;
|
||||||
|
for (ModUpdate update : updates) {
|
||||||
|
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;
|
||||||
|
}))
|
||||||
|
.then(CommandManager.literal("refresh").requires(source -> source.hasPermissionLevel(3)).executes(context -> {
|
||||||
|
checkLoaded();
|
||||||
|
ModUpdater.findUpdates();
|
||||||
|
context.getSource().sendFeedback(new TranslatableText("commands." + ModUpdater.NAMESPACE + ".refresh_start"), true);
|
||||||
|
return 1;
|
||||||
|
}))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,11 @@ import com.squareup.moshi.JsonDataException;
|
||||||
import com.squareup.moshi.Moshi;
|
import com.squareup.moshi.Moshi;
|
||||||
import com.thebrokenrail.modupdater.ModUpdater;
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
import com.thebrokenrail.modupdater.api.ConfigObject;
|
import com.thebrokenrail.modupdater.api.ConfigObject;
|
||||||
import com.thebrokenrail.modupdater.data.ModUpdate;
|
|
||||||
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
|
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 {
|
||||||
|
|
|
@ -5,11 +5,11 @@ import com.squareup.moshi.JsonDataException;
|
||||||
import com.squareup.moshi.Moshi;
|
import com.squareup.moshi.Moshi;
|
||||||
import com.thebrokenrail.modupdater.ModUpdater;
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
import com.thebrokenrail.modupdater.api.ConfigObject;
|
import com.thebrokenrail.modupdater.api.ConfigObject;
|
||||||
import com.thebrokenrail.modupdater.data.ModUpdate;
|
|
||||||
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
|
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) {
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.thebrokenrail.modupdater.strategy;
|
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter;
|
||||||
|
import com.squareup.moshi.JsonDataException;
|
||||||
|
import com.squareup.moshi.Moshi;
|
||||||
|
import com.squareup.moshi.Types;
|
||||||
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
|
import com.thebrokenrail.modupdater.api.ConfigObject;
|
||||||
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
|
import com.thebrokenrail.modupdater.data.ModUpdate;
|
||||||
|
import com.thebrokenrail.modupdater.util.Util;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class JSONStrategy implements UpdateStrategy {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static class LatestVersionEntry {
|
||||||
|
private String version;
|
||||||
|
private String downloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final JsonAdapter<Map<String, LatestVersionEntry>> jsonAdapter;
|
||||||
|
|
||||||
|
public JSONStrategy() {
|
||||||
|
Moshi moshi = new Moshi.Builder().build();
|
||||||
|
Type map = Types.newParameterizedType(Map.class, String.class, LatestVersionEntry.class);
|
||||||
|
jsonAdapter = moshi.adapter(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public ModUpdate run(ConfigObject obj, String oldVersion, String name, String id) {
|
||||||
|
String url;
|
||||||
|
try {
|
||||||
|
url = obj.getString("url");
|
||||||
|
} catch (ConfigObject.MissingValueException e) {
|
||||||
|
ModUpdater.logWarn(name, e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data;
|
||||||
|
try {
|
||||||
|
data = Util.urlToString(url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ModUpdater.logWarn(name, e.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, LatestVersionEntry> map;
|
||||||
|
try {
|
||||||
|
map = jsonAdapter.fromJson(data);
|
||||||
|
} catch (JsonDataException | IOException e) {
|
||||||
|
ModUpdater.logWarn(name, e.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = Util.getMinecraftVersion().getId();
|
||||||
|
if (map.containsKey(version)) {
|
||||||
|
LatestVersionEntry entry = map.get(version);
|
||||||
|
if (!oldVersion.equals(entry.version)) {
|
||||||
|
return new ModUpdate(oldVersion, entry.version, entry.downloadUrl, name);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,28 +2,45 @@ package com.thebrokenrail.modupdater.strategy;
|
||||||
|
|
||||||
import com.thebrokenrail.modupdater.ModUpdater;
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
import com.thebrokenrail.modupdater.api.ConfigObject;
|
import com.thebrokenrail.modupdater.api.ConfigObject;
|
||||||
import com.thebrokenrail.modupdater.data.ModUpdate;
|
|
||||||
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
|
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.dom4j.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.dom4j.DocumentException;
|
import org.w3c.dom.Node;
|
||||||
import org.dom4j.Node;
|
import org.w3c.dom.NodeList;
|
||||||
import org.dom4j.io.SAXReader;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MavenStrategy implements UpdateStrategy {
|
public class MavenStrategy implements UpdateStrategy {
|
||||||
private final SAXReader reader = new SAXReader();
|
private final DocumentBuilder builder;
|
||||||
|
|
||||||
|
public MavenStrategy() {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setValidating(true);
|
||||||
|
factory.setIgnoringElementContentWhitespace(true);
|
||||||
|
try {
|
||||||
|
builder = factory.newDocumentBuilder();
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@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;
|
||||||
|
@ -48,18 +65,29 @@ public class MavenStrategy implements UpdateStrategy {
|
||||||
|
|
||||||
Document doc;
|
Document doc;
|
||||||
try (InputStream source = new ByteArrayInputStream(data.getBytes())) {
|
try (InputStream source = new ByteArrayInputStream(data.getBytes())) {
|
||||||
doc = reader.read(source);
|
doc = builder.parse(source);
|
||||||
} catch (DocumentException | IOException e) {
|
} catch (IOException | SAXException e) {
|
||||||
ModUpdater.logWarn(name, e.toString());
|
ModUpdater.logWarn(name, e.toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Node> versions = doc.selectNodes("/metadata/versioning/versions/*");
|
XPath xPath = XPathFactory.newInstance().newXPath();
|
||||||
|
NodeList versions;
|
||||||
|
try {
|
||||||
|
versions = (NodeList) xPath.compile("/metadata/versioning/versions/*").evaluate(doc, XPathConstants.NODESET);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
ModUpdater.logWarn(name, e.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean strict = isStrict(obj);
|
||||||
|
|
||||||
String newestVersion = null;
|
String newestVersion = null;
|
||||||
for (Node node : versions) {
|
for (int i = 0; i < versions.getLength(); i++) {
|
||||||
String version = node.getText();
|
Node node = versions.item(i);
|
||||||
if (Util.isVersionCompatible(version)) {
|
|
||||||
|
String version = node.getTextContent();
|
||||||
|
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) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.thebrokenrail.modupdater.strategy.util;
|
||||||
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
import com.thebrokenrail.modupdater.strategy.CurseForgeStrategy;
|
import com.thebrokenrail.modupdater.strategy.CurseForgeStrategy;
|
||||||
import com.thebrokenrail.modupdater.strategy.GitHubReleasesStrategy;
|
import com.thebrokenrail.modupdater.strategy.GitHubReleasesStrategy;
|
||||||
|
import com.thebrokenrail.modupdater.strategy.JSONStrategy;
|
||||||
import com.thebrokenrail.modupdater.strategy.MavenStrategy;
|
import com.thebrokenrail.modupdater.strategy.MavenStrategy;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -21,5 +22,6 @@ public class UpdateStrategyRegistry {
|
||||||
data.put("curseforge", new CurseForgeStrategy());
|
data.put("curseforge", new CurseForgeStrategy());
|
||||||
data.put("maven", new MavenStrategy());
|
data.put("maven", new MavenStrategy());
|
||||||
data.put("github", new GitHubReleasesStrategy());
|
data.put("github", new GitHubReleasesStrategy());
|
||||||
|
data.put("json", new JSONStrategy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package com.thebrokenrail.modupdater.strategy.util;
|
||||||
|
|
||||||
import com.thebrokenrail.modupdater.ModUpdater;
|
import com.thebrokenrail.modupdater.ModUpdater;
|
||||||
import com.thebrokenrail.modupdater.api.ConfigObject;
|
import com.thebrokenrail.modupdater.api.ConfigObject;
|
||||||
|
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
||||||
import com.thebrokenrail.modupdater.api.impl.ConfigObjectCustom;
|
import com.thebrokenrail.modupdater.api.impl.ConfigObjectCustom;
|
||||||
import com.thebrokenrail.modupdater.data.ModUpdate;
|
import com.thebrokenrail.modupdater.data.ModUpdate;
|
||||||
import com.thebrokenrail.modupdater.api.UpdateStrategy;
|
|
||||||
import com.thebrokenrail.modupdater.util.Util;
|
import com.thebrokenrail.modupdater.util.Util;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.fabricmc.loader.api.ModContainer;
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
@ -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,32 +52,43 @@ 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);
|
||||||
|
|
||||||
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
ModMetadata metadata = mod.getMetadata();
|
try {
|
||||||
|
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 + ')');
|
||||||
synchronized (updates) {
|
synchronized (updates) {
|
||||||
updates.add(update);
|
updates.add(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
synchronized (remaining) {
|
||||||
|
remaining.decrementAndGet();
|
||||||
|
remaining.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (remaining) {
|
|
||||||
remaining.decrementAndGet();
|
|
||||||
remaining.notifyAll();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
synchronized (remaining) {
|
synchronized (remaining) {
|
||||||
|
@ -96,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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
{
|
{
|
||||||
"gui.modupdater.title": "Available Mod Updates",
|
"gui.modupdater.title": "Available Mod Updates",
|
||||||
"gui.modupdater.download": "Download",
|
"gui.modupdater.download": "Download",
|
||||||
"gui.modupdater.loading": "Loading..."
|
"gui.modupdater.refresh": "Refresh",
|
||||||
|
"gui.modupdater.loading": "Loading...",
|
||||||
|
"commands.modupdater.not_loaded": "Unable To Perform Operation While Mod Updates Are Loading",
|
||||||
|
"commands.modupdater.refresh_start": "Refreshing Mod Updates",
|
||||||
|
"commands.modupdater.hover": "Click To Download",
|
||||||
|
"commands.modupdater.list_title": "Available Mod Updates:"
|
||||||
}
|
}
|
10
src/main/resources/assets/modupdater/lang/zh_cn.json
Normal file
10
src/main/resources/assets/modupdater/lang/zh_cn.json
Normal 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": "可用的模组更新:"
|
||||||
|
}
|
Reference in New Issue
Block a user