Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,54 @@
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.earthcomputer.clientcommands.features.WikiRetriever;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import org.jspecify.annotations.Nullable;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import static com.mojang.brigadier.arguments.StringArgumentType.*;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;

public class WikiCommand {
private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.cwiki.failed"));

private static final String WIKI_HOST = "https://minecraft.wiki/";
private static final String WIKI_ARTICLE = WIKI_HOST + "w/%s";


public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(literal("cwiki")
.then(argument("page", greedyString())
.executes(ctx -> displayWikiPage(ctx.getSource(), getString(ctx, "page")))));
}

@Nullable
private static Component getLinkComponent(String page) {
String title = WikiRetriever.searchArticleName(page);
if (title == null) {
return null;
}

String pageName = URLEncoder.encode(title, StandardCharsets.UTF_8).replace('+', '_');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this line. Is it meant to be replacing spaces with underscores? Spaces get replaced with %20 after URL encoding, not +. Alternatively you could replace them before URL encoding, as I'm not sure that _ gets changed with URL encoding (not 100% sure on this)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it might be outdated but this documentation says otherwise: https://docs.oracle.com/javase/8/docs/api/java/net/URLEncoder.html

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not outdated, it works the same on Java 21.

String url = String.format(WIKI_ARTICLE, pageName);
URI uri = URI.create(url);

ClickEvent clickEvent = new ClickEvent.OpenUrl(uri);

return Component.translatable("commands.cwiki.openArticle")
.withStyle(style -> style
.withClickEvent(clickEvent)
.withColor(ChatFormatting.GREEN)
.withUnderlined(true)
);
}

private static int displayWikiPage(FabricClientCommandSource source, String page) throws CommandSyntaxException {
String content = WikiRetriever.getWikiSummary(page);

if (content == null) {
throw FAILED_EXCEPTION.create();
}
Expand All @@ -31,6 +62,13 @@ private static int displayWikiPage(FabricClientCommandSource source, String page
source.sendFeedback(Component.literal(line));
}

Component link = getLinkComponent(page);
if (link == null) {
throw FAILED_EXCEPTION.create();
}

source.sendFeedback(link);

return content.length();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class WikiRetriever {

private static final String WIKI_HOST = "https://minecraft.wiki/";
private static final String SEARCH_QUERY = WIKI_HOST + "api.php?action=query&list=search&srlimit=1&srprop=snippet&format=json&srsearch=%s";
private static final String PAGE_SUMMARY_QUERY = WIKI_HOST + "api.php?action=query&prop=extracts&exintro=true&format=json&titles=%s";
private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<\\s*(/)?\\s*(\\w+).*?>|<!--.*?-->|\n", Pattern.DOTALL);
private static final ChatFormatting CODE_COLOR = ChatFormatting.DARK_GREEN;
Expand Down Expand Up @@ -184,19 +188,78 @@ public static String decode(String html) {
}

@Nullable
public static String getWikiSummary(String pageName) {
public static QueryResult getResult(URL url) {
QueryResult result;
try (InputStream in = url.openConnection().getInputStream()) {
result = GSON.fromJson(new InputStreamReader(in), QueryResult.class);
} catch (IOException e) {
return null;
}
return result;
}

@Nullable
public static URL buildURL(String page, String query) {
String result = Arrays.stream(page.split("\\s+"))
.map(w -> w.substring(0, 1).toUpperCase(Locale.ROOT)
+ w.substring(1).toLowerCase(Locale.ROOT))
.collect(Collectors.joining(" "));


URL url;
try {
String encodedPage = URLEncoder.encode(pageName, StandardCharsets.UTF_8);
url = URI.create(String.format(PAGE_SUMMARY_QUERY, encodedPage)).toURL();
String encodedPage = URLEncoder.encode(result, StandardCharsets.UTF_8);
url = URI.create(String.format(query, encodedPage)).toURL();
} catch (MalformedURLException e) {
return null;
}
return url;
}

@Nullable
public static String searchArticleName(String pageInput){
URL url = buildURL(pageInput.trim(), SEARCH_QUERY);
if (url == null) {
return null;
}

QueryResult result;
try (InputStream in = url.openConnection().getInputStream()) {
result = GSON.fromJson(new InputStreamReader(in), QueryResult.class);
} catch (IOException e) {
QueryResult result = getResult(url);
if (result == null) {
return null;
}

var query = result.query;
if (query == null) {
return null;
}

var search = query.search;
var searchinfo = query.searchinfo;
if (search == null || search.isEmpty() || searchinfo == null || searchinfo.totalhits == 0) {
return null;
}

if (searchinfo.suggestion != null) {
return searchinfo.suggestion;
}

return query.search.getFirst().title;
}

@Nullable
public static String getWikiSummary(String pageName) {
String title = searchArticleName(pageName);
if (title == null) {
return null;
}

URL url = buildURL(title, PAGE_SUMMARY_QUERY);
if (url == null) {
return null;
}

QueryResult result = getResult(url);
if (result == null) {
return null;
}

Expand All @@ -212,12 +275,12 @@ public static String getWikiSummary(String pageName) {
}

@SuppressWarnings("unused")
private static class QueryResult {
public static class QueryResult {
@Nullable
public String batchcomplete;
@Nullable
public Query query;
private static class Query {
public static class Query {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Nullable
private Map<String, Page> pages;
Expand All @@ -230,6 +293,21 @@ private static class Page {
@Nullable
public String missing;
}
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Nullable
private List<Search> search;
private static class Search {
@Nullable
public String title;
}
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Nullable
private SearchInfo searchinfo;
private static class SearchInfo {
public int totalhits;
@Nullable
public String suggestion;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/main/resources/assets/clientcommands/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@

"commands.cwiki.failed": "Could not retrieve wiki content",
"commands.cwiki.noContent": "There is no introductory paragraph in that article",
"commands.cwiki.openArticle": "[Open article]",

"connectFourGame.draw": "Draw!",
"connectFourGame.lost": "Lost!",
Expand Down