switch config systems; configs can now be modified on the fly and have comments and such

This commit is contained in:
GiantLuigi4 2023-06-02 13:36:59 -04:00
parent 4ac3edb4af
commit 7d3de1fcc5
26 changed files with 704 additions and 188 deletions

View File

@ -76,7 +76,7 @@ dependencies {
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
implementation fg.deobf("com.github.Mysticpasta1:mcef-forge:17731a6bbb")
implementation fg.deobf("curse.maven:cloth_config_forge-348521:3972423")
// implementation fg.deobf("curse.maven:cloth_config_forge-348521:3972423")
implementation fg.deobf("curse.maven:SU-370704:4410614")
implementation fg.deobf("curse.maven:spark-361579:4381167")

View File

@ -5,9 +5,6 @@
package net.montoyo.wd;
import com.google.gson.Gson;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.ConfigHolder;
import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer;
import net.minecraft.ChatFormatting;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.CriteriaTriggers;
@ -41,7 +38,8 @@ import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.config.ModConfig;
import net.montoyo.wd.config.ClientConfig;
import net.montoyo.wd.config.CommonConfig;
import net.montoyo.wd.controls.ScreenControlRegistry;
import net.montoyo.wd.core.*;
import net.montoyo.wd.init.BlockInit;
@ -58,15 +56,11 @@ import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@Mod("webdisplays")
public class WebDisplays {
public static final String MOD_VERSION = "1.1";
public static WebDisplays INSTANCE;
public static SharedProxy PROXY = null;
@ -93,27 +87,20 @@ public class WebDisplays {
//Config
public static final double PAD_RATIO = 59.0 / 30.0;
public String homePage;
public double padResX;
public double padResY;
private int lastPadId = 0;
public boolean doHardRecipe;
private boolean hasOC;
private boolean hasCC;
private List<String> blacklist;
public boolean disableOwnershipThief;
public double unloadDistance2;
public double loadDistance2;
public int maxResX;
public int maxResY;
public int maxScreenX;
public int maxScreenY;
public int miniservPort;
public long miniservQuota;
public boolean enableSoundDistance;
public float ytVolume;
public float avDist100;
public float avDist0;
// mod detection
private boolean hasOC;
private boolean hasCC;
public WebDisplays() {
INSTANCE = this;
@ -122,27 +109,14 @@ public class WebDisplays {
} else {
PROXY = new SharedProxy();
}
AutoConfig.register(ModConfig.class, Toml4jConfigSerializer::new);
ConfigHolder<ModConfig> configHolder = AutoConfig.getConfigHolder(ModConfig.class);
ModConfig config = configHolder.getConfig();
configHolder.save();
this.blacklist = config.main.blacklist;
doHardRecipe = config.main.hardRecipes;
this.homePage = config.main.homepage;
disableOwnershipThief = config.main.disableOwnershipThief;
unloadDistance2 = config.client.unloadDistance * config.client.unloadDistance;
loadDistance2 = config.client.loadDistance * config.client.loadDistance;
this.maxResX = config.main.maxResolutionX;
this.maxResY = config.main.maxResolutionY;
this.miniservPort = config.main.miniservPort;
this.miniservQuota = config.main.miniservQuota * 1024L;
this.maxScreenX = config.main.maxScreenSizeX;
this.maxScreenY = config.main.maxScreenSizeY;
enableSoundDistance = config.client.autoVolumeControl.enableAutoVolume;
this.ytVolume = (float) config.client.autoVolumeControl.ytVolume;
avDist100 = (float) config.client.autoVolumeControl.dist100;
avDist0 = (float) config.client.autoVolumeControl.dist0;
if (FMLEnvironment.dist.isClient()) {
// proxies are annoying, so from now on, I'mma be just registering stuff in here
MinecraftForge.EVENT_BUS.addListener(ClientProxy::onDrawSelection);
ClientConfig.init();
}
CommonConfig.init();
CREATIVE_TAB = new WDCreativeTab();
@ -153,10 +127,6 @@ public class WebDisplays {
criterionKeyboardCat = new Criterion("keyboard_cat");
registerTrigger(criterionPadBreak, criterionUpgradeScreen, criterionLinkPeripheral, criterionKeyboardCat);
//Read configuration
padResY = config.main.padHeight;
padResX = padResY * PAD_RATIO;
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
WDNetworkRegistry.init();
SOUNDS.register(bus);
@ -166,11 +136,6 @@ public class WebDisplays {
ItemInit.registerUpgrade();
ItemInit.registerComponents();
TileInit.init(bus);
if (FMLEnvironment.dist.isClient()) {
// proxies are annoying, so from now on, I'mma be just registering stuff in here
MinecraftForge.EVENT_BUS.addListener(ClientProxy::onDrawSelection);
}
PROXY.preInit();
@ -308,7 +273,7 @@ public class WebDisplays {
@SubscribeEvent
public void onPlayerCraft(PlayerEvent.ItemCraftedEvent ev) {
if(doHardRecipe && ev.getCrafting().getItem() == ItemInit.itemCraftComp.get() && (CraftComponent.EXTCARD.makeItemStack().is(ev.getCrafting().getItem()))) {
if(CommonConfig.hardRecipes && ev.getCrafting().getItem() == ItemInit.itemCraftComp.get() && (CraftComponent.EXTCARD.makeItemStack().is(ev.getCrafting().getItem()))) {
if((ev.getEntity() instanceof ServerPlayer && !hasPlayerAdvancement((ServerPlayer) ev.getEntity(), ADV_PAD_BREAK)) || PROXY.hasClientPlayerAdvancement(ADV_PAD_BREAK) != HasAdvancement.YES) {
ev.getCrafting().setDamageValue(CraftComponent.BADEXTCARD.ordinal());
@ -437,7 +402,9 @@ public class WebDisplays {
public static boolean isSiteBlacklisted(String url) {
try {
URL url2 = new URL(Util.addProtocol(url));
return new ModConfig.Main().blacklist.stream().anyMatch(str -> str.equalsIgnoreCase(url2.getHost()));
for (String str : CommonConfig.Browser.blacklist)
if (str.equalsIgnoreCase(url2.getHost())) return true;
return false;
} catch(MalformedURLException ex) {
return false;
}
@ -446,6 +413,5 @@ public class WebDisplays {
public static String applyBlacklist(String url) {
return isSiteBlacklisted(url) ? BLACKLIST_URL : url;
}
}

View File

@ -32,6 +32,7 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.BlockHitResult;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.config.CommonConfig;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.core.ScreenRights;
@ -221,8 +222,8 @@ public class BlockScreen extends BaseEntityBlock {
return InteractionResult.SUCCESS;
}
if (size.x > WebDisplays.INSTANCE.maxScreenX || size.y > WebDisplays.INSTANCE.maxScreenY) {
Util.toast(player, "tooBig", WebDisplays.INSTANCE.maxScreenX, WebDisplays.INSTANCE.maxScreenY);
if (size.x > CommonConfig.Screen.maxScreenSizeX || size.y > CommonConfig.Screen.maxScreenSizeY) {
Util.toast(player, "tooBig", CommonConfig.Screen.maxScreenSizeX, CommonConfig.Screen.maxScreenSizeY);
return InteractionResult.SUCCESS;
}

View File

@ -58,6 +58,7 @@ import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.client.gui.*;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.renderers.*;
import net.montoyo.wd.config.ClientConfig;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.HasAdvancement;
import net.montoyo.wd.core.JSServerRequest;
@ -575,7 +576,7 @@ public class ClientProxy extends SharedProxy implements IDisplayHandler, IJSQuer
if(tes.isLoaded()) {
if(dist2 > WebDisplays.INSTANCE.unloadDistance2)
tes.unload();
else if(WebDisplays.INSTANCE.enableSoundDistance)
else if(ClientConfig.AutoVolumeControl.enableAutoVolume)
tes.updateTrackDistance(dist2, 80); //ToDo find master volume
} else if(dist2 <= WebDisplays.INSTANCE.loadDistance2)
tes.load();

View File

@ -0,0 +1,103 @@
package net.montoyo.wd.config;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.config.annoconfg.AnnoCFG;
import net.montoyo.wd.config.annoconfg.annotation.format.*;
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
import net.montoyo.wd.config.annoconfg.annotation.value.DoubleRange;
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
@Config(type = ModConfig.Type.CLIENT)
public class ClientConfig {
@SuppressWarnings("unused")
private static final AnnoCFG CFG = new AnnoCFG(FMLJavaModLoadingContext.get().getModEventBus(), ClientConfig.class);
public static void init() {
// loads the class
}
@Name("load_distance")
@Comment("How far (in blocks) you can be before a screen starts rendering")
@Translation("config.webdisplays.load_distance")
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
@Default(valueD = 32)
public static double loadDistance = 30.0;
@Name("unload_distance")
@Comment("How far you can be before a screen stops rendering")
@Translation("config.webdisplays.unload_distance")
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
@Default(valueD = 32)
public static double unloadDistance = 32.0;
@Name("pad_resolution")
@Comment({
"The resolution that minePads should use",
"Smaller values produce lower qualities, higher values produce higher qualities",
"Due to how web browsers work however, the larger this value is, the smaller text is",
"Also, higher values will invariably lag more",
"A good goto value for this would be the height of your monitor, in pixels",
"A standard monitor is (at least currently) 1080"
})
@Translation("config.webdisplays.pad_res")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueI = 720)
public static int padResolution = 720;
@Comment({
"AutoVolume makes audio fade off based on distance",
"Currently, this seems to not work"
})
@CFGSegment("auto_volume")
public static class AutoVolumeControl {
@Name("enabled")
@Comment("Whether or not auto volume should be enabled")
@Translation("config.webdisplays.auto_vol")
@Default(valueBoolean = true)
public static boolean enableAutoVolume = true;
@Name("youtube_volume")
@Comment("How loud youtube should be by default")
@Translation("config.webdisplays.yt_vol")
@DoubleRange(minV = 0, maxV = 100)
@Default(valueD = 100)
public static double ytVolume = 100.0;
@Name("dist0")
@Comment("Distance after which you can't hear anything (in blocks)")
@Translation("config.webdisplays.d0")
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
@Default(valueD = 30)
public static double dist0 = 30.0;
@Name("dist100")
@Comment("Distance after which the sound starts dropping (in blocks)")
@Translation("config.webdisplays.d100")
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
@Default(valueD = 10)
public static double dist100 = 10.0;
}
@SuppressWarnings("unused")
public static void postLoad() {
if (unloadDistance < loadDistance + 2.0)
unloadDistance = loadDistance + 2.0;
if (AutoVolumeControl.dist0 < AutoVolumeControl.dist100 + 0.1)
AutoVolumeControl.dist0 = AutoVolumeControl.dist100 + 0.1;
// cache pad resolution
WebDisplays.INSTANCE.padResY = padResolution;
WebDisplays.INSTANCE.padResX = WebDisplays.INSTANCE.padResY * WebDisplays.PAD_RATIO;
// cache unload/load distances
WebDisplays.INSTANCE.unloadDistance2 = unloadDistance * unloadDistance;
WebDisplays.INSTANCE.loadDistance2 = loadDistance * loadDistance;
WebDisplays.INSTANCE.ytVolume = (float) AutoVolumeControl.ytVolume;
WebDisplays.INSTANCE.avDist100 = (float) AutoVolumeControl.dist100;
WebDisplays.INSTANCE.avDist0 = (float) AutoVolumeControl.dist0;
}
}

View File

@ -0,0 +1,121 @@
package net.montoyo.wd.config;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.config.annoconfg.AnnoCFG;
import net.montoyo.wd.config.annoconfg.annotation.format.*;
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
import net.montoyo.wd.config.annoconfg.annotation.value.LongRange;
@SuppressWarnings("DefaultAnnotationParam")
@Config(type = ModConfig.Type.COMMON)
public class CommonConfig {
@SuppressWarnings("unused")
private static final AnnoCFG CFG = new AnnoCFG(FMLJavaModLoadingContext.get().getModEventBus(), CommonConfig.class);
public static void init() {
// loads the class
}
@Name("hard_recipes")
@Comment("If true, breaking the minePad is required to craft upgrades.")
@Translation("config.webdisplays.hard_recipes")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueBoolean = true)
public static boolean hardRecipes = true;
@Name("disable_ownership_thief")
@Comment("If true, the ownership thief item will be disabled")
@Translation("config.webdisplays.disable_thief")
@Default(valueBoolean = false)
public static boolean disableOwnershipThief = false;
@Comment("Options for the browsers (both the minePad and the screens)")
@CFGSegment("browser_options")
public static class Browser {
@Name("home_page")
@Comment("The page which screens should open up to when turning on")
@Translation("config.webdisplays.blacklist")
public static String[] blacklist = new String[0];
@Name("home_page")
@Comment("The page which screens should open up to when turning on")
@Translation("config.webdisplays.home_page")
@Default(valueStr = "https://www.google.com")
public static String homepage = "https://www.google.com";
}
@Comment("Options for the in world screen blocks")
@CFGSegment("screen_options")
public static class Screen {
@Name("max_resolution_x")
@Comment("The maximum value screen's horizontal resolution, in pixels")
@Translation("config.webdisplays.max_res_x")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueI = 1920)
public static int maxResolutionX = 1920;
@Name("max_resolution_y")
@Comment("The maximum value screen's vertical resolution, in pixels")
@Translation("config.webdisplays.max_res_y")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueI = 1920)
public static int maxResolutionY = 1080;
@Name("max_width")
@Comment("The maximum width for the screen multiblock, in blocks")
@Translation("config.webdisplays.max_width")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueI = 16)
public static int maxScreenSizeX = 16;
@Name("max_height")
@Comment("The maximum height for the screen multiblock, in blocks")
@Translation("config.webdisplays.max_height")
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
@Default(valueI = 16)
public static int maxScreenSizeY = 16;
}
@Comment("Options for the miniserver")
@CFGSegment("mini_server")
public static class MiniServ {
@Name("miniserv_port")
@Comment("The port used by miniserv. 0 to disable")
@Translation("config.webdisplays.miniserv_port")
@IntRange(minV = 0, maxV = Short.MAX_VALUE)
@Default(valueI = 25566)
public static int miniservPort = 25566;
@Name("miniserv_quota")
@Comment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)")
@Translation("config.webdisplays.miniserv_quota")
@LongRange(minV = 0, maxV = Long.MAX_VALUE)
@Default(valueL = 1920)
public static long miniservQuota = 1024; //It's stored as a string anyway
}
@SuppressWarnings("unused")
public static void postLoad() {
WebDisplays.INSTANCE.miniservPort = MiniServ.miniservPort;
WebDisplays.INSTANCE.miniservQuota = MiniServ.miniservQuota * 1024L;
}
// //Comments & shit
// blacklist.setComment("An array of domain names you don't want to load.");
// padHeight.setComment("The minePad Y resolution in pixels. padWidth = padHeight * " + PAD_RATIO);
// hardRecipe.setComment("If true, breaking the minePad is required to craft upgrades.");
// homePage.setComment("The URL that will be loaded each time you create a screen");
// disableOT.setComment("If true, the ownership thief item will be disabled");
// loadDistance.setComment("All screens outside this range will be unloaded");
// unloadDistance.setComment("All unloaded screens inside this range will be loaded");
// maxResX.setComment("Maximum horizontal screen resolution, in pixels");
// maxResY.setComment("Maximum vertical screen resolution, in pixels");
// miniservPort.setComment("The port used by miniserv. 0 to disable.");
// miniservPort.setMaxValue(Short.MAX_VALUE);
// miniservQuota.setComment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)");
// maxScreenX.setComment("Maximum screen width, in blocks. Resolution will be clamped by maxResolutionX.");
// maxScreenY.setComment("Maximum screen height, in blocks. Resolution will be clamped by maxResolutionY.");
}

View File

@ -1,120 +0,0 @@
package net.montoyo.wd.config;
import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.annotation.Config;
import me.shedaniel.autoconfig.annotation.ConfigEntry;
import net.minecraft.util.Mth;
import java.util.List;
@Config(name = "webdisplays")
public class ModConfig implements ConfigData {
@ConfigEntry.Category("main")
public Main main = new Main();
@ConfigEntry.Category("client")
public Client client = new Client();
public static class Main {
@ConfigEntry.Gui.Tooltip
public List<String> blacklist = List.of();
@ConfigEntry.Gui.Tooltip
public int padHeight = 480;
@ConfigEntry.Gui.Tooltip
public boolean hardRecipes = true;
@ConfigEntry.Gui.Tooltip
public String homepage = "https://www.google.com";
@ConfigEntry.Gui.Tooltip
public boolean disableOwnershipThief = false;
@ConfigEntry.Gui.Tooltip
public int maxResolutionX = 1920;
@ConfigEntry.Gui.Tooltip
public int maxResolutionY = 1080;
@ConfigEntry.Gui.Tooltip
@ConfigEntry.BoundedDiscrete(max = Short.MAX_VALUE)
public int miniservPort = 25566;
@ConfigEntry.Gui.Tooltip
public long miniservQuota = 1024; //It's stored as a string anyway
@ConfigEntry.Gui.Tooltip
public int maxScreenSizeX = 16;
@ConfigEntry.Gui.Tooltip
public int maxScreenSizeY = 16;
}
public static class Client {
@ConfigEntry.Gui.Tooltip
public double loadDistance = 30.0;
@ConfigEntry.Gui.Tooltip
public double unloadDistance = 32.0;
@ConfigEntry.Gui.CollapsibleObject()
public AutoVolumeControl autoVolumeControl = new AutoVolumeControl();
public static class AutoVolumeControl {
@ConfigEntry.Gui.Tooltip
public boolean enableAutoVolume = true;
@ConfigEntry.Gui.Tooltip
public double ytVolume = 100.0;
@ConfigEntry.Gui.Tooltip
public double dist100 = 10.0;
@ConfigEntry.Gui.Tooltip
public double dist0 = 30.0;
}
}
@Override
public void validatePostLoad() throws ValidationException {
ConfigData.super.validatePostLoad();
main.miniservPort = Mth.clamp(main.miniservPort, 0, Short.MAX_VALUE);
client.autoVolumeControl.ytVolume = Mth.clamp(client.autoVolumeControl.ytVolume, 0.0, 100.0);
client.autoVolumeControl.dist0 = Mth.clamp(client.autoVolumeControl.dist0, 0.0, Double.MAX_VALUE);
client.autoVolumeControl.ytVolume = Mth.clamp(client.autoVolumeControl.dist100, 0.0, Double.MAX_VALUE);
if(client.unloadDistance < client.loadDistance + 2.0) {
client.unloadDistance = client.loadDistance + 2.0;
}
if(client.autoVolumeControl.dist0 < client.autoVolumeControl.dist100 + 0.1) {
client.autoVolumeControl.dist0 = client.autoVolumeControl.dist100 + 0.1;
}
}
// //Comments & shit
// blacklist.setComment("An array of domain names you don't want to load.");
// padHeight.setComment("The minePad Y resolution in pixels. padWidth = padHeight * " + PAD_RATIO);
// hardRecipe.setComment("If true, breaking the minePad is required to craft upgrades.");
// homePage.setComment("The URL that will be loaded each time you create a screen");
// disableOT.setComment("If true, the ownership thief item will be disabled");
// loadDistance.setComment("All screens outside this range will be unloaded");
// unloadDistance.setComment("All unloaded screens inside this range will be loaded");
// maxResX.setComment("Maximum horizontal screen resolution, in pixels");
// maxResY.setComment("Maximum vertical screen resolution, in pixels");
// miniservPort.setComment("The port used by miniserv. 0 to disable.");
// miniservPort.setMaxValue(Short.MAX_VALUE);
// miniservQuota.setComment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)");
// maxScreenX.setComment("Maximum screen width, in blocks. Resolution will be clamped by maxResolutionX.");
// maxScreenY.setComment("Maximum screen height, in blocks. Resolution will be clamped by maxResolutionY.");
// enableAutoVol.setComment("If true, the volume of YouTube videos will change depending on how far you are");
// ytVolume.setComment("Volume for YouTube videos. This will have no effect if enableSoundDistance is set to false");
// ytVolume.setMinValue(0.0);
// ytVolume.setMaxValue(100.0);
// dist100.setComment("Distance after which the sound starts dropping (in blocks)");
// dist100.setMinValue(0.0);
// dist0.setComment("Distance after which you can't hear anything (in blocks)");
// dist0.setMinValue(0.0);
}

View File

@ -0,0 +1,215 @@
package net.montoyo.wd.config.annoconfg;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.montoyo.wd.config.annoconfg.annotation.format.*;
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
import net.montoyo.wd.config.annoconfg.annotation.value.DoubleRange;
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
import net.montoyo.wd.config.annoconfg.annotation.value.LongRange;
import net.montoyo.wd.config.annoconfg.handle.UnsafeHandle;
import net.montoyo.wd.config.annoconfg.util.EnumType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.Supplier;
public class AnnoCFG {
private ForgeConfigSpec mySpec;
private final HashMap<String, ConfigEntry> handles = new HashMap<>();
private static final ArrayList<AnnoCFG> configs = new ArrayList<>();
private final Method postInit;
public AnnoCFG(IEventBus bus, Class<?> clazz) {
bus.addListener(this::onConfigChange);
ForgeConfigSpec.Builder configBuilder = new ForgeConfigSpec.Builder();
setup("", configBuilder, clazz);
configs.add(this);
Method m = null;
try {
m = clazz.getDeclaredMethod("postLoad");
} catch (Throwable ignored) {
}
postInit = m;
Config configDescriptor = clazz.getAnnotation(Config.class);
if (configDescriptor != null) {
String pth = configDescriptor.path();
if (!pth.isEmpty()) pth = pth + "/";
switch (configDescriptor.type()) {
case SERVER -> create(ModConfig.Type.SERVER, pth + ModLoadingContext.get().getActiveNamespace() + "_server.toml");
case CLIENT -> create(ModConfig.Type.CLIENT, pth + ModLoadingContext.get().getActiveNamespace() + "_client.toml");
case COMMON -> create(ModConfig.Type.COMMON, pth + ModLoadingContext.get().getActiveNamespace() + "_common.toml");
default -> throw new RuntimeException("wat");
}
}
}
protected void setupCommentsAndTranslations(AnnotatedElement element, ForgeConfigSpec.Builder builder, String... additionalLines) {
Translation translation = element.getAnnotation(Translation.class);
Comment comment = element.getAnnotation(Comment.class);
StringBuilder builder1 = new StringBuilder();
if (comment != null) {
for (int i = 0; i < comment.value().length; i++) {
String s = comment.value()[i];
builder1.append(s);
if (i != comment.value().length - 1)
builder1.append("\n");
}
}
for (String additionalLine : additionalLines) builder1.append(additionalLine);
if (!builder1.isEmpty())
builder.comment(builder1.toString());
if (translation != null)
builder.translation(translation.value());
}
public void setup(String dir, ForgeConfigSpec.Builder builder, Class<?> clazz) {
if (dir.startsWith(".")) dir = dir.substring(1);
for (Field field : clazz.getFields()) {
if (field.canAccess(null)) {
Skip skip = field.getAnnotation(Skip.class);
if (skip != null) continue;
Name name = field.getAnnotation(Name.class);
String nameStr = field.getName();
if (name != null) nameStr = name.value();
setupCommentsAndTranslations(field, builder);
Supplier<?> value;
Default defaultValue = field.getAnnotation(Default.class);
try {
switch (EnumType.forClass(field.getType())) {
case INT -> {
IntRange range = field.getAnnotation(IntRange.class);
int v = defaultValue.valueI();
if (range != null) {
int min = range.minV();
int max = range.maxV();
value = builder.defineInRange(nameStr, v, min, max);
} else {
value = builder.define(nameStr, v);
}
}
case LONG -> {
LongRange range = field.getAnnotation(LongRange.class);
long v = defaultValue.valueL();
if (range != null) {
long min = range.minV();
long max = range.maxV();
value = builder.defineInRange(nameStr, v, min, max);
} else {
value = builder.define(nameStr, v);
}
}
case DOUBLE -> {
DoubleRange range = field.getAnnotation(DoubleRange.class);
double v = defaultValue.valueD();
if (range != null) {
double min = range.minV();
double max = range.maxV();
value = builder.defineInRange(nameStr, v, min, max);
} else {
value = builder.define(nameStr, v);
}
}
case BOOLEAN -> {
boolean b = defaultValue.valueBoolean();
value = builder.define(nameStr, b);
}
case OTHER -> {
Class<?> fieldType = field.getType();
if (fieldType.equals(String[].class)) {
value = builder.define(nameStr, new String[0]);
} else if (fieldType.equals(String.class)) {
String def = defaultValue.valueStr();
value = builder.define(nameStr, def);
} else
throw new RuntimeException("NYI " + field.getType());
}
default -> throw new RuntimeException("NYI " + field.getType());
}
} catch (NullPointerException npe) {
String inf = "";
if (npe.getMessage().contains("\"value.Default\"")) inf = " this is likely due to a missing default.";
throw new RuntimeException("A null pointer occurred on " + field.getName() + inf, npe);
}
Object o;
try {
// without this line, this system freaks out due to using theUnsafe
//noinspection UnusedAssignment
o = field.get(null);
} catch (Throwable ignored) {
}
UnsafeHandle handle = new UnsafeHandle(field);
o = handle.get();
handle.set(o);
//noinspection FunctionalExpressionCanBeFolded
handles.put(dir + "." + nameStr, new ConfigEntry(
handle, value::get
));
}
}
// TODO: check if the nested class is a direct nesting
for (Class<?> nestMember : clazz.getClasses()) {
if (nestMember == clazz) continue;
if (!nestMember.getName().startsWith(clazz.getName())) continue;
CFGSegment segment = nestMember.getAnnotation(CFGSegment.class);
if (segment == null) {
System.out.println(nestMember);
throw new RuntimeException("NYI: default name");
}
String name = segment.value();
setupCommentsAndTranslations(nestMember, builder);
builder.push(name);
setup(dir + "." + name, builder, nestMember);
builder.pop();
}
mySpec = builder.build();
}
public void onConfigChange(ModConfigEvent event) {
if (
event.getConfig().getSpec().equals(mySpec) ||
event.getConfig().getSpec() == mySpec
) {
for (String s : handles.keySet()) {
ConfigEntry entry = handles.get(s);
entry.handle.set(entry.supplier.get());
}
}
try {
postInit.invoke(null);
} catch (Throwable err) {
err.printStackTrace();
}
}
public void create(ModConfig.Type type, String file) {
ModLoadingContext.get().registerConfig(type, mySpec, file);
}
}

View File

@ -0,0 +1,15 @@
package net.montoyo.wd.config.annoconfg;
import net.montoyo.wd.config.annoconfg.handle.UnsafeHandle;
import java.util.function.Supplier;
public class ConfigEntry {
UnsafeHandle handle;
Supplier<?> supplier;
public ConfigEntry(UnsafeHandle handle, Supplier<?> supplier) {
this.handle = handle;
this.supplier = supplier;
}
}

View File

@ -0,0 +1,9 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface CFGSegment {
String value();
}

View File

@ -0,0 +1,9 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Comment {
String[] value();
}

View File

@ -0,0 +1,12 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import net.minecraftforge.fml.config.ModConfig;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
ModConfig.Type type();
String path() default "";
}

View File

@ -0,0 +1,9 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Name {
String value();
}

View File

@ -0,0 +1,8 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Skip {
}

View File

@ -0,0 +1,9 @@
package net.montoyo.wd.config.annoconfg.annotation.format;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Translation {
String value();
}

View File

@ -0,0 +1,16 @@
package net.montoyo.wd.config.annoconfg.annotation.value;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Default {
byte valueB() default 0;
short valueS() default 0;
int valueI() default 0;
long valueL() default 0;
float valueF() default 0;
double valueD() default 0;
boolean valueBoolean() default false;
String valueStr() default "";
}

View File

@ -0,0 +1,10 @@
package net.montoyo.wd.config.annoconfg.annotation.value;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DoubleRange {
double minV();
double maxV();
}

View File

@ -0,0 +1,10 @@
package net.montoyo.wd.config.annoconfg.annotation.value;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
int minV();
int maxV();
}

View File

@ -0,0 +1,10 @@
package net.montoyo.wd.config.annoconfg.annotation.value;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface LongRange {
long minV();
long maxV();
}

View File

@ -0,0 +1,86 @@
package net.montoyo.wd.config.annoconfg.handle;
import net.montoyo.wd.config.annoconfg.util.EnumType;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class UnsafeHandle {
private static final Unsafe theUnsafe;
static {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
theUnsafe = (Unsafe) f.get(null);
} catch (Throwable ignored) {
throw new RuntimeException("AnnoConfg: Failed to acquire an instance of the unsafe.");
}
}
private final long offset;
private final Consumer<Object> uploader;
private final Supplier<Object> getter;
public UnsafeHandle(Field f) {
this(null, f);
}
public UnsafeHandle(Object relative, Field f) {
offset = theUnsafe.staticFieldOffset(f);
if (relative == null) relative = theUnsafe.staticFieldBase(f);
Object finalRelative = relative;
if (f.getType().isPrimitive()) {
switch (EnumType.forClass(f.getType())) {
case BYTE -> {
uploader = (v) -> theUnsafe.putByte(finalRelative, offset, (byte) v);
getter = () -> theUnsafe.getByte(finalRelative, offset);
}
case SHORT -> {
uploader = (v) -> theUnsafe.putShort(finalRelative, offset, (short) v);
getter = () -> theUnsafe.getShort(finalRelative, offset);
}
case INT -> {
uploader = (v) -> theUnsafe.putInt(finalRelative, offset, (int) v);
getter = () -> theUnsafe.getInt(finalRelative, offset);
}
case LONG -> {
uploader = (v) -> theUnsafe.putLong(finalRelative, offset, (long) v);
getter = () -> theUnsafe.getLong(finalRelative, offset);
}
case FLOAT -> {
uploader = (v) -> theUnsafe.putFloat(finalRelative, offset, (float) v);
getter = () -> theUnsafe.getFloat(finalRelative, offset);
}
case DOUBLE -> {
uploader = (v) -> theUnsafe.putDouble(finalRelative, offset, (double) v);
getter = () -> theUnsafe.getDouble(finalRelative, offset);
}
case BOOLEAN -> {
uploader = (v) -> theUnsafe.putBoolean(finalRelative, offset, (boolean) v);
getter = () -> theUnsafe.getBoolean(finalRelative, offset);
}
default -> {
// TODO: check that I have all primitives?
uploader = null;
getter = () -> null;
}
}
} else {
uploader = (v) -> theUnsafe.putObject(finalRelative, offset, v);
getter = () -> theUnsafe.getObject(finalRelative, offset);
}
}
public void set(Object o) {
uploader.accept(o);
// System.out.println(getter.get());
}
public Object get() {
return getter.get();
}
}

View File

@ -0,0 +1,25 @@
package net.montoyo.wd.config.annoconfg.util;
public enum EnumType {
BYTE(byte.class),
SHORT(short.class),
INT(int.class),
LONG(long.class),
FLOAT(float.class),
DOUBLE(double.class),
BOOLEAN(boolean.class),
OTHER(Object.class),
;
Class<?> clazz;
EnumType(Class<?> clazz) {
this.clazz = clazz;
}
public static EnumType forClass(Class<?> clazz) {
for (EnumType value : EnumType.values())
if (value.clazz.equals(clazz)) return value;
return OTHER;
}
}

View File

@ -5,8 +5,6 @@
package net.montoyo.wd.core;
import net.minecraft.world.item.ItemStack;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.config.ModConfig;
import net.montoyo.wd.init.ItemInit;
public enum DefaultUpgrade {

View File

@ -29,6 +29,7 @@ import net.montoyo.mcef.api.IBrowser;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.config.CommonConfig;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.core.JSServerRequest;
@ -207,16 +208,16 @@ public class TileEntityScreen extends BlockEntity {
public void clampResolution() {
if (resolution.x > WebDisplays.INSTANCE.maxResX) {
float newY = ((float) resolution.y) * ((float) WebDisplays.INSTANCE.maxResX) / ((float) resolution.x);
resolution.x = WebDisplays.INSTANCE.maxResX;
if (resolution.x > CommonConfig.Screen.maxResolutionX) {
float newY = ((float) resolution.y) * ((float) CommonConfig.Screen.maxResolutionX) / ((float) resolution.x);
resolution.x = CommonConfig.Screen.maxResolutionX;
resolution.y = (int) newY;
}
if (resolution.y > WebDisplays.INSTANCE.maxResY) {
float newX = ((float) resolution.x) * ((float) WebDisplays.INSTANCE.maxResY) / ((float) resolution.y);
if (resolution.y > CommonConfig.Screen.maxResolutionY) {
float newX = ((float) resolution.x) * ((float) CommonConfig.Screen.maxResolutionY) / ((float) resolution.y);
resolution.x = (int) newX;
resolution.y = WebDisplays.INSTANCE.maxResY;
resolution.y = CommonConfig.Screen.maxResolutionY;
}
}
@ -303,7 +304,7 @@ public class TileEntityScreen extends BlockEntity {
Screen ret = new Screen();
ret.side = side;
ret.size = size;
ret.url = WebDisplays.INSTANCE.homePage;
ret.url = CommonConfig.Browser.homepage;
ret.friends = new ArrayList<>();
ret.friendRights = ScreenRights.DEFAULTS;
ret.otherRights = ScreenRights.DEFAULTS;

View File

@ -18,6 +18,7 @@ import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.config.CommonConfig;
import net.montoyo.wd.core.CraftComponent;
import javax.annotation.Nonnull;
@ -37,7 +38,7 @@ public class ItemMinePad2 extends Item implements WDItem {
private static String getURL(ItemStack is) {
if (is.getTag() == null || !is.getTag().contains("PadURL"))
return WebDisplays.INSTANCE.homePage;
return CommonConfig.Browser.homepage;
else
return is.getTag().getString("PadURL");
}

View File

@ -14,6 +14,7 @@ import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.config.CommonConfig;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.*;
import org.jetbrains.annotations.NotNull;
@ -38,7 +39,7 @@ public class ItemOwnershipThief extends Item implements WDItem {
if(context.getLevel().isClientSide)
return InteractionResult.SUCCESS;
if(WebDisplays.INSTANCE.disableOwnershipThief) {
if(CommonConfig.disableOwnershipThief) {
Util.toast(context.getPlayer(), "otDisabled");
return InteractionResult.SUCCESS;
}

View File

@ -12,7 +12,7 @@ modId="webdisplays" #mandatory
version="1.0.0" #mandatory
displayName="MCEF" #mandatory
displayName="WebDisplays" #mandatory
displayURL="https://github.com/Mysticpasta1/webdisplays" #optional