Refactored to expose the ModMenu Integration to other Mods

This commit is contained in:
Frank 2021-08-20 03:05:36 +02:00
parent 5808bab08e
commit 0486b56ec3
4 changed files with 136 additions and 50 deletions

View file

@ -0,0 +1,12 @@
package ru.bclib.gui.modmenu;
import com.terraformersmc.modmenu.util.ModMenuApiMarker;
import ru.bclib.integration.ModMenuIntegration;
public class EntryPoint extends ModMenuIntegration {
public static final ModMenuApiMarker entrypointObject = createEntrypoint(new EntryPoint());
public EntryPoint() {
super(MainScreen::new);
}
}

View file

@ -1,4 +1,4 @@
package ru.bclib.gui.screens.ModMenu; package ru.bclib.gui.modmenu;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.CommonComponents;

View file

@ -3,23 +3,18 @@ package ru.bclib.integration;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.terraformersmc.modmenu.util.ModMenuApiMarker; import com.terraformersmc.modmenu.util.ModMenuApiMarker;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import ru.bclib.gui.screens.ModMenu.MainScreen; import ru.bclib.integration.ModMenuIntegration.ModMenuScreenFactory;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Map; import java.util.Map;
@FunctionalInterface class ModMenuScreenFactoryImpl {
interface IModMenuScreenFactory<S extends Screen> {
S create(Screen parent);
}
class ModMenuScreenFactory {
static class ScreenFactoryInvocationHandler implements InvocationHandler { static class ScreenFactoryInvocationHandler implements InvocationHandler {
private final IModMenuScreenFactory act; private final ModMenuScreenFactory act;
public ScreenFactoryInvocationHandler(IModMenuScreenFactory act) { public ScreenFactoryInvocationHandler(ModMenuScreenFactory act) {
this.act = act; this.act = act;
} }
@ -29,7 +24,7 @@ class ModMenuScreenFactory {
} }
} }
public static IModMenuScreenFactory create(IModMenuScreenFactory act) { public static ModMenuScreenFactory create(ModMenuScreenFactory act) {
Class<?> iConfigScreenFactory = null; Class<?> iConfigScreenFactory = null;
try { try {
iConfigScreenFactory = Class.forName("com.terraformersmc.modmenu.api.ConfigScreenFactory"); iConfigScreenFactory = Class.forName("com.terraformersmc.modmenu.api.ConfigScreenFactory");
@ -40,14 +35,128 @@ class ModMenuScreenFactory {
Object o = Proxy.newProxyInstance( Object o = Proxy.newProxyInstance(
ModMenuIntegration.class.getClassLoader(), ModMenuIntegration.class.getClassLoader(),
new Class[] {iConfigScreenFactory, IModMenuScreenFactory.class}, new Class[] {iConfigScreenFactory, ModMenuScreenFactory.class},
new ScreenFactoryInvocationHandler(act)); new ScreenFactoryInvocationHandler(act));
return (IModMenuScreenFactory)o; return (ModMenuScreenFactory)o;
} }
} }
public class ModMenuIntegration { /**
* Integration, to provide a custom Screen for ModMenu.
* <p>
* This integration allows you to use ModMenu without adding a dependency to your project. If the
* Mod is installed on the Client, and the correct ModMenu-EntryPoint is registered in your <i>fabric.mod.json</i>
* the screen will show up.
* <p>
* You only need to subclass this class, and initialize a static Field of Type {@link ModMenuApiMarker} using
* the {@link #createEntrypoint(ModMenuIntegration)}-Method.
* <p>
* Example:
* <pre>{@code public class ModMenu extends ModMenuIntegration {
* public static final ModMenuApiMarker entrypointObject = createEntrypoint(new EntryPoint());
*
* public EntryPoint() {
* super(GridScreen::new);
* }
* }</pre>
* You'd also need to add the ModMenu-Entrypoint to your <i>fabric.mod.json</i>:
* <pre>"entrypoints": {
* ...
* "modmenu": [ "your.mod.ModMenu::entrypointObject" ]
* }</pre>
*/
public abstract class ModMenuIntegration {
/**
* Creates a new EntryPoint Object that is accepted by ModMenu
* @param target The delegate Object that will receive calls from ModMenu
* @return A Proxy that conforms to the ModMenu spec
*/
public static ModMenuApiMarker createEntrypoint(ModMenuIntegration target) {
Class<?> iModMenuAPI = null;
//Class<?> iModMenuAPIMarker = null;
try {
iModMenuAPI = Class.forName("com.terraformersmc.modmenu.api.ModMenuApi");
//iModMenuAPIMarker = Class.forName("com.terraformersmc.modmenu.util.ModMenuApiMarker");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
return (ModMenuApiMarker)new Object();
}
Object o = Proxy.newProxyInstance(
ModMenuIntegration.class.getClassLoader(),
new Class[] {iModMenuAPI},
new BCLibModMenuInvocationHandler(target));
return (ModMenuApiMarker)o;
}
protected final ModMenuScreenFactory screenFactory;
/**
* Create a new ModMenu delegate
* @param screenFactory A Factory. The Factory receives the currently visible {@code parent}-Screen
* and must return a new Screen Object.
*/
public ModMenuIntegration(ModMenuScreenFactory screenFactory){
this.screenFactory = screenFactory;
}
/**
* A Helper class to make a BCLib-Factory conform to the ModMenu-Factory Interface.
* @param factory
* @return A ModMenu Factory for a Screen
*/
final protected ModMenuScreenFactory createFactory(ModMenuScreenFactory factory){
return ModMenuScreenFactoryImpl.create( factory );
}
/**
* 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.
* (Text copied from ModMenu)
*
* @return A factory for constructing config screen instances.
*
*/
public ModMenuScreenFactory getModConfigScreenFactory() {
return createFactory(screenFactory);
}
/**
* 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.
* (Text copied from ModMenu)
*
* @return a map of mod ids to screen factories.
*/
public Map<String, ModMenuScreenFactory> getProvidedConfigScreenFactories() {
return ImmutableMap.of();
}
@Override
public String toString() {
return super.toString();
}
/**
* A Factory Interface for ModMenu-Screens
* <p>
* The Interface matches {@code com.terraformersmc.modmenu.api.ConfigScreenFactory}
*/
@FunctionalInterface
public static interface ModMenuScreenFactory {
Screen create(Screen parent);
}
static class BCLibModMenuInvocationHandler implements InvocationHandler { static class BCLibModMenuInvocationHandler implements InvocationHandler {
private final ModMenuIntegration target; private final ModMenuIntegration target;
@ -68,39 +177,4 @@ public class ModMenuIntegration {
} }
} }
} }
public static final ModMenuApiMarker entrypointObject = create();
public static ModMenuApiMarker create() {
Class<?> iModMenuAPI = null;
//Class<?> iModMenuAPIMarker = null;
try {
iModMenuAPI = Class.forName("com.terraformersmc.modmenu.api.ModMenuApi");
//iModMenuAPIMarker = Class.forName("com.terraformersmc.modmenu.util.ModMenuApiMarker");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
return (ModMenuApiMarker)new Object();
}
Object o = Proxy.newProxyInstance(
ModMenuIntegration.class.getClassLoader(),
new Class[] {iModMenuAPI},
new BCLibModMenuInvocationHandler(new ModMenuIntegration()));
return (ModMenuApiMarker)o;
}
IModMenuScreenFactory<?> getModConfigScreenFactory() {
return ModMenuScreenFactory.create( MainScreen::new );
}
Map<String, IModMenuScreenFactory<?>> getProvidedConfigScreenFactories() {
return ImmutableMap.of();
}
@Override
public String toString() {
return super.toString();
}
} }

View file

@ -26,7 +26,7 @@
"server": [ "server": [
"ru.bclib.server.BCLibServer" "ru.bclib.server.BCLibServer"
], ],
"modmenu": [ "ru.bclib.integration.ModMenuIntegration::entrypointObject" ] "modmenu": [ "ru.bclib.gui.modmenu.EntryPoint::entrypointObject" ]
}, },
"mixins": [ "mixins": [
"bclib.mixins.common.json", "bclib.mixins.common.json",