Skip to content

Commit

Permalink
Re-port the refactor from 1.16 (except I actually included the files …
Browse files Browse the repository at this point in the history
…this time)

Took 2 minutes
  • Loading branch information
Prospector committed Feb 11, 2021
1 parent fa8421a commit e455995
Show file tree
Hide file tree
Showing 56 changed files with 3,666 additions and 0 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/check_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Automatically build the project and run any configured tests for every push
# and submitted pull request. This can help catch issues that only occur on
# certain platforms or Java versions, and provides a first line of defence
# against bad commits.

name: Check Build
on: [push, pull_request]

jobs:
build:
strategy:
matrix:
# Use these Java versions
java: [
1.8, # Minimum
11, # LTS
15 # Latest
]
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup JDK ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Make Gradle wrapper executable
if: ${{ runner.os != 'Windows' }}
run: chmod +x ./gradlew
- name: Build
run: ./gradlew build --stacktrace --parallel
- name: Capture build artifacts
if: ${{ runner.os == 'Linux' && matrix.java == '11' }} # Only upload artifacts built from LTS java on one OS
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: build/libs/
62 changes: 62 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Release
on:
workflow_dispatch:
inputs:
previousVersion:
description: 'Previous Version (Do not include v prefix, must be same as the last version tag! Example: 1.4.1)'
required: true
version:
description: 'Version (Do not include v prefix! Example: 1.4.2)'
required: true
jobs:
release:
strategy:
matrix:
# Use these Java versions
java: [11]
# and run on both Linux and Windows
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Create version tag
uses: actions/github-script@v3
with:
github-token: ${{ github.token }}
script: |
github.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/v${{ github.event.inputs.version }}",
sha: context.sha
})
- name: Fetch tags
run: git fetch --tags
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup JDK ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Make Gradle wrapper executable
if: ${{ runner.os != 'Windows' }}
run: chmod +x ./gradlew
- name: Build
run: ./gradlew generateChangelog build publish curseforge github publishModrinth --stacktrace --parallel -PlastTag="v${{ github.event.inputs.previousVersion }}" -PcurrentTag="v${{ github.event.inputs.version }}"
env:
MAVEN_URL: ${{ secrets.MAVEN_URL }}
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_API_KEY }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
DISCORD_ANNOUNCEMENT_WEBHOOK: ${{ secrets.DISCORD_ANNOUNCEMENT_WEBHOOK }}
- name: Capture build artifacts
if: ${{ runner.os == 'Linux' && matrix.java == '11' }} # Only upload artifacts built from LTS java on one OS
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: build/libs/
Empty file added logs/latest.log
Empty file.
126 changes: 126 additions & 0 deletions src/main/java/com/terraformersmc/modmenu/ModMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.terraformersmc.modmenu;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.LinkedListMultimap;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import com.terraformersmc.modmenu.config.ModMenuConfig;
import com.terraformersmc.modmenu.config.ModMenuConfigManager;
import com.terraformersmc.modmenu.event.ModMenuEventHandler;
import com.terraformersmc.modmenu.util.ModMenuApiMarker;
import com.terraformersmc.modmenu.util.mod.Mod;
import com.terraformersmc.modmenu.util.mod.fabric.FabricDummyParentMod;
import com.terraformersmc.modmenu.util.mod.fabric.FabricMod;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;

import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

public class ModMenu implements ClientModInitializer {
public static final String MOD_ID = "modmenu";
public static final Gson GSON = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();

public static final Map<String, Mod> MODS = new HashMap<>();
public static final Map<String, Mod> ROOT_MODS = new HashMap<>();
public static final LinkedListMultimap<Mod, Mod> PARENT_MAP = LinkedListMultimap.create();

private static ImmutableMap<String, ConfigScreenFactory<?>> configScreenFactories = ImmutableMap.of();

private static int cachedDisplayedModCount = -1;

public static Screen getConfigScreen(String modid, Screen menuScreen) {
ConfigScreenFactory<?> factory = configScreenFactories.get(modid);
return factory != null ? factory.create(menuScreen) : null;
}

@Override
public void onInitializeClient() {
ModMenuConfigManager.initializeConfig();
Map<String, ConfigScreenFactory<?>> factories = new HashMap<>();
FabricLoader.getInstance().getEntrypointContainers("modmenu", ModMenuApiMarker.class).forEach(entrypoint -> {
ModMenuApiMarker marker = entrypoint.getEntrypoint();
if (marker instanceof ModMenuApi) {
/* Current API */
ModMenuApi api = (ModMenuApi) marker;
factories.put(entrypoint.getProvider().getMetadata().getId(), api.getModConfigScreenFactory());
api.getProvidedConfigScreenFactories().forEach(factories::putIfAbsent);
} else if (marker instanceof io.github.prospector.modmenu.api.ModMenuApi) {
/* Legacy API */
io.github.prospector.modmenu.api.ModMenuApi api = (io.github.prospector.modmenu.api.ModMenuApi) entrypoint.getEntrypoint();
factories.put(entrypoint.getProvider().getMetadata().getId(), screen -> api.getModConfigScreenFactory().create(screen));
api.getProvidedConfigScreenFactories().forEach((id, legacyFactory) -> factories.put(id, legacyFactory::create));
} else {
throw new RuntimeException(entrypoint.getProvider().getMetadata().getId() + " is providing an invalid ModMenuApi implementation");
}
});
configScreenFactories = new ImmutableMap.Builder<String, ConfigScreenFactory<?>>().putAll(factories).build();


// Fill mods map
for (ModContainer modContainer : FabricLoader.getInstance().getAllMods()) {
if (!ModMenuConfig.HIDDEN_MODS.getValue().contains(modContainer.getMetadata().getId())) {
FabricMod mod = new FabricMod(modContainer);
MODS.put(mod.getId(), mod);
}
}

Map<String, Mod> dummyParents = new HashMap<>();

// Initialize parent map
for (Mod mod : MODS.values()) {
String parentId = mod.getParent();
if (parentId != null) {
Mod parent = MODS.getOrDefault(parentId, dummyParents.get(parentId));
if (parent == null) {
if (mod instanceof FabricMod) {
parent = new FabricDummyParentMod((FabricMod) mod, parentId);
dummyParents.put(parentId, parent);
}
}
PARENT_MAP.put(parent, mod);
} else {
ROOT_MODS.put(mod.getId(), mod);
}
}
MODS.putAll(dummyParents);
ModMenuEventHandler.register();
}

public static void clearModCountCache() {
cachedDisplayedModCount = -1;
}

public static String getDisplayedModCount() {
if (cachedDisplayedModCount == -1) {
// listen, if you have >= 2^32 mods then that's on you
cachedDisplayedModCount = Math.toIntExact(MODS.values().stream().filter(mod ->
(ModMenuConfig.COUNT_CHILDREN.getValue() || mod.getParent() == null) &&
(ModMenuConfig.COUNT_LIBRARIES.getValue() || !mod.getBadges().contains(Mod.Badge.LIBRARY)) &&
(ModMenuConfig.COUNT_HIDDEN_MODS.getValue() || !ModMenuConfig.HIDDEN_MODS.getValue().contains(mod.getId()))
).count());
}
return NumberFormat.getInstance().format(cachedDisplayedModCount);
}

public static Text createModsButtonText() {
TranslatableText modsText = new TranslatableText("modmenu.title");
if (ModMenuConfig.MOD_COUNT_LOCATION.getValue().isOnModsButton() && ModMenuConfig.MODS_BUTTON_STYLE.getValue() != ModMenuConfig.ModsButtonStyle.ICON) {
if (ModMenuConfig.MODS_BUTTON_STYLE.getValue() == ModMenuConfig.ModsButtonStyle.SHRINK) {
modsText.append(new LiteralText(" ")).append(new TranslatableText("modmenu.loaded.short", ModMenu.getDisplayedModCount()));
} else {
modsText.append(new LiteralText(" ")).append(new TranslatableText("modmenu.loaded", ModMenu.getDisplayedModCount()));
}
}
return modsText;
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/terraformersmc/modmenu/ModMenuModMenuCompat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.terraformersmc.modmenu;

import com.google.common.collect.ImmutableMap;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import com.terraformersmc.modmenu.gui.ModMenuOptionsScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.option.OptionsScreen;

import java.util.Map;

public class ModMenuModMenuCompat implements ModMenuApi {

@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return ModMenuOptionsScreen::new;
}

@Override
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
return ImmutableMap.of("minecraft", parent -> new OptionsScreen(parent, MinecraftClient.getInstance().options));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.terraformersmc.modmenu.api;

import net.minecraft.client.gui.screen.Screen;

@FunctionalInterface
public interface ConfigScreenFactory<S extends Screen> extends io.github.prospector.modmenu.api.ConfigScreenFactory<S> {
S create(Screen parent);
}
61 changes: 61 additions & 0 deletions src/main/java/com/terraformersmc/modmenu/api/ModMenuApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.terraformersmc.modmenu.api;

import com.google.common.collect.ImmutableMap;
import com.terraformersmc.modmenu.ModMenu;
import com.terraformersmc.modmenu.gui.ModsScreen;
import com.terraformersmc.modmenu.util.ModMenuApiMarker;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;

import java.util.Map;

public interface ModMenuApi extends ModMenuApiMarker {

/**
* Used for creating a {@link Screen} instance of the Mod Menu
* "Mods" screen
*
* @param previous The screen before opening
* @return A "Mods" Screen
*/
static Screen createModsScreen(Screen previous) {
return new ModsScreen(previous);
}

/**
* Used for creating a {@link Text} just like what would appear
* on a Mod Menu Mods button
*
* @return The text that would be displayed on a Mods button
*/
static Text createModsButtonText() {
return ModMenu.createModsButtonText();
}

/**
* Used to construct a new config screen instance when your mod's
* configuration button is selected on the mod menu screen. The
* screen instance parameter is the active mod menu screen.
*
* @return A factory for constructing config screen instances.
*/
default ConfigScreenFactory<?> getModConfigScreenFactory() {
return screen -> null;
}

/**
* Used to provide config screen factories for other mods. This takes second
* priority to a mod's own config screen factory provider. For example, if
* mod `xyz` supplies a config screen factory, mod `abc` providing a config
* screen to `xyz` will be pointless, as the one provided by `xyz` will be
* used.
* <p>
* This method is NOT meant to be used to add a config screen factory to
* your own mod.
*
* @return a map of mod ids to screen factories.
*/
default Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
return ImmutableMap.of();
}
}
Loading

0 comments on commit e455995

Please sign in to comment.