Skip to content

Commit

Permalink
Add update checker to check version with GitHub latest release (#64)
Browse files Browse the repository at this point in the history
* add update checker to check version with GitHub latest release

* better exception logger

* make UpdateChecker extends Thread, cache latestVersion

* show update msg when player join world

* fix mod version
  • Loading branch information
DancingSnow0517 authored Nov 10, 2024
1 parent afce8d1 commit fbb10a5
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.github.skydynamic.quickbackupmulti.config.ConfigStorage;
import io.github.skydynamic.quickbackupmulti.command.QuickBackupMultiCommand;
import io.github.skydynamic.quickbackupmulti.utils.QbmManager;
import io.github.skydynamic.quickbackupmulti.utils.UpdateChecker;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
Expand Down Expand Up @@ -47,7 +48,11 @@ public class QuickBackupMulti implements ModInitializer {
//#else
//$$ public static final Logger LOGGER = LogManager.getLogger(QuickBackupMulti.class);
//#endif

public static final UpdateChecker updateChecker = new UpdateChecker();

public static final String modName = "QuickBackupMulti";
public static final String modId = "quickbackupmulti";

EnvType env = FabricLoader.getInstance().getEnvironmentType();

Expand All @@ -56,6 +61,9 @@ public class QuickBackupMulti implements ModInitializer {

@Override
public void onInitialize() {
FabricLoader.getInstance().getModContainer(modId).ifPresent(modContainer ->
Config.TEMP_CONFIG.setModVersion(modContainer.getMetadata().getVersion().getFriendlyString()));

//#if MC>=12005
//$$ Packets.registerPacketCodec();
//#endif
Expand Down Expand Up @@ -104,6 +112,8 @@ public void onInitialize() {
}
Config.TEMP_CONFIG.server = null;
});

if (Config.INSTANCE.getCheckUpdata()) updateChecker.start();
}

public void initDataBase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
public class ConfigStorage implements IConfig {
@Ignore
public static final ConfigStorage DEFAULT = new ConfigStorage(
true,
new ArrayList<>(),
new ArrayList<>(),
"zh_cn",
Expand All @@ -21,8 +22,9 @@ public class ConfigStorage implements IConfig {
"QuickBackupMulti"
);

private ArrayList<String> ignoredFiles;
private ArrayList<String> ignoredFolders;
private final boolean checkUpdate;
private final ArrayList<String> ignoredFiles;
private final ArrayList<String> ignoredFolders;
private String lang;
private boolean scheduleBackup;
private String scheduleCron;
Expand All @@ -34,9 +36,10 @@ public class ConfigStorage implements IConfig {

private boolean useInternalDataBase;
private String mongoDBUri;
private String storagePath;
private final String storagePath;

public ConfigStorage(
boolean checkUpdate,
ArrayList<String> IgnoredFiles,
ArrayList<String> ignoredFolders,
String lang,
Expand All @@ -49,6 +52,7 @@ public ConfigStorage(
boolean useInternalDataBase,
String mongoDBUri,
String storagePath) {
this.checkUpdate = checkUpdate;
this.ignoredFiles = IgnoredFiles;
this.ignoredFolders = ignoredFolders;
this.lang = lang;
Expand All @@ -63,22 +67,18 @@ public ConfigStorage(
this.storagePath = storagePath;
}

public ArrayList<String> getIgnoredFiles() {
return ignoredFiles;
public boolean isCheckUpedate() {
return checkUpdate;
}

public void setIgnoredFiles(ArrayList<String> ignoredFiles) {
this.ignoredFiles = ignoredFiles;
public ArrayList<String> getIgnoredFiles() {
return ignoredFiles;
}

public ArrayList<String> getIgnoredFolders() {
return ignoredFolders;
}

public void setIgnoredFolders(ArrayList<String> ignoredFolders) {
this.ignoredFolders = ignoredFolders;
}

public String getLang() {
return lang;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class QbmTempConfig {
public String worldName;
public @Nullable Scheduler scheduler;
public long latestScheduleExecuteTime;
public String modVersion;

public void setIsBackupValue(Boolean value) {
this.isBackup = value;
Expand Down Expand Up @@ -42,4 +43,8 @@ public void setScheduler(@NotNull Scheduler scheduler) {
public void setLatestScheduleExecuteTime(long time) {
this.latestScheduleExecuteTime = time;
}

public void setModVersion(String modVersion) {
this.modVersion = modVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ public void setConfigStorage(ConfigStorage configStorage) {
}
}

public boolean getCheckUpdata() {
synchronized (lock) {
return configStorage.isCheckUpedate();
}
}

public List<String> getIgnoredFiles() {
synchronized (lock) {
List<String> list = new ArrayList<>(configStorage.getIgnoredFiles());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.github.skydynamic.quickbackupmulti.mixin.client;

import io.github.skydynamic.quickbackupmulti.QuickBackupMulti;
import io.github.skydynamic.quickbackupmulti.utils.Messenger;
import io.github.skydynamic.quickbackupmulti.utils.UpdateChecker;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.MutableText;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import static io.github.skydynamic.quickbackupmulti.i18n.Translate.tr;

@Mixin(ClientPlayNetworkHandler.class)
public class ClientPlayNetworkHandlerMixin {
@Inject(
method = "onGameJoin",
at = @At("TAIL")
)
private void showUpdateMsg(GameJoinS2CPacket packet, CallbackInfo ci) {
if (MinecraftClient.getInstance().player == null) {
return;
}
UpdateChecker checker = QuickBackupMulti.updateChecker;
if (checker.needUpdate) {
ClientPlayerEntity player = MinecraftClient.getInstance().player;
MutableText updateText = Messenger.literal(
tr("quickbackupmulti.check_update.on_player_join", checker.latestVersion)
);
updateText.styled(style -> style
.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, checker.latestVersionHtmUrl))
.withHoverEvent(new HoverEvent(
HoverEvent.Action.SHOW_TEXT, Messenger.literal(tr("quickbackupmulti.check_update.click_tooltip"))
))
);
player.sendMessage(updateText, false);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.skydynamic.quickbackupmulti.mixin.client;

import io.github.skydynamic.quickbackupmulti.config.Config;
import io.github.skydynamic.quickbackupmulti.i18n.Translate;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.toast.ToastManager;
Expand All @@ -13,16 +12,18 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import static io.github.skydynamic.quickbackupmulti.i18n.Translate.tr;

@Mixin(MinecraftClient.class)
public class MinecraftClientMixin {
public abstract class MinecraftClientMixin {
@Shadow @Final
public ToastManager toastManager;

@Inject(method = "setScreen", at = @At("RETURN"))
private void inj(CallbackInfo ci) {
if (Config.TEMP_CONFIG.isBackup) {
Text title = Text.of(Translate.tr("quickbackupmulti.toast.start_title"));
Text content = Text.of(Translate.tr("quickbackupmulti.toast.start_content"));
Text title = Text.of(tr("quickbackupmulti.toast.start_title"));
Text content = Text.of(tr("quickbackupmulti.toast.start_content"));
//#if MC>=11800
SystemToast.show(this.toastManager, SystemToast.Type.PERIODIC_NOTIFICATION, title, content);
//#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
//#endif

public class Messenger {

public static void sendMessage(ServerCommandSource commandSource, Text text) {
//#if MC>=11900
commandSource.sendMessage(text);
Expand All @@ -24,5 +23,4 @@ public static MutableText literal(String string) {
//$$ return new LiteralText(string);
//#endif
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.github.skydynamic.quickbackupmulti.utils;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.github.skydynamic.quickbackupmulti.QuickBackupMulti;
import io.github.skydynamic.quickbackupmulti.config.Config;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

public class UpdateChecker extends Thread {

private static final HttpClient CLIENT = HttpClients.createDefault();
private static final String RELEASE_API_URL = "https://api.github.com/repos/QuickBackupMultiMod-Dev/QuickBackupM-Fabric/releases/latest";

public String latestVersion;
public String latestVersionHtmUrl;
public boolean needUpdate = false;

public UpdateChecker() {
super("QuickBackupM-Fabric-Update-Checker");
}

@Override
public void run() {
try {
if (Config.TEMP_CONFIG.modVersion == null) {
QuickBackupMulti.LOGGER.warn("Current mod version is not found.");
return;
}
HttpResponse httpResponse = CLIENT.execute(new HttpGet(RELEASE_API_URL));
String body = EntityUtils.toString(httpResponse.getEntity());

// Get Meta data
JsonObject jsonObject = JsonParser.parseString(body).getAsJsonObject();
latestVersion = jsonObject.get("tag_name").getAsString();
latestVersionHtmUrl = jsonObject.get("html_url").getAsString();

String tag = latestVersion
.replaceAll("\\+.*", "")
.replaceFirst("^v", "");
String currentVersion = Config.TEMP_CONFIG.modVersion
.replaceAll("\\+.*", "")
.replaceFirst("^v", "");

if (tag.compareTo(currentVersion) > 0) {
needUpdate = true;
QuickBackupMulti.LOGGER.info(
"{} has new version {}. You can see: {}", QuickBackupMulti.modName, latestVersion, latestVersionHtmUrl
);
}

} catch (IOException e) {
QuickBackupMulti.LOGGER.error("Check update failed", e);
}
}
}
4 changes: 4 additions & 0 deletions src/main/resources/assets/quickbackupmulti/lang/en_us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ quickbackupmulti:
empty_comment: §7Empty§r
list_empty: "§7Do not have any backups now"

check_update:
on_player_join: "§bQuickBackupMulti §rhas new release: §6%s"
click_tooltip: "Click to open release page"

config_page:
save_button: "Save Config"
close_button: "Close Screen"
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/assets/quickbackupmulti/lang/zh_cn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ quickbackupmulti:
empty_comment: §7空§r
list_empty: "§7当前没有任何备份"

check_update:
on_player_join: "检测到 §bQuickBackupMulti §r有新版本: §6%s"
click_tooltip: "点击这里打开新版本发布页面"

config_page:
save_button: "保存"
close_button: "关闭"
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/assets/quickbackupmulti/lang/zh_tw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ quickbackupmulti:
empty_comment: §7空§r
list_empty: "§7目前沒有任何備份"

check_update:
on_player_join: "§bQuickBackupMulti §rhas new release: §6%s"
click_tooltip: "Click to open release page"

config_page:
save_button: "儲存"
close_button: "關閉"
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/quickbackupmulti.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"server.MinecraftServerMixin"
],
"client": [
"client.ClientPlayNetworkHandlerMixin",
"client.MinecraftClientMixin",
"client.MinecraftServerMixin",
"client.TitleScreenMixin",
Expand Down

0 comments on commit fbb10a5

Please sign in to comment.