diff --git a/common/build.gradle.kts b/common/build.gradle.kts index a88ecd1..0303a00 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } group = "com.adamcalculator" -version = "1.0.13" +version = "1.0.14" repositories { mavenCentral() diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/DynamicPackModBase.java b/common/src/main/java/com/adamcalculator/dynamicpack/DynamicPackModBase.java index 76a56e4..d45ba02 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/DynamicPackModBase.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/DynamicPackModBase.java @@ -13,6 +13,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public abstract class DynamicPackModBase { @@ -21,9 +22,10 @@ public abstract class DynamicPackModBase { public static DynamicPackModBase INSTANCE; protected static int manuallySyncThreadCounter = 0; + public boolean rescanPacksBlocked = false; private boolean isPacksScanning = false; - private List packs = new ArrayList<>(); + private HashMap packs = new HashMap<>(); private File gameDir; private File resourcePacks; private boolean minecraftInitialized = false; @@ -54,9 +56,12 @@ public void rescanPacks() { Out.warn("rescanPacks already in scanning!"); return; } + if (rescanPacksBlocked) { + Out.warn("rescanPacks blocked"); + return; + } isPacksScanning = true; - packs.clear(); - + List forDelete = new ArrayList<>(packs.keySet()); for (File packFile : AFiles.lists(resourcePacks)) { try { PackUtil.openPackFileSystem(packFile, path -> { @@ -65,7 +70,8 @@ public void rescanPacks() { Out.println("+ Pack " + packFile.getName() + " supported by mod!"); try { processPack(packFile, PackUtil.readJson(dynamicPackPath)); - } catch (IOException e) { + forDelete.remove(packFile.getName()); + } catch (Exception e) { throw new RuntimeException(e); } } else { @@ -80,6 +86,10 @@ public void rescanPacks() { } } } + for (String s : forDelete) { + Out.println("Pack " + s + " no longer exists!"); + packs.remove(s); + } isPacksScanning = false; } @@ -87,9 +97,13 @@ public void rescanPacks() { private void processPack(File location, JSONObject json) { long formatVersion = json.getLong("formatVersion"); + Pack oldestPack = packs.getOrDefault(location.getName(), null); if (formatVersion == 1) { Pack pack = new Pack(location, json); - packs.add(pack); + if (oldestPack != null) { + pack.saveReScanData(oldestPack); + } + packs.put(location.getName(), pack); } else { throw new RuntimeException("Unsupported formatVersion: " + formatVersion); @@ -135,7 +149,7 @@ public File getGameDir() { } public Pack[] getPacks() { - return packs.toArray(new Pack[0]); + return packs.values().toArray(new Pack[0]); } public void minecraftInitialized() { diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java b/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java index 830d46e..843a1d2 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java @@ -8,12 +8,19 @@ import java.util.Set; public class Mod { + public static final String VERSION_NAME_MOD = "1.0.14"; + public static final String VERSION_NAME_BRANCH = "mc1.19.4"; + public static final String VERSION_NAME = VERSION_NAME_MOD + "-" + VERSION_NAME_BRANCH; + public static final long VERSION_BUILD = 14; + + // NOTE: for increase contact to mod developer. public static final long DYNAMIC_PACK_HTTPS_FILE_SIZE_LIMIT = megabyte(8); // kb -> mb -> 5MB (for files in resourcepack) public static final long MODRINTH_HTTPS_FILE_SIZE_LIMIT = megabyte(1024); // 1 GB (for .zip files from modrinth) public static final long MOD_MODTINTH_API_LIMIT = megabyte(8); // 8 MB of api public static final long GZIP_LIMIT = megabyte(50); // 50 MB of .gz file public static final long MOD_FILES_LIMIT = megabyte(8); + public static final String MODRINTH_URL = "https://modrinth.com/mod/dynamicpack"; private static final Set ALLOWED_HOSTS = new HashSet<>(); static { @@ -43,6 +50,8 @@ protected static void addAllowedHosts(String host, Object requester) throws Exce Out.securityWarning("# "); Out.securityWarning("# Host: " + host); Out.securityWarning("# Requester: " + requester); + Out.securityWarning("# StackTrace:"); + Out.securityStackTrace(); Out.securityWarning("# "); Out.securityWarning("==========================="); diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoRemote.java b/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoRemote.java index fb74540..3c4a3a7 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoRemote.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoRemote.java @@ -16,6 +16,7 @@ import java.nio.file.Path; import java.security.NoSuchAlgorithmException; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.LongConsumer; public class DynamicRepoRemote extends Remote { @@ -55,7 +56,6 @@ public void init(Pack pack, JSONObject remote, JSONObject current) { } } - if (skipSign != this.publicKey.isBlank()) { throw new RuntimeException("Incompatible parameters set. Select one of: sign_no_required or public_key"); } @@ -107,19 +107,21 @@ public String getCurrentPackContentHash(String id) { @Override - public boolean sync(PackSyncProgress progress, boolean manually) throws IOException, NoSuchAlgorithmException { + public boolean sync(PackSyncProgress progress, boolean manually) throws IOException { + AtomicBoolean returnValue = new AtomicBoolean(false); PackUtil.openPackFileSystem(parent.getLocation(), path -> { try { - sync0(progress, path); + boolean t = sync0(progress, path); + returnValue.set(t); - } catch (IOException | NoSuchAlgorithmException e) { + } catch (Exception e) { throw new RuntimeException(e); } }); - return true; + return returnValue.get(); } - public void sync0(PackSyncProgress progress, Path path) throws IOException, NoSuchAlgorithmException { + public boolean sync0(PackSyncProgress progress, Path path) throws IOException, NoSuchAlgorithmException { String packUrlContent; LongConsumer parseProgress = new FileDownloadConsumer() { @@ -144,6 +146,11 @@ public void onUpdate(FileDownloadConsumer it) { throw new RuntimeException("Incompatible formatVersion: " + formatVersion); } + long minBuildForWork; + if ((minBuildForWork = repoJson.optLong("minimal_mod_build", Mod.VERSION_BUILD)) > Mod.VERSION_BUILD) { + throw new RuntimeException("Incompatible DynamicPack Mod version for this pack: required minimal_mod_build=" + minBuildForWork + ", but currently mod build is " + Mod.VERSION_BUILD); + } + String remoteName = repoJson.getString("name"); if (!InputValidator.isPackNameValid(remoteName)) { throw new RuntimeException("Remote name of pack not valid."); @@ -163,6 +170,8 @@ public void onUpdate(FileDownloadConsumer it) { parent.updateJsonLatestUpdate(); AFiles.nioWriteText(path.resolve(DynamicPackModBase.CLIENT_FILE), parent.getPackJson().toString(2)); + + return dynamicRepoSyncProcessV1.isReloadRequired(); } public String getUrl() { diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoSyncProcessV1.java b/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoSyncProcessV1.java index d5421fb..8be9568 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoSyncProcessV1.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/pack/DynamicRepoSyncProcessV1.java @@ -23,6 +23,7 @@ public class DynamicRepoSyncProcessV1 { private final Set oldestFilesList = new HashSet<>(); private final Path packRootPath; + private boolean isReloadRequired = false; public DynamicRepoSyncProcessV1(Pack pack, DynamicRepoRemote dynamicRepoRemote, PackSyncProgress progress, JSONObject repoJson, Path path) { this.remote = dynamicRepoRemote; @@ -47,6 +48,7 @@ public void run() throws IOException { progress.textLog("File deleted from resource-pack: " + s); AFiles.nioSmartDelete(path); + markReloadRequired(); } try { @@ -140,6 +142,7 @@ private void processContentParsed(JSONObject jsonContent) throws IOException { continue; } + markReloadRequired(); this.progress.textLog("Overwriting: " + filePath); Urls.downloadDynamicFile(fileRemoteUrl, filePath, hash, new FileDownloadConsumer() { @Override @@ -199,4 +202,15 @@ private List calcActiveContents() { } return activeContents; } + + public boolean isReloadRequired() { + return isReloadRequired; + } + + private void markReloadRequired() { + if (!isReloadRequired) { + Out.debug("Now reload is required in " + this); + } + this.isReloadRequired = true; + } } diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java b/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java index 90ada74..5bd1f6e 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java @@ -2,6 +2,7 @@ import com.adamcalculator.dynamicpack.DynamicPackModBase; import com.adamcalculator.dynamicpack.PackUtil; +import com.adamcalculator.dynamicpack.status.StatusChecker; import com.adamcalculator.dynamicpack.sync.PackSyncProgress; import com.adamcalculator.dynamicpack.util.AFiles; import com.adamcalculator.dynamicpack.util.Out; @@ -28,6 +29,7 @@ public class Pack { private boolean cachedUpdateAvailable; private boolean isSyncing = false; private final String remoteTypeStr; + private Exception latestException; public Pack(File location, JSONObject json) { @@ -50,6 +52,12 @@ public boolean isSyncing() { return isSyncing; } + // See StatusChecker for this. + // Developer can block network for specify version in dynamicpack.status.v1.json by security questions + public boolean isNetworkBlocked() { + return StatusChecker.isBlockUpdating(remoteTypeStr); + } + public boolean isZip() { if (location.isDirectory()) { return false; @@ -84,6 +92,7 @@ public long getLatestUpdated() { } public boolean checkIsUpdateAvailable() throws IOException { + checkNetwork(); return cachedUpdateAvailable = remote.checkUpdateAvailable(); } @@ -95,9 +104,11 @@ public void sync(PackSyncProgress progress, boolean manually) throws Exception { try { sync0(progress, manually); checkSafePackMinecraftMeta(); + setLatestException(null); } catch (Exception e) { isSyncing = false; checkSafePackMinecraftMeta(); + setLatestException(e); throw e; } } @@ -108,6 +119,9 @@ private void sync0(PackSyncProgress progress, boolean manually) throws Exception progress.done(false); return; } + + checkNetwork(); + if (!checkIsUpdateAvailable() && !manually) { progress.textLog("update not available"); progress.done(false); @@ -124,6 +138,12 @@ private void sync0(PackSyncProgress progress, boolean manually) throws Exception progress.done(reloadRequired); } + private void checkNetwork() { + if (isNetworkBlocked()) { + throw new SecurityException("Network is blocked for remote_type=" + remoteTypeStr + " current version of mod not safe. Update mod!"); + } + } + private void checkSafePackMinecraftMeta() throws IOException { PackUtil.openPackFileSystem(location, path -> { Path mcmeta = path.resolve(DynamicPackModBase.MINECRAFT_META); @@ -154,4 +174,21 @@ private boolean checkMinecraftMetaIsValid(String s) { public String getRemoteType() { return remoteTypeStr; } + + public void setLatestException(Exception e) { + Out.debug(this + ": latestExcep="+e); + this.latestException = e; + } + + public Exception getLatestException() { + return latestException; + } + + public void saveReScanData(Pack oldestPack) { + if (oldestPack == null) return; + + if (this.latestException == null) { + this.latestException = oldestPack.latestException; + } + } } diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java b/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java new file mode 100644 index 0000000..87e7898 --- /dev/null +++ b/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java @@ -0,0 +1,53 @@ +package com.adamcalculator.dynamicpack.status; + +import com.adamcalculator.dynamicpack.Mod; +import com.adamcalculator.dynamicpack.util.Out; +import com.adamcalculator.dynamicpack.util.Urls; +import org.json.JSONObject; + +public class StatusChecker { + private static final String URL = "https://adamcalculator.github.io/DynamicPack/dynamicpack.status.v1.json"; + + + private static boolean isUpdateAvailable = false; + private static boolean isFormatActual = true; + private static boolean isSafe = true; + private static boolean isChecked = false; + + public static void check() throws Exception { + Out.println("Checking status..."); + String s = Urls.parseContent(URL, 1024 * 1024 * 128); + JSONObject j = new JSONObject(s); + JSONObject lat = j.getJSONObject("latest_version"); + isUpdateAvailable = lat.getLong("build") > Mod.VERSION_BUILD; + isSafe = lat.getLong("safe") <= Mod.VERSION_BUILD; + isFormatActual = lat.getLong("format") <= Mod.VERSION_BUILD; + + isChecked = true; + Out.println(String.format("Status checked! isSafe=%s, isFormatActual=%s, isUpdateAvailable=%s", isSafe, isFormatActual, isUpdateAvailable)); + } + + public static boolean isBlockUpdating(String remoteType) { + if (remoteType.equals("modrinth")) { + return false; + } + return !isSafe(); + } + + + public static boolean isModUpdateAvailable() { + return isUpdateAvailable; + } + + public static boolean isSafe() { + return isSafe; + } + + public static boolean isFormatActual() { + return isFormatActual; + } + + public static boolean isChecked() { + return isChecked; + } +} diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java index d8e2894..e01cf56 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java @@ -1,5 +1,8 @@ package com.adamcalculator.dynamicpack.sync; +import com.adamcalculator.dynamicpack.status.StatusChecker; +import com.adamcalculator.dynamicpack.util.Out; + import java.util.function.Supplier; public class SyncThread extends Thread { @@ -10,6 +13,9 @@ public class SyncThread extends Thread { public SyncThread(Supplier taskSupplier) { super("SyncThread" + (counter++)); + if (counter > 1) { + Out.warn("Multiple SyncThread's is bad behavior..."); + } this.taskSupplier = taskSupplier; } @@ -27,6 +33,11 @@ public void run() { private void startSync() { + try { + StatusChecker.check(); + } catch (Exception e) { + Out.error("Error while check status!", e); + } taskSupplier.get().run(); } } diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncingTask.java b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncingTask.java index a9e3234..cad5ca2 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncingTask.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncingTask.java @@ -32,6 +32,7 @@ public void run() { Out.println("SyncTask started!"); onSyncStart(); DynamicPackModBase.INSTANCE.rescanPacks(); + DynamicPackModBase.INSTANCE.rescanPacksBlocked = true; for (Pack pack : DynamicPackModBase.INSTANCE.getPacks()) { currentPack = pack; try { @@ -42,6 +43,7 @@ public void run() { onPackError(pack, e); } } + DynamicPackModBase.INSTANCE.rescanPacksBlocked = false; onSyncDone(reloadRequired); Out.println("SyncTask ended!"); isSyncing = false; diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java b/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java index cf627f6..60c912a 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java @@ -16,7 +16,7 @@ public static void println(Object o) { System.out.println(o); return; } - LOGGER.warn(o + ""); + LOGGER.info(o + ""); } public static void error(String s, Exception e) { @@ -66,4 +66,16 @@ public static void securityWarning(String s) { public static void debug(String s) { println("DEBUG: " + s); } + + /** + * Always enable! Ignore enable/disable + */ + public static void securityStackTrace() { + if (USE_SOUT) { + System.out.println("[dynamicpack] Stacktrace"); + new Throwable("StackTrace printer").printStackTrace(); + return; + } + LOGGER.error("No error. This is stacktrace printer", new Throwable("StackTrace printer")); + } } diff --git a/gradle.properties b/gradle.properties index ff2aa88..a7edea2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,6 +12,6 @@ loader_version=0.15.7 fabric_version=0.87.2+1.19.4 # Mod Properties -mod_version=1.0.13-mc1.19.4 +mod_version=1.0.14-mc1.19.4 maven_group=com.adamcalculator archives_base_name=dynamicpack \ No newline at end of file diff --git a/src/client/java/com/adamcalculator/dynamicpack/DynamicPackScreen.java b/src/client/java/com/adamcalculator/dynamicpack/DynamicPackScreen.java index 4153ad4..4a51a4e 100644 --- a/src/client/java/com/adamcalculator/dynamicpack/DynamicPackScreen.java +++ b/src/client/java/com/adamcalculator/dynamicpack/DynamicPackScreen.java @@ -1,8 +1,11 @@ package com.adamcalculator.dynamicpack; import com.adamcalculator.dynamicpack.pack.Pack; +import com.adamcalculator.dynamicpack.sync.SyncingTask; +import com.terraformersmc.modmenu.util.DrawingUtil; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; @@ -14,6 +17,7 @@ public class DynamicPackScreen extends Screen { private final Screen parent; private final Pack pack; private final Text screenDescText; + private ButtonWidget syncButton; public DynamicPackScreen(Screen parent, Pack pack) { super(Text.literal(pack.getName()).formatted(Formatting.BOLD)); @@ -24,19 +28,25 @@ public DynamicPackScreen(Screen parent, Pack pack) { } @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - renderBackground(matrixStack); - drawTextWithShadow(matrixStack, this.textRenderer, this.title, 20, 8, 16777215); - drawTextWithShadow(matrixStack, this.textRenderer, screenDescText, 20, 20, 16777215); - drawTextWithShadow(matrixStack, this.textRenderer, Text.translatable("dynamicpack.screen.pack.remote_type", pack.getRemoteType()), 20, 36, 16777215); - drawTextWithShadow(matrixStack, this.textRenderer, Text.translatable("dynamicpack.screen.pack.latestUpdated", pack.getLatestUpdated() < 0 ? "-" : new Date(pack.getLatestUpdated() * 1000)), 20, 52, 16777215); - - super.render(matrixStack, mouseX, mouseY, delta); + public void render(MatrixStack context, int mouseX, int mouseY, float delta) { + renderBackground(context); + syncButton.active = !SyncingTask.isSyncing; + int h = 20; + context.drawTextWithShadow(this.textRenderer, this.title, 20, 8, 16777215); + context.drawTextWithShadow(this.textRenderer, screenDescText, 20, 20 + h, 16777215); + context.drawTextWithShadow(this.textRenderer, Text.translatable("dynamicpack.screen.pack.remote_type", pack.getRemoteType()), 20, 36 + h, 16777215); + context.drawTextWithShadow(this.textRenderer, Text.translatable("dynamicpack.screen.pack.latestUpdated", pack.getLatestUpdated() < 0 ? "-" : new Date(pack.getLatestUpdated() * 1000)), 20, 52 + h, 16777215); + + if (pack.getLatestException() != null) { + DrawingUtil.drawWrappedString(context, Text.translatable("dynamicpack.screen.pack.latestException", pack.getLatestException().getMessage()).asTruncatedString(9999), 20, 78 + h, 500, 99, 0xff2222); + } + + super.render(context, mouseX, mouseY, delta); } @Override protected void init() { - addDrawableChild(Compat.createButton( + addDrawableChild(syncButton = Compat.createButton( Text.translatable("dynamicpack.screen.pack.manually_sync"), () -> { DynamicPackModBase.INSTANCE.startManuallySync(); diff --git a/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java b/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java index d253bd6..95c05c1 100644 --- a/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java +++ b/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java @@ -1,23 +1,30 @@ package com.adamcalculator.dynamicpack; import com.adamcalculator.dynamicpack.pack.Pack; +import com.adamcalculator.dynamicpack.status.StatusChecker; import com.adamcalculator.dynamicpack.sync.SyncThread; import com.adamcalculator.dynamicpack.sync.SyncingTask; import com.adamcalculator.dynamicpack.sync.state.StateDownloading; import com.adamcalculator.dynamicpack.sync.state.StateFileDeleted; import com.adamcalculator.dynamicpack.sync.state.SyncProgressState; +import com.adamcalculator.dynamicpack.util.Out; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.SharedConstants; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.ToastManager; import net.minecraft.resource.metadata.PackResourceMetadataReader; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.JsonHelper; public class FabricDynamicMod extends DynamicPackModBase implements ClientModInitializer { - private static final boolean SHOW_STATE = false; private SystemToast toast = null; private long toastUpdated = 0; @@ -40,6 +47,37 @@ public void setToastContent(Text title, Text text) { public void onInitializeClient() { var gameDir = FabricLoader.getInstance().getGameDir().toFile(); init(gameDir); + + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + ClientPlayerEntity player = client.player; + Text download = Text.translatable("dynamicpack.status_checker.download") + .fillStyle(Style.EMPTY + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("dynamicpack.status_checker.download.hover", Text.literal(Mod.MODRINTH_URL).formatted(Formatting.UNDERLINE, Formatting.AQUA)))) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, Mod.MODRINTH_URL)) + ) + .formatted(Formatting.YELLOW, Formatting.UNDERLINE); + + + if (player == null) { + Out.warn("player == null on world join"); + + } else if (!StatusChecker.isSafe()) { + player.sendMessage(Text.translatable("dynamicpack.status_checker.not_safe", download)); + setToastContent(Text.translatable("dynamicpack.status_checker.not_safe.toast.title"), + Text.translatable("dynamicpack.status_checker.not_safe.toast.description")); + + } else if (!StatusChecker.isFormatActual()) { + player.sendMessage(Text.translatable("dynamicpack.status_checker.format_not_actual", download)); + + } else if (StatusChecker.isModUpdateAvailable()) { + Out.println("DynamicPack mod update available: " + Mod.MODRINTH_URL); + + } else if (!StatusChecker.isChecked()) { + Out.warn("StatusChecker isChecked = false :("); + } else { + Out.println("Mod in actual state in current date!"); + } + }); } @Override diff --git a/src/client/java/com/adamcalculator/dynamicpack/PackMixinHelper.java b/src/client/java/com/adamcalculator/dynamicpack/PackMixinHelper.java index 27fd04b..779632d 100644 --- a/src/client/java/com/adamcalculator/dynamicpack/PackMixinHelper.java +++ b/src/client/java/com/adamcalculator/dynamicpack/PackMixinHelper.java @@ -1,6 +1,7 @@ package com.adamcalculator.dynamicpack; import com.adamcalculator.dynamicpack.pack.Pack; +import com.adamcalculator.dynamicpack.sync.SyncingTask; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.pack.PackListWidget; import net.minecraft.client.util.math.MatrixStack; @@ -8,21 +9,28 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public class PackMixinHelper { + private static final Identifier BUTTON_TEXTURE = Identifier.of("dynamicpack", "select_button.png"); + private static final Identifier BUTTON_WARNING_TEXTURE = Identifier.of("dynamicpack", "select_button_warning.png"); + public static void renderResourcePackEntry(Object resourcePackEntryMixin, MatrixStack context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta, CallbackInfo ci) { PackListWidget.ResourcePackEntry entry = (PackListWidget.ResourcePackEntry) resourcePackEntryMixin; - if (DynamicPackModBase.INSTANCE.isNameIsDynamic(entry.getName())) { + Pack pack = DynamicPackModBase.INSTANCE.getDynamicPackByMinecraftName(entry.getName()); + if (pack != null && !SyncingTask.isSyncing) { int i = mouseX - x; int j = mouseY - y; - + // TODO(adam) 2024.03.20: INDICATOR NOT WORKING IN 1.19.4 BACKPORT... //DrawableHelper.drawTexture(context, Identifier.of("dynamicpack", "select_button.png"), x + 174, y+16, 0.0F, ((i >= 174 && j >= 16 && hovered) ? 16f : 0f), 16, 16, 16, 32); + + context.drawTexture(pack.getLatestException() != null ? BUTTON_WARNING_TEXTURE : BUTTON_TEXTURE, x + 174, y+16, 0.0F, ((i >= 174 && j >= 16 && hovered) ? 16f : 0f), 16, 16, 16, 32); + } } public static void mouseClicked(Object resourcePackEntryMixin, PackListWidget widget, double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { PackListWidget.ResourcePackEntry entry = (PackListWidget.ResourcePackEntry) resourcePackEntryMixin; Pack pack = DynamicPackModBase.INSTANCE.getDynamicPackByMinecraftName(entry.getName()); - if (pack != null) { + if (pack != null && !SyncingTask.isSyncing) { double d = mouseX - (double)widget.getRowLeft(); double e = mouseY - (double)widget.getRowTop(widget.children().indexOf(entry)); diff --git a/src/main/resources/assets/dynamicpack/icon.png b/src/main/resources/assets/dynamicpack/icon.png index 57e7f86..57f3f24 100644 Binary files a/src/main/resources/assets/dynamicpack/icon.png and b/src/main/resources/assets/dynamicpack/icon.png differ diff --git a/src/main/resources/assets/dynamicpack/lang/en_us.json b/src/main/resources/assets/dynamicpack/lang/en_us.json index 2b1c715..55f67fb 100644 --- a/src/main/resources/assets/dynamicpack/lang/en_us.json +++ b/src/main/resources/assets/dynamicpack/lang/en_us.json @@ -16,5 +16,12 @@ "dynamicpack.screen.pack.description": "This resource pack support DynamicPack features!", "dynamicpack.screen.pack.remote_type": "Remote type: %s", "dynamicpack.screen.pack.latestUpdated": "Latest updated at: %s", - "dynamicpack.screen.pack.manually_sync": "Manually sync" + "dynamicpack.screen.pack.latestException": "Latest error on this pack: %s\nFor details see game logs", + "dynamicpack.screen.pack.manually_sync": "Manually sync", + "dynamicpack.status_checker.not_safe": "Security update available for DynamicPack mod! This message should not be ignored, since the update has fixed possible vulnerabilities: %s", + "dynamicpack.status_checker.not_safe.toast.title": "DynamicPack", + "dynamicpack.status_checker.not_safe.toast.description": "Security update available", + "dynamicpack.status_checker.format_not_actual": "Dynamic pack format update available! Perhaps resource pack developers will use it, and then without updating the mod they will stop working: %s", + "dynamicpack.status_checker.download": "Download!", + "dynamicpack.status_checker.download.hover": "Click for go to %s" } \ No newline at end of file diff --git a/src/main/resources/assets/dynamicpack/lang/ru_ru.json b/src/main/resources/assets/dynamicpack/lang/ru_ru.json index 804c1ae..5c2ed1e 100644 --- a/src/main/resources/assets/dynamicpack/lang/ru_ru.json +++ b/src/main/resources/assets/dynamicpack/lang/ru_ru.json @@ -16,6 +16,12 @@ "dynamicpack.screen.pack.description": "Этот ресурспак поддерживает возможности мода DynamicPack!", "dynamicpack.screen.pack.remote_type": "Тип: %s", "dynamicpack.screen.pack.latestUpdated": "Обновлён: %s", - "dynamicpack.screen.pack.manually_sync": "Синхр. вручную" - + "dynamicpack.screen.pack.latestException": "Последняя ошибка в паке: %s\nДля дополнительного смотрите логи", + "dynamicpack.screen.pack.manually_sync": "Синхр. вручную", + "dynamicpack.status_checker.not_safe": "Доступно обновление безопасности для мода DynamicPack! Это сообщение не стоит игнорировать, поскольку в обновлении были исправлены возможные уязвимости: %s", + "dynamicpack.status_checker.not_safe.toast.title": "DynamicPack", + "dynamicpack.status_checker.not_safe.toast.description": "Доступно обновление безопасности", + "dynamicpack.status_checker.format_not_actual": "Доступно обновление формата динамических паков! Возможно разработчики ресурспаков будут его использовать, и тогда без обновления мода они работать перестанут: %s", + "dynamicpack.status_checker.download": "Загрузить!", + "dynamicpack.status_checker.download.hover": "Нажмите чтобы перейти %s" } \ No newline at end of file diff --git a/src/main/resources/assets/dynamicpack/select_button.png b/src/main/resources/assets/dynamicpack/select_button.png index 4810abf..d3e8e08 100644 Binary files a/src/main/resources/assets/dynamicpack/select_button.png and b/src/main/resources/assets/dynamicpack/select_button.png differ diff --git a/src/main/resources/assets/dynamicpack/select_button_warning.png b/src/main/resources/assets/dynamicpack/select_button_warning.png new file mode 100644 index 0000000..f538b3a Binary files /dev/null and b/src/main/resources/assets/dynamicpack/select_button_warning.png differ