Skip to content

Commit

Permalink
change config to ini. default invis armor stands to off (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
SFort committed Mar 23, 2023
1 parent b809c56 commit cc43680
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 75 deletions.
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ archivesBaseName = project.archives_base_name
version = project.mod_version
group = project.maven_group

repositories {
maven {
url = "https://maven.ssf.tf/"
}
}

dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation include ("tf.ssf.sfort.ini:SF-INI:${project.sfini_version}")
}

processResources {
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ org.gradle.jvmargs=-Xmx1G
minecraft_version=1.19
yarn_mappings=1.19+build.1
loader_version=0.12.6
sfini_version=1

# Mod Properties
mod_version = 2.2.0
mod_version = 2.2.1
maven_group = tf.ssf.sfort
archives_base_name = invisframes
23 changes: 23 additions & 0 deletions src/main/java/tf/ssf/sfort/invisframes/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tf.ssf.sfort.invisframes;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Config {
public static Logger LOGGER = LogManager.getLogger();
public enum ItemCheck {
CLIENT(true, false),
SERVER(false, true),
BOTH(true, true),
NONE(false, false);
public final boolean client;
public final boolean server;
ItemCheck(boolean client, boolean server) {
this.client = client;
this.server = server;
}
}
public enum NameCheck {
NEVER, ALWAYS, INVIS_ONLY
}
}
65 changes: 65 additions & 0 deletions src/main/java/tf/ssf/sfort/invisframes/ConfigLegacy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package tf.ssf.sfort.invisframes;

import net.fabricmc.loader.api.FabricLoader;
import org.apache.logging.log4j.Level;
import tf.ssf.sfort.ini.SFIni;

import java.io.File;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConfigLegacy {
public static void loadLegacy(SFIni inIni) {
Map<String, String> oldConf = new HashMap<>();
File confFile = new File(
FabricLoader.getInstance().getConfigDir().toString(),
"InvisFrames.conf"
);
if (!confFile.exists()) return;
try {
List<String> la = Files.readAllLines(confFile.toPath());
String[] ls = la.toArray(new String[Math.max(la.size(), 18)|1]);

try{
oldConf.put("frame.clientForceInvis", Boolean.toString(ls[0].contains("true")));
}catch (Exception ignore){}
try{
oldConf.put("frame.allowProjectile", Boolean.toString(ls[2].contains("true")));
}catch (Exception ignore){}
try{
oldConf.put("frame.itemCheck", ls[4].contains("both")? "both" : ls[4].contains("server")? "server" : ls[4].contains("none")? "none" : "client");
}catch (Exception ignore){}
try {
oldConf.put("frame.clientHideCustomName", ls[6].contains("always") ? "always" : ls[6].contains("invis_only") ? "invis_only" : "never");
} catch (Exception ignore) {}
try{
oldConf.put("frame.equipSound", Boolean.toString(!ls[8].contains("false")));
}catch (Exception ignore){}
try{
oldConf.put("frame.toggleable", Boolean.toString(!ls[10].contains("false")));
}catch (Exception ignore){}
try{
oldConf.put("stand.toggleable", Boolean.toString(!ls[12].contains("false")));
}catch (Exception ignore){}
try{
oldConf.put("stand.allowProjectile", Boolean.toString(ls[14].contains("true")));
}catch (Exception ignore){}
try{
oldConf.put("stand.itemCheck", ls[16].contains("both")? "both" : ls[16].contains("server")? "server" : ls[16].contains("none")? "none" : "client");
}catch (Exception ignore){}
for (Map.Entry<String, String> entry : oldConf.entrySet()) {
SFIni.Data data = inIni.getLastData(entry.getKey());
if (data != null) {
data.val = entry.getValue();
}
}

Files.delete(confFile.toPath());
Config.LOGGER.log(Level.INFO,"tf.ssf.sfort.invisframes successfully loaded legacy config file");
} catch(Exception e) {
Config.LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to load legacy config file\n"+e);
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/tf/ssf/sfort/invisframes/InvisFramesShared.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package tf.ssf.sfort.invisframes;

import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.item.ItemStack;

public class InvisFramesShared {
public static boolean IsEmpty(ArmorStandEntity entity) {
for (ItemStack item : entity.getArmorItems())
if (!item.isEmpty())
return false;
return true;
}
}
177 changes: 106 additions & 71 deletions src/main/java/tf/ssf/sfort/invisframes/mixin/FrameConf.java
Original file line number Diff line number Diff line change
@@ -1,103 +1,144 @@
package tf.ssf.sfort.invisframes.mixin;

import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.item.ItemStack;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import tf.ssf.sfort.ini.SFIni;
import tf.ssf.sfort.invisframes.Config;
import tf.ssf.sfort.invisframes.ConfigLegacy;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Consumer;

public class FrameConf implements IMixinConfigPlugin {
public static final String mixin = "tf.ssf.sfort.invisframes.mixin";
public static Logger LOGGER = LogManager.getLogger();

public static boolean clientForceInvis = false;
public static boolean allowFrameProjectile = false;
public static boolean allowStandProjectile = false;
public static boolean playFrameSound = true;
public static boolean enableInvisFrames = true;
public static boolean enableInvisStands = true;
//byte0-client, byte1-server
public static int frameItemCheck = 1;
public static int standItemCheck = 1;
public static int clientHideFrameNames = 0;
public static boolean enableInvisStands = false;
public static Config.ItemCheck frameItemCheck = Config.ItemCheck.CLIENT;
public static Config.ItemCheck standItemCheck = Config.ItemCheck.NONE;
public static Config.NameCheck clientHideFrameNames = Config.NameCheck.NEVER;

@Override
public void onLoad(String mixinPackage) {
// Configs
loadConfig();
}
public void loadConfig() {
SFIni defIni = new SFIni();
defIni.load(String.join("\n", new String[]{
"; Enable invisible item frame toggle [true] true | false",
"frame.toggleable=true",
"; Should client always make frames with items invisible [false] true | false",
"; You might want to use this if the mod is installed client side",
"frame.clientForceInvis=false",
"; Allow the use of projectiles for changing frame visibility [false] true | false",
"; For example shift throwing a snowball or firing an arrow",
"frame.allowProjectile=false",
"; Frame has item check [client] client | server | both | none",
"; the item check makes the frame visible when it contains an item",
"frame.itemCheck=client",
"; Client hide item frame item names [never] never | always | invis_only",
"frame.clientHideCustomName=never",
"; Frame plays equip sound on toggle [true] true | false",
"frame.equipSound=true",
"; Enable armor stand toggle [false] true | false",
"stand.toggleable=false",
"; Allow the use of projectiles for changing armor stand visibility [false] true | false",
"; For example shift throwing a snowball or firing an arrow",
"stand.allowProjectile=false",
"; Armor stand has item check [none] client | server | both | none",
"; the item check makes the frame visible when it contains an item",
"stand.itemCheck=none",
}));
ConfigLegacy.loadLegacy(defIni);
File confFile = new File(
FabricLoader.getInstance().getConfigDir().toString(),
"InvisFrames.conf"
"InvisFrames.sf.ini"
);
try {
confFile.createNewFile();
List<String> la = Files.readAllLines(confFile.toPath());
List<String> defaultDesc = Arrays.asList(
"^-Should client always make frames with items invisible [false] true | false // You would want to use this if the mod is installed client side only",
"^-Allow the use of projectiles for changing frame visibility [false] true | false //snowballs arrows etc",
"^-Frame has item check [client] client | server | both | none",
"^-Frame hides item names [never] never | always | invis_only // client-side only",
"^-Frame plays equip sound on being toggled [true] true | false",
"^-Enable invis item frames [true] true | false",
"^-Enable invis armor stands [true] true | false",
"^-Allow the use of projectiles for changing armor stand visibility [false] true | false",
"^-Armor Stand has item check [client] client | server | both | none"
);
String[] ls = la.toArray(new String[Math.max(la.size(), defaultDesc.size() * 2)|1]);
for (int i = 0; i<defaultDesc.size();++i)
ls[i*2+1]= defaultDesc.get(i);

try{clientForceInvis = ls[0].contains("true");}catch (Exception ignore){}
ls[0] = String.valueOf(clientForceInvis);
try{
allowFrameProjectile = ls[2].contains("true");}catch (Exception ignore){}
ls[2] = String.valueOf(allowFrameProjectile);
try{
frameItemCheck = (ls[4].contains("both")? 3 : ls[4].contains("server")? 2 : ls[4].contains("none")? 0 : 1);}catch (Exception ignore){}
ls[4] = frameItemCheck == 3 ? "both" : frameItemCheck == 2 ? "server": frameItemCheck == 0 ? "none" : "client";
if (!confFile.exists()) {
try {
clientHideFrameNames = ls[6].contains("always") ? 1 : ls[6].contains("invis_only") ? 2 : 0;
} catch (Exception ignore) {}
ls[6] = clientHideFrameNames == 2 ? "invis_only" : clientHideFrameNames == 1 ? "always" : "never";
try{playFrameSound = !ls[8].contains("false");}catch (Exception ignore){}
ls[8] = String.valueOf(playFrameSound);
try{enableInvisFrames = !ls[10].contains("false");}catch (Exception ignore){}
ls[10] = String.valueOf(enableInvisFrames);
try{enableInvisStands = !ls[12].contains("false");}catch (Exception ignore){}
ls[12] = String.valueOf(enableInvisStands);
try{allowStandProjectile = ls[14].contains("true");}catch (Exception ignore){}
ls[14] = String.valueOf(allowStandProjectile);
try{
standItemCheck = (ls[16].contains("both")? 3 : ls[16].contains("server")? 2 : ls[16].contains("none")? 0 : 1);}catch (Exception ignore){}
ls[16] = standItemCheck == 3 ? "both" : standItemCheck == 2 ? "server": standItemCheck == 0 ? "none" : "client";

Files.write(confFile.toPath(), Arrays.asList(ls));
LOGGER.log(Level.INFO,"tf.ssf.sfort.invisframes successfully loaded config file");
Files.write(confFile.toPath(), defIni.toString().getBytes());
loadIni(defIni);
} catch (IOException e) {
Config.LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to create config file, using defaults", e);
}
return;
}
try {
SFIni ini = new SFIni();
String text = Files.readString(confFile.toPath());
int hash = text.hashCode();
ini.load(text);
for (Map.Entry<String, List<SFIni.Data>> entry : defIni.data.entrySet()) {
List<SFIni.Data> list = ini.data.get(entry.getKey());
if (list == null || list.isEmpty()) {
ini.data.put(entry.getKey(), entry.getValue());
} else {
list.get(0).comments = entry.getValue().get(0).comments;
}
}
loadIni(ini);
String iniStr = ini.toString();
if (hash != iniStr.hashCode()) {
Files.write(confFile.toPath(), iniStr.getBytes());
}
} catch(Exception e) {
LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to load config file, using defaults\n"+e);
Config.LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to load config file, using defaults\n"+e);
}
}
public static<E extends Enum<E>> void setOrResetEnum(SFIni ini, String key, Consumer<E> set, E en, Class<E> clazz) {
try {
set.accept(ini.getEnum(key, clazz));
} catch (Exception e) {
SFIni.Data data = ini.getLastData(key);
if (data != null) data.val = en.name().toLowerCase(Locale.ROOT);
Config.LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to load "+key+", setting to default value", e);
}
}
public static void setOrResetBool(SFIni ini, String key, Consumer<Boolean> set, boolean bool) {
try {
set.accept(ini.getBoolean(key));
} catch (Exception e) {
SFIni.Data data = ini.getLastData(key);
if (data != null) data.val = Boolean.toString(bool);
Config.LOGGER.log(Level.ERROR,"tf.ssf.sfort.invisframes failed to load "+key+", setting to default value", e);
}
}
public static void loadIni(SFIni ini) {
setOrResetBool(ini, "frame.toggleable", b->enableInvisFrames=b, enableInvisFrames);
setOrResetBool(ini, "frame.clientForceInvis", b->clientForceInvis=b, clientForceInvis);
setOrResetBool(ini, "frame.allowProjectile", b->allowFrameProjectile=b, allowFrameProjectile);
setOrResetBool(ini, "frame.equipSound", b->playFrameSound=b, playFrameSound);
setOrResetBool(ini, "stand.toggleable", b->enableInvisStands=b, enableInvisStands);
setOrResetBool(ini, "stand.allowProjectile", b->allowStandProjectile=b, allowStandProjectile);

setOrResetEnum(ini, "frame.clientHideCustomName", e->clientHideFrameNames=e, clientHideFrameNames, Config.NameCheck.class);
setOrResetEnum(ini, "frame.itemCheck", e->frameItemCheck=e, frameItemCheck, Config.ItemCheck.class);
setOrResetEnum(ini, "stand.itemCheck", e->standItemCheck=e, standItemCheck, Config.ItemCheck.class);
Config.LOGGER.log(Level.INFO,"tf.ssf.sfort.invisframes successfully loaded config file");
}

@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return switch (mixinClassName) {
case mixin + ".FrameEntity" -> enableInvisFrames && (frameItemCheck & 2) == 0;
case mixin + ".FrameEntityServer" -> enableInvisFrames && (frameItemCheck & 2) != 0;
case mixin + ".FrameRender" -> (frameItemCheck & 1) != 0 && !clientForceInvis;
case mixin + ".FrameRenderForce" -> (frameItemCheck & 1) != 0 && clientForceInvis;
case mixin + ".FrameName" -> clientHideFrameNames == 2;
case mixin + ".FrameNameAlways" -> clientHideFrameNames == 1;
case mixin + ".StandRender" -> (standItemCheck & 1) != 0;
case mixin + ".StandEntity" -> enableInvisStands && (standItemCheck & 2) == 0;
case mixin + ".StandEntityServer" -> enableInvisStands && (standItemCheck & 2) != 0;
case mixin + ".FrameEntity" -> enableInvisFrames && !frameItemCheck.server;
case mixin + ".FrameEntityServer" -> enableInvisFrames && frameItemCheck.server;
case mixin + ".FrameRender" -> frameItemCheck.client && !clientForceInvis;
case mixin + ".FrameRenderForce" -> frameItemCheck.client && clientForceInvis;
case mixin + ".FrameName" -> clientHideFrameNames == Config.NameCheck.INVIS_ONLY;
case mixin + ".FrameNameAlways" -> clientHideFrameNames == Config.NameCheck.ALWAYS;
case mixin + ".StandRender" -> standItemCheck.client;
case mixin + ".StandEntity" -> enableInvisStands && !standItemCheck.server;
case mixin + ".StandEntityServer" -> enableInvisStands && standItemCheck.server;
default -> true;
};
}
Expand All @@ -107,10 +148,4 @@ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
@Override public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
@Override public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }

public static boolean IsEmpty(ArmorStandEntity entity) {
for(ItemStack item : entity.getArmorItems())
if(!item.isEmpty())
return false;
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import tf.ssf.sfort.invisframes.InvisFramesShared;

@Mixin(ArmorStandEntity.class)
public abstract class StandEntityServer extends LivingEntity {
Expand All @@ -25,7 +26,7 @@ protected StandEntityServer(EntityType<? extends LivingEntity> entityType, World
public void damage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) {
Entity attacker = source.getAttacker();
if (attacker !=null && attacker.isSneaky() && (FrameConf.allowStandProjectile || source.getName().equals("player"))) {
this.setInvisible(!(this.isInvisible() || FrameConf.IsEmpty((ArmorStandEntity) (Object) this)));
this.setInvisible(!(this.isInvisible() || InvisFramesShared.IsEmpty((ArmorStandEntity) (Object) this)));
info.setReturnValue(true);
info.cancel();
} else {
Expand All @@ -34,7 +35,7 @@ public void damage(DamageSource source, float amount, CallbackInfoReturnable<Boo
}
@Inject(method="equipStack(Lnet/minecraft/entity/EquipmentSlot;Lnet/minecraft/item/ItemStack;)V", at=@At("RETURN"))
public void update(CallbackInfo ci) {
if (FrameConf.IsEmpty((ArmorStandEntity) (Object) this)) {
if (InvisFramesShared.IsEmpty((ArmorStandEntity) (Object) this)) {
this.setInvisible(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import tf.ssf.sfort.invisframes.InvisFramesShared;

@Mixin(ArmorStandEntityRenderer.class)
public abstract class StandRender {
Expand All @@ -14,7 +15,7 @@ public abstract class StandRender {
@ModifyVariable(method="getRenderLayer(Lnet/minecraft/entity/LivingEntity;ZZZ)Lnet/minecraft/client/render/RenderLayer;", at=@At("HEAD"), ordinal=0, argsOnly=true)
public boolean getRenderLayer(boolean old, LivingEntity entity, boolean bl) {
if (entity instanceof ArmorStandEntity) {
if (FrameConf.IsEmpty((ArmorStandEntity) entity)) {
if (InvisFramesShared.IsEmpty((ArmorStandEntity) entity)) {
survivalflight$secondBool = false;
return true;
} else {
Expand Down

0 comments on commit cc43680

Please sign in to comment.