From f7da85074d143e02d42377c70b4579a19d2960f3 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 1 Jul 2024 12:46:30 +0200 Subject: [PATCH] v3.12 dev. progress Early prototype for quick-share GUI. Missing error handlers for now. --- .../betterstats/BetterStatsConfig.java | 17 --- .../gui/screen/QuickShareDownloadScreen.java | 140 ++++++++++++------ .../client/gui/screen/QuickShareScreen.java | 7 +- .../gui/screen/QuickShareUploadScreen.java | 42 +++++- .../gui/stats/tabs/BSStatsSharingTab.java | 17 +-- .../github/thecsdev/betterstats/util/BST.java | 14 ++ .../tcdcommons-3.12+fabric-1.20.6.jar | Bin 846491 -> 846578 bytes .../assets/betterstats/lang/en_us.json | 14 +- .../betterstats/BetterStatsConfig.java | 17 --- .../gui/screen/QuickShareDownloadScreen.java | 140 ++++++++++++------ .../client/gui/screen/QuickShareScreen.java | 7 +- .../gui/screen/QuickShareUploadScreen.java | 42 +++++- .../gui/stats/tabs/BSStatsSharingTab.java | 17 +-- .../github/thecsdev/betterstats/util/BST.java | 14 ++ .../tcdcommons-3.12+fabric-1.21.jar | Bin 846706 -> 846793 bytes .../assets/betterstats/lang/en_us.json | 17 ++- 16 files changed, 352 insertions(+), 153 deletions(-) diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/BetterStatsConfig.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/BetterStatsConfig.java index b8705bd..fb6cfa1 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/BetterStatsConfig.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/BetterStatsConfig.java @@ -7,8 +7,6 @@ public class BetterStatsConfig extends AutoConfig { - // ================================================== - private static @NonSerialized boolean FULL_VERSION = false; // ================================================== public static @NonSerialized boolean DEBUG_MODE = false; // -------------------------------------------------- @@ -22,20 +20,5 @@ public class BetterStatsConfig extends AutoConfig public @SerializedAs("server-sasConfig") SASConfig sasConfig = new SASConfig(); // ================================================== public BetterStatsConfig(String name) { super(name); } - static - { - //check for the "full version" file's presence - try - { - final var s = BetterStats.class.getResourceAsStream("/betterstats.full.txt"); - if(s != null) { s.close(); FULL_VERSION = true; } - } - catch(Exception e) { FULL_VERSION = true; } - } - // ================================================== - /** - * Returns {@code true} if all features should always be available. - */ - public final boolean isFullVersion() { return FULL_VERSION || this.forceFullVersion; } // ================================================== } \ No newline at end of file diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareDownloadScreen.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareDownloadScreen.java index 400a904..b20bebd 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareDownloadScreen.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareDownloadScreen.java @@ -9,6 +9,7 @@ import java.time.Instant; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.io.IOUtils; import org.apache.http.Header; @@ -24,8 +25,10 @@ import io.github.thecsdev.betterstats.api.client.gui.screen.BetterStatsScreen; import io.github.thecsdev.betterstats.api.util.io.RAMStatsProvider; +import io.github.thecsdev.betterstats.util.BST; import io.github.thecsdev.betterstats.util.io.BetterStatsWebApiUtils; -import io.github.thecsdev.tcdcommons.api.util.TextUtils; +import io.github.thecsdev.tcdcommons.api.client.gui.other.TLabelElement; +import io.github.thecsdev.tcdcommons.api.util.enumerations.HorizontalAlignment; import io.github.thecsdev.tcdcommons.api.util.io.HttpUtils.FetchOptions; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResource; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResourceManager; @@ -39,16 +42,18 @@ public class QuickShareDownloadScreen extends QuickShareScreen { // ================================================== - private @Internal final String quickShareCode; + private @Nullable Screen bssParent; + private final String quickShareCode; // -------------------------------------------------- private @Internal volatile boolean __started = false; private @Internal volatile int __stage = 0; private @Internal volatile Throwable __error = null; // ================================================== - public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) + public QuickShareDownloadScreen(@Nullable Screen bssParent, @Nullable Screen parent, String quickShareCode) throws NullPointerException { - super(parent, TextUtils.translatable("betterstats.gui.qs_screen.download.title")); + super(parent, BST.gui_qsscreen_download_title()); + this.bssParent = bssParent; Objects.requireNonNull(quickShareCode); quickShareCode = quickShareCode.toLowerCase(Locale.ENGLISH); if(!quickShareCode.endsWith(QSC_SUFFIX)) quickShareCode += QSC_SUFFIX; @@ -60,7 +65,22 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) //start the operation __start__stage1(); - //FIXME - IMPLEMENT GUI + //the primary label + final var lbl = new TLabelElement(0, 0, getWidth(), getHeight()); + lbl.setTextHorizontalAlignment(HorizontalAlignment.CENTER); + lbl.setTextColor(0xffffff00); + addChild(lbl, false); + + //the primary label text + switch(this.__stage) + { + case 0: lbl.setText(BST.gui_qsscreen_download_stage0()); break; + case 1: lbl.setText(BST.gui_qsscreen_download_stage1()); break; + case 2: lbl.setText(BST.gui_qsscreen_download_stage2()); break; + case 3: lbl.setText(BST.gui_qsscreen_download_stage3()); break; + case 4: lbl.setText(BST.gui_qsscreen_download_stage4()); break; + default: break; + } } // ================================================== private @Internal void __start_onError(@Nullable Exception exception) @@ -82,12 +102,11 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) //fetch the API links BetterStatsWebApiUtils.fetchBssApiLinksAsync(MC_CLIENT, - json -> __start__stage2(json), + json -> __start__stage2and3(json), error -> __start_onError(error)); } - - private @Internal void __start__stage2(final JsonObject links) + private @Internal void __start__stage2and3(final JsonObject links) { //prepare this.__stage = 2; @@ -106,47 +125,79 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) public final @Override CachedResource fetchResourceSync() throws Exception { //fetch the download link - @Nullable JsonObject downloadUrlData = null; - @Nullable CloseableHttpResponse response = null; - try + final AtomicReference du_ready = new AtomicReference(); + final AtomicReference du_error = new AtomicReference(); + CachedResourceManager.getResourceSync( //NOTE: MUST BE SYNCHRONOUS! + Identifier.of( + getModID(), + "quick_share/download_urls/" + + QuickShareDownloadScreen.this.quickShareCode + ".json"), + new IResourceFetchTask() { - //perform the http request - response = fetchSync(links.get("quickshare_gdu").getAsString(), new FetchOptions() + public final @Override ThreadExecutor getMinecraftClientOrServer() { return MC_CLIENT; } + public final @Override Class getResourceType() { return JsonObject.class; } + public final @Override CachedResource fetchResourceSync() throws Exception { - public final @Override String method() { return "POST"; } - public final @Override Object body() + //check if the API is available + if(!links.has("quickshare_gdu")) + throw new NullPointerException("Quick-share download API is unavailable."); + + //perform the request + @Nullable CloseableHttpResponse response = null; + try { - final var json = new JsonObject(); - json.addProperty("file", QuickShareDownloadScreen.this.quickShareCode); - return json; + response = fetchSync(links.get("quickshare_gdu").getAsString(), new FetchOptions() + { + public final @Override String method() { return "POST"; } + public final @Override Object body() + { + final var json = new JsonObject(); + json.addProperty("file", QuickShareDownloadScreen.this.quickShareCode); + return json; + } + }); + + //collect the response message + String responseMessage = ""; + if(response.getEntity() != null) + responseMessage = EntityUtils.toString(response.getEntity()); + + //handle the response status code + final var statusCode = response.getStatusLine().getStatusCode(); + final var statusMessage = response.getStatusLine().getReasonPhrase(); + if(statusCode != 200) + throw new HttpException( + "BSS API server response message:\n----------\n" + responseMessage + "\n----------", + new HttpResponseException(statusCode, statusMessage)); + + //parse the response + final var json = GSON.fromJson(responseMessage, JsonObject.class); + @Nullable Instant expires = null; + try { expires = Instant.parse(json.get("expires").getAsString()); } + catch(Exception parseExc) { expires = Instant.now().plusSeconds(30); } + + //return the response json + return new CachedResource(json, responseMessage.length(), expires); } - }); - - //collect the response message - String responseMessage = ""; - if(response.getEntity() != null) - responseMessage = EntityUtils.toString(response.getEntity()); - - //handle the response status code - final var statusCode = response.getStatusLine().getStatusCode(); - final var statusMessage = response.getStatusLine().getReasonPhrase(); - if(statusCode != 200) - throw new HttpException( - "BSS API server response message:\n----------\n" + responseMessage + "\n----------", - new HttpResponseException(statusCode, statusMessage)); - - //parse the response json - downloadUrlData = GSON.fromJson(responseMessage, JsonObject.class); - } - finally { if(response != null) IOUtils.closeQuietly(response); } + finally { if(response != null) IOUtils.closeQuietly(response); } + } + public final @Override void onError(Exception error) { du_error.set(error); } + public final @Override void onReady(JsonObject result) { du_ready.set(result); } + }); + + //handle the download link fetch outcome + if(du_error.get() != null) + throw du_error.get(); + else if(du_ready.get() == null) + throw new NullPointerException("Failed to obtain quick-share download URL."); //prepare to download the MCBS file QuickShareDownloadScreen.this.__stage = 3; QuickShareDownloadScreen.this.refresh(); + final var downloadUrlData = du_ready.get(); final var url = downloadUrlData.get("url").getAsString(); - final var method = downloadUrlData.get("method").getAsString(); - //final var expires = Instant.parse(downloadUrlData.get("expires").getAsString()); -- download url expiration is ignored for now + final var method = downloadUrlData.get("method").getAsString().toUpperCase(Locale.ENGLISH); final var headers = downloadUrlData.get("headers").getAsJsonObject() .entrySet().stream() .map(entry -> new BasicHeader(entry.getKey(), entry.getValue().getAsString())) @@ -158,6 +209,7 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) " to download the quick-share file, but I only support HTTP GET."); //perform the download + @Nullable CloseableHttpResponse response = null; try { //fetch @@ -193,24 +245,26 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) //finally, conclude @Nullable Instant expires_file = null; try { expires_file = Instant.parse(downloadUrlData.get("expires_file").getAsString()); } - catch(Exception parseExc) { expires_file = Instant.now().plus(Duration.ofHours(48)); } + catch(Exception parseExc) { expires_file = Instant.now().plus(Duration.ofDays(1)); } return new CachedResource(responseBody, responseBody.length, expires_file); } finally { if(response != null) IOUtils.closeQuietly(response); } } public final @Override void onError(Exception error) { __start_onError(error); } - public final @Override void onReady(byte[] result) { __start__stage3(result); } + public final @Override void onReady(byte[] result) { __start__stage4(result); } }); } - private @Internal void __start__stage3(final byte[] mcbs) + private @Internal void __start__stage4(final byte[] mcbs) { + this.__stage = 4; + refresh(); try { final var buffer = new PacketByteBuf(Unpooled.wrappedBuffer(mcbs)); final var stats = new RAMStatsProvider(buffer, true); - final var bss = new BetterStatsScreen(null, stats); + final var bss = new BetterStatsScreen(this.bssParent, stats); MC_CLIENT.setScreen(bss.getAsScreen()); } catch(Exception exc) { __start_onError(exc); } diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java index 811b45d..8bda92e 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java @@ -32,9 +32,14 @@ public QuickShareScreen(@Nullable Screen parent, Text title) } // -------------------------------------------------- public final @Override Screen getParentScreen() { return this.parent; } + public @Virtual @Override void close() { MC_CLIENT.setScreen(getParentScreen()); } // ================================================== protected final void refresh() { MC_CLIENT.executeSync(() -> { if(!isOpen()) return; clearChildren(); init(); }); } // -------------------------------------------------- - public @Virtual @Override void renderBackground(TDrawContext pencil) { pencil.drawTFill(COLOR_BACKGROUND); } + public @Virtual @Override void renderBackground(TDrawContext pencil) + { + super.renderBackground(pencil); + pencil.drawTFill(COLOR_BACKGROUND); + } // ================================================== } \ No newline at end of file diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java index cdb1737..60b6c2f 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java @@ -1,5 +1,7 @@ package io.github.thecsdev.betterstats.client.gui.screen; +import static io.github.thecsdev.tcdcommons.api.util.TextUtils.translatable; +import static io.github.thecsdev.tcdcommons.api.util.TextUtils.literal; import static io.github.thecsdev.betterstats.BetterStats.getModID; import static io.github.thecsdev.betterstats.client.BetterStatsClient.MC_CLIENT; import static io.github.thecsdev.betterstats.util.io.BetterStatsWebApiUtils.GSON; @@ -12,6 +14,7 @@ import java.util.Objects; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpException; import org.apache.http.client.HttpResponseException; @@ -28,8 +31,11 @@ import io.github.thecsdev.betterstats.api.util.io.IStatsProvider; import io.github.thecsdev.betterstats.api.util.io.StatsProviderIO; +import io.github.thecsdev.betterstats.util.BST; import io.github.thecsdev.betterstats.util.io.BetterStatsWebApiUtils; -import io.github.thecsdev.tcdcommons.api.util.TextUtils; +import io.github.thecsdev.tcdcommons.api.client.gui.other.TLabelElement; +import io.github.thecsdev.tcdcommons.api.client.gui.widget.TButtonWidget; +import io.github.thecsdev.tcdcommons.api.util.enumerations.HorizontalAlignment; import io.github.thecsdev.tcdcommons.api.util.io.HttpUtils.FetchOptions; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResource; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResourceManager; @@ -38,6 +44,7 @@ import io.netty.buffer.Unpooled; import net.minecraft.client.gui.screen.Screen; import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.thread.ThreadExecutor; @@ -56,7 +63,7 @@ public final class QuickShareUploadScreen extends QuickShareScreen public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) throws NullPointerException { - super(parent, TextUtils.translatable("betterstats.gui.qs_screen.upload.title")); + super(parent, BST.gui_qsscreen_upload_title()); this.stats = Objects.requireNonNull(stats); } // ================================================== @@ -65,7 +72,34 @@ public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) //start the operation __start__stage1(); - //FIXME - IMPLEMENT GUI + //the primary label + final var lbl = new TLabelElement(0, 0, getWidth(), getHeight()); + lbl.setTextHorizontalAlignment(HorizontalAlignment.CENTER); + lbl.setTextColor(0xffffff00); + addChild(lbl, false); + + //the primary label text + switch(this.__stage) + { + case 0: lbl.setText(BST.gui_qsscreen_upload_stage0()); break; + case 1: lbl.setText(BST.gui_qsscreen_upload_stage1()); break; + case 2: lbl.setText(BST.gui_qsscreen_upload_stage2()); break; + case 3: lbl.setText(BST.gui_qsscreen_upload_stage3()); break; + case 4: + //set final stage label text + final var codeStr = StringUtils.removeEnd("" + this.__quickShareCode, QSC_SUFFIX) + .toUpperCase(Locale.ENGLISH); + final var codeTxt = literal(codeStr).formatted(Formatting.WHITE); + lbl.setText(BST.gui_qsscreen_upload_stage4(codeTxt)); + + //add a "Done" button + final var btn_done = new TButtonWidget((getWidth() / 2) - 75, getHeight() - 30, 150, 20); + btn_done.setText(translatable("gui.done")); + btn_done.setOnClick(__ -> close()); + addChild(btn_done, false); + break; + default: break; + } } // ================================================== private @Internal void __start_onError(@Nullable Exception exception) @@ -98,7 +132,7 @@ public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) //fetch the upload link CachedResourceManager.getResourceAsync( - Identifier.of(getModID(), "quick_share/upload_url.json"), + Identifier.of(getModID(), "quick_share/latest_upload_url.json"), new IResourceFetchTask() { public ThreadExecutor getMinecraftClientOrServer() { return MC_CLIENT; } diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java index 6cc3e96..00bf6c7 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java @@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils; -import io.github.thecsdev.betterstats.BetterStats; import io.github.thecsdev.betterstats.BetterStatsProperties; import io.github.thecsdev.betterstats.api.client.gui.screen.BetterStatsScreen; import io.github.thecsdev.betterstats.api.client.gui.util.StatsTabUtils; @@ -33,7 +32,6 @@ import io.github.thecsdev.tcdcommons.api.util.TextUtils; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; public class BSStatsSharingTab extends StatsTab { @@ -43,12 +41,7 @@ public class BSStatsSharingTab extends StatsTab // -------------------------------------------------- private static boolean LEGAL_QS_CONSENT = false; // ================================================== - public final @Override Text getName() - { - final var txt = BST.menu_statsSharing(); - return BetterStats.getInstance().getConfig().isFullVersion() ? - txt : txt.formatted(Formatting.YELLOW); - } + public final @Override Text getName() { return BST.menu_statsSharing(); } public final boolean isAvailable() { return false; } // ================================================== public final @Override void initFilters(FiltersInitContext initContext) @@ -101,7 +94,7 @@ private final void init_ssps(StatsInitContext initContext) //the input and submit widgets final var n1 = UILayout.nextChildVerticalRect(panel); n1.y += 3; - final var a = BetterStats.getInstance().getConfig().isFullVersion() && cpnh.isPresent() && cpnh.get().comms(); + final var a = cpnh.isPresent() && cpnh.get().comms(); final var in_name = new TTextFieldWidget(n1.x, n1.y, n1.width - 25, 20); in_name.setPlaceholderText(translatable("gui.abuseReport.type.name")); @@ -197,7 +190,11 @@ private final void init_quickShare_download(StatsInitContext initContext) { final var input = in_qscode.getInput().trim(); if(StringUtils.isBlank(input)) return; - MC_CLIENT.setScreen(new QuickShareDownloadScreen(MC_CLIENT.currentScreen, input).getAsScreen()); + MC_CLIENT.setScreen(new QuickShareDownloadScreen( + GuiUtils.getCurrentScreenParent(), + MC_CLIENT.currentScreen, + input + ).getAsScreen()); }); panel.addChild(btn_submit, false); } diff --git a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/util/BST.java b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/util/BST.java index 747aa6d..23d3691 100644 --- a/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/util/BST.java +++ b/betterstats-3-fabric-1.20.5/src/main/java/io/github/thecsdev/betterstats/util/BST.java @@ -117,5 +117,19 @@ private BST() {} public static final MutableText gui_tpsbs_qs_step1() { return translatable("betterstats.gui.tpsbs.tab.qs.step_1"); } public static final MutableText gui_tpsbs_qs_step2() { return translatable("betterstats.gui.tpsbs.tab.qs.step_2"); } public static final MutableText gui_tpsbs_qs_step2_entrqscode() { return translatable("betterstats.gui.tpsbs.tab.qs.step_2.enter_qscode"); } + // -------------------------------------------------- + public static final MutableText gui_qsscreen_upload_title() { return translatable("betterstats.gui.qs_screen.upload.title"); } + public static final MutableText gui_qsscreen_upload_stage0() { return translatable("betterstats.gui.qs_screen.upload.stage_0"); } + public static final MutableText gui_qsscreen_upload_stage1() { return translatable("betterstats.gui.qs_screen.upload.stage_1"); } + public static final MutableText gui_qsscreen_upload_stage2() { return translatable("betterstats.gui.qs_screen.upload.stage_2"); } + public static final MutableText gui_qsscreen_upload_stage3() { return translatable("betterstats.gui.qs_screen.upload.stage_3"); } + public static final MutableText gui_qsscreen_upload_stage4(Text qsCode) { return translatable("betterstats.gui.qs_screen.upload.stage_4", qsCode); } + // + public static final MutableText gui_qsscreen_download_title() { return translatable("betterstats.gui.qs_screen.download.title"); } + public static final MutableText gui_qsscreen_download_stage0() { return translatable("betterstats.gui.qs_screen.download.stage_0"); } + public static final MutableText gui_qsscreen_download_stage1() { return translatable("betterstats.gui.qs_screen.download.stage_1"); } + public static final MutableText gui_qsscreen_download_stage2() { return translatable("betterstats.gui.qs_screen.download.stage_2"); } + public static final MutableText gui_qsscreen_download_stage3() { return translatable("betterstats.gui.qs_screen.download.stage_3"); } + public static final MutableText gui_qsscreen_download_stage4() { return translatable("betterstats.gui.qs_screen.download.stage_4"); } // ================================================== } \ No newline at end of file diff --git a/betterstats-3-fabric-1.20.5/src/main/resources/META-INF/jarjar-excluded/tcdcommons-3.12+fabric-1.20.6.jar b/betterstats-3-fabric-1.20.5/src/main/resources/META-INF/jarjar-excluded/tcdcommons-3.12+fabric-1.20.6.jar index aa9c7d913930af6de16740264b51d27089350273..6d02264b9c33421271935084ed49ff69d7002ea3 100644 GIT binary patch delta 9640 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 V>KC-O--4FE06x?VG60&*{{Tmgk&XZW delta 9652 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 __start__stage2(json), + json -> __start__stage2and3(json), error -> __start_onError(error)); } - - private @Internal void __start__stage2(final JsonObject links) + private @Internal void __start__stage2and3(final JsonObject links) { //prepare this.__stage = 2; @@ -106,47 +125,79 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) public final @Override CachedResource fetchResourceSync() throws Exception { //fetch the download link - @Nullable JsonObject downloadUrlData = null; - @Nullable CloseableHttpResponse response = null; - try + final AtomicReference du_ready = new AtomicReference(); + final AtomicReference du_error = new AtomicReference(); + CachedResourceManager.getResourceSync( //NOTE: MUST BE SYNCHRONOUS! + Identifier.of( + getModID(), + "quick_share/download_urls/" + + QuickShareDownloadScreen.this.quickShareCode + ".json"), + new IResourceFetchTask() { - //perform the http request - response = fetchSync(links.get("quickshare_gdu").getAsString(), new FetchOptions() + public final @Override ThreadExecutor getMinecraftClientOrServer() { return MC_CLIENT; } + public final @Override Class getResourceType() { return JsonObject.class; } + public final @Override CachedResource fetchResourceSync() throws Exception { - public final @Override String method() { return "POST"; } - public final @Override Object body() + //check if the API is available + if(!links.has("quickshare_gdu")) + throw new NullPointerException("Quick-share download API is unavailable."); + + //perform the request + @Nullable CloseableHttpResponse response = null; + try { - final var json = new JsonObject(); - json.addProperty("file", QuickShareDownloadScreen.this.quickShareCode); - return json; + response = fetchSync(links.get("quickshare_gdu").getAsString(), new FetchOptions() + { + public final @Override String method() { return "POST"; } + public final @Override Object body() + { + final var json = new JsonObject(); + json.addProperty("file", QuickShareDownloadScreen.this.quickShareCode); + return json; + } + }); + + //collect the response message + String responseMessage = ""; + if(response.getEntity() != null) + responseMessage = EntityUtils.toString(response.getEntity()); + + //handle the response status code + final var statusCode = response.getStatusLine().getStatusCode(); + final var statusMessage = response.getStatusLine().getReasonPhrase(); + if(statusCode != 200) + throw new HttpException( + "BSS API server response message:\n----------\n" + responseMessage + "\n----------", + new HttpResponseException(statusCode, statusMessage)); + + //parse the response + final var json = GSON.fromJson(responseMessage, JsonObject.class); + @Nullable Instant expires = null; + try { expires = Instant.parse(json.get("expires").getAsString()); } + catch(Exception parseExc) { expires = Instant.now().plusSeconds(30); } + + //return the response json + return new CachedResource(json, responseMessage.length(), expires); } - }); - - //collect the response message - String responseMessage = ""; - if(response.getEntity() != null) - responseMessage = EntityUtils.toString(response.getEntity()); - - //handle the response status code - final var statusCode = response.getStatusLine().getStatusCode(); - final var statusMessage = response.getStatusLine().getReasonPhrase(); - if(statusCode != 200) - throw new HttpException( - "BSS API server response message:\n----------\n" + responseMessage + "\n----------", - new HttpResponseException(statusCode, statusMessage)); - - //parse the response json - downloadUrlData = GSON.fromJson(responseMessage, JsonObject.class); - } - finally { if(response != null) IOUtils.closeQuietly(response); } + finally { if(response != null) IOUtils.closeQuietly(response); } + } + public final @Override void onError(Exception error) { du_error.set(error); } + public final @Override void onReady(JsonObject result) { du_ready.set(result); } + }); + + //handle the download link fetch outcome + if(du_error.get() != null) + throw du_error.get(); + else if(du_ready.get() == null) + throw new NullPointerException("Failed to obtain quick-share download URL."); //prepare to download the MCBS file QuickShareDownloadScreen.this.__stage = 3; QuickShareDownloadScreen.this.refresh(); + final var downloadUrlData = du_ready.get(); final var url = downloadUrlData.get("url").getAsString(); - final var method = downloadUrlData.get("method").getAsString(); - //final var expires = Instant.parse(downloadUrlData.get("expires").getAsString()); -- download url expiration is ignored for now + final var method = downloadUrlData.get("method").getAsString().toUpperCase(Locale.ENGLISH); final var headers = downloadUrlData.get("headers").getAsJsonObject() .entrySet().stream() .map(entry -> new BasicHeader(entry.getKey(), entry.getValue().getAsString())) @@ -158,6 +209,7 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) " to download the quick-share file, but I only support HTTP GET."); //perform the download + @Nullable CloseableHttpResponse response = null; try { //fetch @@ -193,24 +245,26 @@ public QuickShareDownloadScreen(@Nullable Screen parent, String quickShareCode) //finally, conclude @Nullable Instant expires_file = null; try { expires_file = Instant.parse(downloadUrlData.get("expires_file").getAsString()); } - catch(Exception parseExc) { expires_file = Instant.now().plus(Duration.ofHours(48)); } + catch(Exception parseExc) { expires_file = Instant.now().plus(Duration.ofDays(1)); } return new CachedResource(responseBody, responseBody.length, expires_file); } finally { if(response != null) IOUtils.closeQuietly(response); } } public final @Override void onError(Exception error) { __start_onError(error); } - public final @Override void onReady(byte[] result) { __start__stage3(result); } + public final @Override void onReady(byte[] result) { __start__stage4(result); } }); } - private @Internal void __start__stage3(final byte[] mcbs) + private @Internal void __start__stage4(final byte[] mcbs) { + this.__stage = 4; + refresh(); try { final var buffer = new PacketByteBuf(Unpooled.wrappedBuffer(mcbs)); final var stats = new RAMStatsProvider(buffer, true); - final var bss = new BetterStatsScreen(null, stats); + final var bss = new BetterStatsScreen(this.bssParent, stats); MC_CLIENT.setScreen(bss.getAsScreen()); } catch(Exception exc) { __start_onError(exc); } diff --git a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java index 811b45d..8bda92e 100644 --- a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java +++ b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareScreen.java @@ -32,9 +32,14 @@ public QuickShareScreen(@Nullable Screen parent, Text title) } // -------------------------------------------------- public final @Override Screen getParentScreen() { return this.parent; } + public @Virtual @Override void close() { MC_CLIENT.setScreen(getParentScreen()); } // ================================================== protected final void refresh() { MC_CLIENT.executeSync(() -> { if(!isOpen()) return; clearChildren(); init(); }); } // -------------------------------------------------- - public @Virtual @Override void renderBackground(TDrawContext pencil) { pencil.drawTFill(COLOR_BACKGROUND); } + public @Virtual @Override void renderBackground(TDrawContext pencil) + { + super.renderBackground(pencil); + pencil.drawTFill(COLOR_BACKGROUND); + } // ================================================== } \ No newline at end of file diff --git a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java index cdb1737..60b6c2f 100644 --- a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java +++ b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/screen/QuickShareUploadScreen.java @@ -1,5 +1,7 @@ package io.github.thecsdev.betterstats.client.gui.screen; +import static io.github.thecsdev.tcdcommons.api.util.TextUtils.translatable; +import static io.github.thecsdev.tcdcommons.api.util.TextUtils.literal; import static io.github.thecsdev.betterstats.BetterStats.getModID; import static io.github.thecsdev.betterstats.client.BetterStatsClient.MC_CLIENT; import static io.github.thecsdev.betterstats.util.io.BetterStatsWebApiUtils.GSON; @@ -12,6 +14,7 @@ import java.util.Objects; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpException; import org.apache.http.client.HttpResponseException; @@ -28,8 +31,11 @@ import io.github.thecsdev.betterstats.api.util.io.IStatsProvider; import io.github.thecsdev.betterstats.api.util.io.StatsProviderIO; +import io.github.thecsdev.betterstats.util.BST; import io.github.thecsdev.betterstats.util.io.BetterStatsWebApiUtils; -import io.github.thecsdev.tcdcommons.api.util.TextUtils; +import io.github.thecsdev.tcdcommons.api.client.gui.other.TLabelElement; +import io.github.thecsdev.tcdcommons.api.client.gui.widget.TButtonWidget; +import io.github.thecsdev.tcdcommons.api.util.enumerations.HorizontalAlignment; import io.github.thecsdev.tcdcommons.api.util.io.HttpUtils.FetchOptions; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResource; import io.github.thecsdev.tcdcommons.api.util.io.cache.CachedResourceManager; @@ -38,6 +44,7 @@ import io.netty.buffer.Unpooled; import net.minecraft.client.gui.screen.Screen; import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.thread.ThreadExecutor; @@ -56,7 +63,7 @@ public final class QuickShareUploadScreen extends QuickShareScreen public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) throws NullPointerException { - super(parent, TextUtils.translatable("betterstats.gui.qs_screen.upload.title")); + super(parent, BST.gui_qsscreen_upload_title()); this.stats = Objects.requireNonNull(stats); } // ================================================== @@ -65,7 +72,34 @@ public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) //start the operation __start__stage1(); - //FIXME - IMPLEMENT GUI + //the primary label + final var lbl = new TLabelElement(0, 0, getWidth(), getHeight()); + lbl.setTextHorizontalAlignment(HorizontalAlignment.CENTER); + lbl.setTextColor(0xffffff00); + addChild(lbl, false); + + //the primary label text + switch(this.__stage) + { + case 0: lbl.setText(BST.gui_qsscreen_upload_stage0()); break; + case 1: lbl.setText(BST.gui_qsscreen_upload_stage1()); break; + case 2: lbl.setText(BST.gui_qsscreen_upload_stage2()); break; + case 3: lbl.setText(BST.gui_qsscreen_upload_stage3()); break; + case 4: + //set final stage label text + final var codeStr = StringUtils.removeEnd("" + this.__quickShareCode, QSC_SUFFIX) + .toUpperCase(Locale.ENGLISH); + final var codeTxt = literal(codeStr).formatted(Formatting.WHITE); + lbl.setText(BST.gui_qsscreen_upload_stage4(codeTxt)); + + //add a "Done" button + final var btn_done = new TButtonWidget((getWidth() / 2) - 75, getHeight() - 30, 150, 20); + btn_done.setText(translatable("gui.done")); + btn_done.setOnClick(__ -> close()); + addChild(btn_done, false); + break; + default: break; + } } // ================================================== private @Internal void __start_onError(@Nullable Exception exception) @@ -98,7 +132,7 @@ public QuickShareUploadScreen(@Nullable Screen parent, IStatsProvider stats) //fetch the upload link CachedResourceManager.getResourceAsync( - Identifier.of(getModID(), "quick_share/upload_url.json"), + Identifier.of(getModID(), "quick_share/latest_upload_url.json"), new IResourceFetchTask() { public ThreadExecutor getMinecraftClientOrServer() { return MC_CLIENT; } diff --git a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java index 6cc3e96..00bf6c7 100644 --- a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java +++ b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/client/gui/stats/tabs/BSStatsSharingTab.java @@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils; -import io.github.thecsdev.betterstats.BetterStats; import io.github.thecsdev.betterstats.BetterStatsProperties; import io.github.thecsdev.betterstats.api.client.gui.screen.BetterStatsScreen; import io.github.thecsdev.betterstats.api.client.gui.util.StatsTabUtils; @@ -33,7 +32,6 @@ import io.github.thecsdev.tcdcommons.api.util.TextUtils; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; public class BSStatsSharingTab extends StatsTab { @@ -43,12 +41,7 @@ public class BSStatsSharingTab extends StatsTab // -------------------------------------------------- private static boolean LEGAL_QS_CONSENT = false; // ================================================== - public final @Override Text getName() - { - final var txt = BST.menu_statsSharing(); - return BetterStats.getInstance().getConfig().isFullVersion() ? - txt : txt.formatted(Formatting.YELLOW); - } + public final @Override Text getName() { return BST.menu_statsSharing(); } public final boolean isAvailable() { return false; } // ================================================== public final @Override void initFilters(FiltersInitContext initContext) @@ -101,7 +94,7 @@ private final void init_ssps(StatsInitContext initContext) //the input and submit widgets final var n1 = UILayout.nextChildVerticalRect(panel); n1.y += 3; - final var a = BetterStats.getInstance().getConfig().isFullVersion() && cpnh.isPresent() && cpnh.get().comms(); + final var a = cpnh.isPresent() && cpnh.get().comms(); final var in_name = new TTextFieldWidget(n1.x, n1.y, n1.width - 25, 20); in_name.setPlaceholderText(translatable("gui.abuseReport.type.name")); @@ -197,7 +190,11 @@ private final void init_quickShare_download(StatsInitContext initContext) { final var input = in_qscode.getInput().trim(); if(StringUtils.isBlank(input)) return; - MC_CLIENT.setScreen(new QuickShareDownloadScreen(MC_CLIENT.currentScreen, input).getAsScreen()); + MC_CLIENT.setScreen(new QuickShareDownloadScreen( + GuiUtils.getCurrentScreenParent(), + MC_CLIENT.currentScreen, + input + ).getAsScreen()); }); panel.addChild(btn_submit, false); } diff --git a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/util/BST.java b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/util/BST.java index 747aa6d..23d3691 100644 --- a/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/util/BST.java +++ b/betterstats-3-fabric-1.21/src/main/java/io/github/thecsdev/betterstats/util/BST.java @@ -117,5 +117,19 @@ private BST() {} public static final MutableText gui_tpsbs_qs_step1() { return translatable("betterstats.gui.tpsbs.tab.qs.step_1"); } public static final MutableText gui_tpsbs_qs_step2() { return translatable("betterstats.gui.tpsbs.tab.qs.step_2"); } public static final MutableText gui_tpsbs_qs_step2_entrqscode() { return translatable("betterstats.gui.tpsbs.tab.qs.step_2.enter_qscode"); } + // -------------------------------------------------- + public static final MutableText gui_qsscreen_upload_title() { return translatable("betterstats.gui.qs_screen.upload.title"); } + public static final MutableText gui_qsscreen_upload_stage0() { return translatable("betterstats.gui.qs_screen.upload.stage_0"); } + public static final MutableText gui_qsscreen_upload_stage1() { return translatable("betterstats.gui.qs_screen.upload.stage_1"); } + public static final MutableText gui_qsscreen_upload_stage2() { return translatable("betterstats.gui.qs_screen.upload.stage_2"); } + public static final MutableText gui_qsscreen_upload_stage3() { return translatable("betterstats.gui.qs_screen.upload.stage_3"); } + public static final MutableText gui_qsscreen_upload_stage4(Text qsCode) { return translatable("betterstats.gui.qs_screen.upload.stage_4", qsCode); } + // + public static final MutableText gui_qsscreen_download_title() { return translatable("betterstats.gui.qs_screen.download.title"); } + public static final MutableText gui_qsscreen_download_stage0() { return translatable("betterstats.gui.qs_screen.download.stage_0"); } + public static final MutableText gui_qsscreen_download_stage1() { return translatable("betterstats.gui.qs_screen.download.stage_1"); } + public static final MutableText gui_qsscreen_download_stage2() { return translatable("betterstats.gui.qs_screen.download.stage_2"); } + public static final MutableText gui_qsscreen_download_stage3() { return translatable("betterstats.gui.qs_screen.download.stage_3"); } + public static final MutableText gui_qsscreen_download_stage4() { return translatable("betterstats.gui.qs_screen.download.stage_4"); } // ================================================== } \ No newline at end of file diff --git a/betterstats-3-fabric-1.21/src/main/resources/META-INF/jarjar-excluded/tcdcommons-3.12+fabric-1.21.jar b/betterstats-3-fabric-1.21/src/main/resources/META-INF/jarjar-excluded/tcdcommons-3.12+fabric-1.21.jar index d3a52f6b161b126d2ac526e7de1e105c705c86d3..c437c2b7744d9851e746fde5f6c134c7c70044b5 100644 GIT binary patch delta 9840 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 delta 9615 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 XTO9-Qs=o!)1ys=y6ciR}08;-CU|eWO diff --git a/betterstats-3-fabric-1.21/src/main/resources/assets/betterstats/lang/en_us.json b/betterstats-3-fabric-1.21/src/main/resources/assets/betterstats/lang/en_us.json index f66bace..a31dc99 100644 --- a/betterstats-3-fabric-1.21/src/main/resources/assets/betterstats/lang/en_us.json +++ b/betterstats-3-fabric-1.21/src/main/resources/assets/betterstats/lang/en_us.json @@ -110,5 +110,20 @@ "betterstats.gui.tpsbs.tab.qs.abuse_notice": "To prevent spam and abuse, rate-limits and other limitations may apply.", "betterstats.gui.tpsbs.tab.qs.step_1": "§eStep 1:\n§7Click the button to quickly share the statistics file you are currently viewing. After that, the stats get uploaded, and you are given a 'quick-share code'.", "betterstats.gui.tpsbs.tab.qs.step_2": "§eStep 2:\n§7The person intended to view the shared statistics then types in the 'quick-share code', and clicks on the button to download and view the shared statistics.", - "betterstats.gui.tpsbs.tab.qs.step_2.enter_qscode": "Enter the quick-share code here" + "betterstats.gui.tpsbs.tab.qs.step_2.enter_qscode": "Enter the quick-share code here", + + + "betterstats.gui.qs_screen.upload.title": "Uploading quick-share statistics...", + "betterstats.gui.qs_screen.upload.stage_0": "Preparting to upload the statistics...", + "betterstats.gui.qs_screen.upload.stage_1": "Fetching better-stats API endpoint URLs...", + "betterstats.gui.qs_screen.upload.stage_2": "Fetching cloud upload API endpoint URL...", + "betterstats.gui.qs_screen.upload.stage_3": "Uploading statistics to the cloud...", + "betterstats.gui.qs_screen.upload.stage_4": "Done. Your quick-share code is: %s", + + "betterstats.gui.qs_screen.download.title": "Downloading quick-share statistics...", + "betterstats.gui.qs_screen.download.stage_0": "Preparting to download the statistics...", + "betterstats.gui.qs_screen.download.stage_1": "Fetching better-stats API endpoint URLs...", + "betterstats.gui.qs_screen.download.stage_2": "Fetching cloud download API endpoint URL...", + "betterstats.gui.qs_screen.download.stage_3": "Downloading statistics from the cloud...", + "betterstats.gui.qs_screen.download.stage_4": "Done. Loading the downloaded statistics..." } \ No newline at end of file