-
Notifications
You must be signed in to change notification settings - Fork 27
Add DayZ workshop mod updates #280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
92d094e
b6604e2
39f93ce
2c6f735
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| /* | ||
| * Copyright (c) 2024 Osiris-Team. | ||
| * All rights reserved. | ||
| * | ||
| * This software is copyrighted work, licensed under the terms | ||
| * of the MIT-License. Consult the "LICENSE" file for details. | ||
| */ | ||
|
|
||
| package com.osiris.autoplug.client.tasks.updater.mods; | ||
|
|
||
| import com.osiris.autoplug.client.tasks.updater.search.SearchResult; | ||
|
|
||
| interface ModDownloadTask { | ||
| void start(); | ||
|
|
||
| boolean isAlive(); | ||
|
|
||
| String getPlName(); | ||
|
|
||
| SearchResult getSearchResult(); | ||
|
|
||
| boolean isDownloadSuccessful(); | ||
|
|
||
| boolean isInstallSuccessful(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| /* | ||
| * Copyright (c) 2024 Osiris-Team. | ||
| * All rights reserved. | ||
| * | ||
| * This software is copyrighted work, licensed under the terms | ||
| * of the MIT-License. Consult the "LICENSE" file for details. | ||
| */ | ||
|
|
||
| package com.osiris.autoplug.client.tasks.updater.mods; | ||
|
|
||
| import org.jetbrains.annotations.NotNull; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.IOException; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.nio.file.Files; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Comparator; | ||
| import java.util.List; | ||
|
|
||
| public class SteamWorkshopMod extends MinecraftMod { | ||
| private final File directory; | ||
| private String publishedId; | ||
| private final String timestamp; | ||
|
|
||
| public SteamWorkshopMod(File directory, String name, String publishedId) { | ||
| this(directory, name, publishedId, null); | ||
| } | ||
|
|
||
| public SteamWorkshopMod(File directory, String name, String publishedId, String timestamp) { | ||
| super(directory.getAbsolutePath(), name, timestamp != null ? timestamp : publishedId, "Steam Workshop", null, null, null); | ||
| this.directory = directory; | ||
| this.publishedId = publishedId; | ||
| this.timestamp = timestamp; | ||
| } | ||
|
|
||
| public File getDirectory() { | ||
| return directory; | ||
| } | ||
|
|
||
| public String getPublishedId() { | ||
| return publishedId; | ||
| } | ||
|
|
||
| public void setPublishedId(String publishedId) { | ||
| this.publishedId = publishedId; | ||
| if (getVersion() == null) | ||
| setVersion(publishedId); | ||
| } | ||
|
|
||
| public String getTimestamp() { | ||
| return timestamp; | ||
| } | ||
|
|
||
| @NotNull | ||
| public static List<SteamWorkshopMod> findIn(File dir) throws IOException { | ||
| if (!dir.exists()) throw new FileNotFoundException("Directory does not exist: " + dir); | ||
| List<SteamWorkshopMod> mods = new ArrayList<>(); | ||
| File[] files = dir.listFiles(); | ||
| if (files == null) return mods; | ||
| Arrays.sort(files, Comparator.comparing(File::getName)); | ||
| for (File file : files) { | ||
| if (!file.isDirectory()) continue; | ||
| File metaFile = new File(file, "meta.cpp"); | ||
| if (metaFile.exists()) | ||
| mods.add(readFromMeta(file, metaFile)); | ||
| } | ||
| return mods; | ||
| } | ||
|
|
||
| static SteamWorkshopMod readFromMeta(File modDir, File metaFile) throws IOException { | ||
| String name = modDir.getName(); | ||
| String publishedId = null; | ||
| String timestamp = null; | ||
| for (String line : Files.readAllLines(metaFile.toPath(), StandardCharsets.UTF_8)) { | ||
| String trimmedLine = line.trim(); | ||
| if (trimmedLine.isEmpty() || trimmedLine.startsWith("//")) continue; | ||
|
|
||
| int equalsIndex = trimmedLine.indexOf('='); | ||
| if (equalsIndex < 0) continue; | ||
|
|
||
| String key = trimmedLine.substring(0, equalsIndex).trim(); | ||
| String value = trimmedLine.substring(equalsIndex + 1).trim(); | ||
| int semicolonIndex = value.indexOf(';'); | ||
| if (semicolonIndex < 0) continue; | ||
| value = value.substring(0, semicolonIndex).trim(); | ||
| if (value.startsWith("\"") && value.endsWith("\"") && value.length() >= 2) | ||
| value = value.substring(1, value.length() - 1); | ||
|
|
||
| if (key.equals("name")) name = value; | ||
| if (key.equals("publishedid")) publishedId = value; | ||
| if (key.equals("timestamp")) timestamp = value; | ||
| } | ||
|
|
||
| if (publishedId == null || !publishedId.matches("\\d+")) | ||
| throw new IOException("Failed to read publishedid from " + metaFile); | ||
|
|
||
| return new SteamWorkshopMod(modDir, name, publishedId, timestamp); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| import com.osiris.autoplug.client.tasks.updater.plugins.ResourceFinder; | ||
| import com.osiris.autoplug.client.tasks.updater.search.SearchResult; | ||
| import com.osiris.autoplug.client.utils.GD; | ||
| import com.osiris.autoplug.client.utils.SteamCMD; | ||
| import com.osiris.autoplug.client.utils.UtilsFile; | ||
| import com.osiris.autoplug.client.utils.UtilsMinecraft; | ||
| import com.osiris.betterthread.BThread; | ||
|
|
@@ -40,7 +41,7 @@ public class TaskModsUpdater extends BThread { | |
| private final String manualProfile = "MANUAL"; | ||
| private final String automaticProfile = "AUTOMATIC"; | ||
| private final int updatesDownloaded = 0; | ||
| private final List<TaskModDownload> downloadTasksList = new ArrayList<>(); | ||
| private final List<ModDownloadTask> downloadTasksList = new ArrayList<>(); | ||
| @NotNull | ||
| private final List<MinecraftMod> includedMods = new ArrayList<>(); | ||
| @NotNull | ||
|
|
@@ -81,7 +82,9 @@ public void runAtStart() throws Exception { | |
| setStatus("Fetching latest mod data..."); | ||
|
|
||
| userProfile = updaterConfig.mods_updater_profile.asString(); | ||
| this.allMods.addAll(new UtilsMinecraft().getMods(FileManager.convertRelativeToAbsolutePath(updaterConfig.mods_updater_path.asString()))); | ||
| File modsDir = FileManager.convertRelativeToAbsolutePath(updaterConfig.mods_updater_path.asString()); | ||
| this.allMods.addAll(new UtilsMinecraft().getMods(modsDir)); | ||
| this.allMods.addAll(SteamWorkshopMod.findIn(modsDir)); | ||
|
|
||
| for (MinecraftMod installedMod : | ||
| allMods) { | ||
|
|
@@ -96,6 +99,7 @@ public void runAtStart() throws Exception { | |
| YamlSection author = modsConfig.put(name, plName, "author").setDefValues(installedMod.getAuthor()); | ||
| YamlSection modrinthId = modsConfig.put(name, plName, "modrinth-id"); | ||
| YamlSection curseforgeId = modsConfig.put(name, plName, "curseforge-id"); | ||
| YamlSection steamWorkshopId = modsConfig.put(name, plName, "steam-workshop-id"); | ||
| YamlSection ignoreContentType = modsConfig.put(name, plName, "ignore-content-type").setDefValues("false"); | ||
| YamlSection forceLatest = modsConfig.put(name, plName, "force-latest").setDefValues("false"); | ||
| YamlSection forceUpdate = modsConfig.put(name, plName, "force-update").setDefValues("false"); | ||
|
|
@@ -111,6 +115,8 @@ public void runAtStart() throws Exception { | |
| modrinthId.setValues(installedMod.modrinthId); | ||
| if (installedMod.curseforgeId != null && curseforgeId.asString() == null) | ||
| curseforgeId.setValues(installedMod.curseforgeId); | ||
| if (installedMod instanceof SteamWorkshopMod) | ||
| steamWorkshopId.setValues(((SteamWorkshopMod) installedMod).getPublishedId()); | ||
|
|
||
| // Update the detailed mods in-memory values | ||
| installedMod.modrinthId = (modrinthId.asString()); | ||
|
|
@@ -125,6 +131,15 @@ public void runAtStart() throws Exception { | |
| installedMod.jenkinsArtifactName = (jenkinsArtifactName.asString()); | ||
| installedMod.jenkinsBuildId = (jenkinsBuildId.asInt()); | ||
| installedMod.forceUpdate = forceUpdate.asBoolean(); | ||
| if (installedMod instanceof SteamWorkshopMod) { | ||
| ((SteamWorkshopMod) installedMod).setPublishedId(steamWorkshopId.asString()); | ||
| installedMod.setVersion(version.asString()); | ||
| if (exclude.asBoolean()) | ||
| excludedMods.add(installedMod); | ||
| else | ||
| includedMods.add(installedMod); | ||
| continue; | ||
| } | ||
|
|
||
| // Check for missing author in internal config | ||
| if ((installedMod.getVersion() == null) | ||
|
|
@@ -184,10 +199,10 @@ public void runAtStart() throws Exception { | |
| int sizeBukkitMods = 0; | ||
| int sizeUnknownMods = 0; | ||
| int sizeCustomMods = 0; | ||
|
|
||
| int sizeSteamWorkshopMods = 0; | ||
|
|
||
| String mcVersion = updaterConfig.mods_updater_version.asString(); | ||
| if (mcVersion == null) updaterConfig.server_updater_version.asString(); | ||
| if (mcVersion == null) mcVersion = updaterConfig.server_updater_version.asString(); | ||
| if (mcVersion == null) mcVersion = Server.getMCVersion(); | ||
|
|
||
| ExecutorService executorService; | ||
|
|
@@ -201,7 +216,10 @@ public void runAtStart() throws Exception { | |
| includedMods) { | ||
| try { | ||
| setStatus("Initialising update check for " + mod.getName() + "..."); | ||
| if (mod.customCheckURL != null) { // Custom Check | ||
| if (mod instanceof SteamWorkshopMod) { | ||
| sizeSteamWorkshopMods++; | ||
| activeFutures.add(executorService.submit(() -> findSteamWorkshopUpdate((SteamWorkshopMod) mod))); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please extract findSteamWorkshopUpdate (and related functions) into another class and use it via ResourceFinder like the other existing code does. please also do this for anything else and try to stay close to the file/class structure/organization of existing code. |
||
| } else if (mod.customCheckURL != null) { // Custom Check | ||
| sizeCustomMods++; | ||
| activeFutures.add(executorService.submit(() -> new ResourceFinder().findByCustomCheckURL(mod))); | ||
| } else if (mod.jenkinsProjectUrl != null) { // JENKINS MOD | ||
|
|
@@ -272,12 +290,13 @@ else if (code == SearchResult.Type.RESOURCE_NOT_FOUND) | |
| } | ||
| } | ||
| } | ||
| executorService.shutdown(); | ||
|
|
||
| // Wait until all download tasks have finished. | ||
| while (!downloadTasksList.isEmpty()) { | ||
| Thread.sleep(1000); | ||
| TaskModDownload download = null; | ||
| for (TaskModDownload task : | ||
| ModDownloadTask download = null; | ||
| for (ModDownloadTask task : | ||
| downloadTasksList) { | ||
| if (!task.isAlive()) { | ||
| download = task; | ||
|
|
@@ -305,10 +324,10 @@ else if (code == SearchResult.Type.RESOURCE_NOT_FOUND) | |
| matchingResult.type = SearchResult.Type.UPDATE_INSTALLED; | ||
| YamlSection jenkinsBuildId = modsConfig.get( | ||
| modsConfigName, download.getPlName(), "alternatives", "jenkins", "build-id"); | ||
| jenkinsBuildId.setValues(String.valueOf(download.searchResult.jenkinsId)); | ||
| jenkinsBuildId.setValues(String.valueOf(download.getSearchResult().jenkinsId)); | ||
| YamlSection version = modsConfig.get( | ||
| modsConfigName, download.getPlName(), "version"); | ||
| version.setValues(download.searchResult.getLatestVersion()); | ||
| version.setValues(download.getSearchResult().getLatestVersion()); | ||
| } | ||
|
|
||
| } | ||
|
|
@@ -337,6 +356,63 @@ else if (code == SearchResult.Type.RESOURCE_NOT_FOUND) | |
|
|
||
| } | ||
|
|
||
| private SearchResult findSteamWorkshopUpdate(@NotNull SteamWorkshopMod mod) { | ||
| SearchResult result = new SearchResult(null, SearchResult.Type.UP_TO_DATE, mod.getVersion(), null, "steam-workshop", null, null, false); | ||
| result.mod = mod; | ||
| String workshopAppId = getWorkshopAppId(); | ||
| if (workshopAppId == null) { | ||
| result.type = SearchResult.Type.API_ERROR; | ||
| result.setException(new Exception("Steam Workshop mod '" + mod.getName() + "' was found, but server-updater.software is not a numeric Steam app-id.")); | ||
| return result; | ||
| } | ||
|
|
||
| try { | ||
| SteamCMD.SteamWorkshopItemDetails details = createSteamCMD().getWorkshopItemDetails(mod.getPublishedId()); | ||
| result.latestVersion = details.getTimeUpdated(); | ||
| result.downloadUrl = details.getFileUrl(); | ||
| if (hasSteamWorkshopUpdate(mod, details.getTimeUpdated())) | ||
| result.type = SearchResult.Type.UPDATE_AVAILABLE; | ||
| } catch (Exception e) { | ||
| result.type = SearchResult.Type.API_ERROR; | ||
| result.setException(e); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| private String getWorkshopAppId() { | ||
| String workshopAppId = updaterConfig.server_software.asString(); | ||
| if (workshopAppId == null || !workshopAppId.matches("\\d+")) | ||
| return null; | ||
| return workshopAppId; | ||
| } | ||
|
|
||
| private boolean hasSteamWorkshopUpdate(SteamWorkshopMod mod, String latestVersion) { | ||
| if (latestVersion == null || latestVersion.isEmpty()) | ||
| return false; | ||
| String currentVersion = mod.getVersion(); | ||
| if (currentVersion == null || currentVersion.isEmpty()) | ||
| return true; | ||
| if (latestVersion.equals(currentVersion)) | ||
| return false; | ||
| if (currentVersion.equals(mod.getPublishedId())) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Im not sure how this (line 397) makes sense, can you explain? |
||
| return true; | ||
| if (isSteamUnixTimestamp(latestVersion) && !isSteamUnixTimestamp(currentVersion)) | ||
| return true; | ||
| try { | ||
| return Long.parseLong(latestVersion) > Long.parseLong(currentVersion); | ||
| } catch (NumberFormatException e) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| private boolean isSteamUnixTimestamp(String version) { | ||
| return version != null && version.matches("\\d{1,10}"); | ||
| } | ||
|
|
||
| SteamCMD createSteamCMD() { | ||
| return new SteamCMD(); | ||
| } | ||
|
|
||
| private void doDownloadLogic(@NotNull MinecraftMod mod, SearchResult result) { | ||
| SearchResult.Type code = result.type; | ||
| String type = result.getDownloadType(); // The file type to download (Note: When 'external' is returned nothing will be downloaded. Working on a fix for this!) | ||
|
|
@@ -361,8 +437,25 @@ private void doDownloadLogic(@NotNull MinecraftMod mod, SearchResult result) { | |
| } | ||
|
|
||
| if (userProfile.equals(notifyProfile)) { | ||
| addInfo("NOTIFY: Mod '" + mod.getName() + "' has an update available (" + mod.getVersion() + " -> " + latest + "). Download url: " + downloadUrl); | ||
| if (mod instanceof SteamWorkshopMod) | ||
| addInfo("NOTIFY: Steam Workshop mod '" + mod.getName() + "' has an update available (" + mod.getVersion() + " -> " + latest + ")."); | ||
| else | ||
| addInfo("NOTIFY: Mod '" + mod.getName() + "' has an update available (" + mod.getVersion() + " -> " + latest + "). Download url: " + downloadUrl); | ||
| } else { | ||
| if (mod instanceof SteamWorkshopMod) { | ||
| String workshopAppId = getWorkshopAppId(); | ||
| if (workshopAppId == null) { | ||
| getWarnings().add(new BWarning(this, new Exception("Steam Workshop mod '" + mod.getName() + "' was found, but server-updater.software is not a numeric Steam app-id."))); | ||
| return; | ||
| } | ||
|
|
||
| TaskSteamWorkshopModDownload task = new TaskSteamWorkshopModDownload("SteamWorkshopModDownloader", getManager(), | ||
| (SteamWorkshopMod) mod, workshopAppId, userProfile, createSteamCMD(), result); | ||
| downloadTasksList.add(task); | ||
| task.start(); | ||
| return; | ||
| } | ||
|
|
||
| // Make sure that plName and plLatestVersion do not contain any slashes (/ or \) that could break the file name | ||
| UtilsFile utilsFile = new UtilsFile(); | ||
| mod.setName(utilsFile.getValidFileName(mod.getName())); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.