Skip to content

Commit

Permalink
Major refactor + better error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jwkerr committed Sep 4, 2023
1 parent 4d1e8f1 commit 32bb36b
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 230 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ If you would like to customise the formatting of specific usernames in tab, you

Once you have reached the .minecraft directory, navigate to `.minecraft/config/Tabby`. You will find that there is already a file here named "groups.json", the groups defined by default in this file are staff of the server I develop for, EarthMC.

You are free to edit this file as you like, however, it is important that you follow the structure I have laid out. Below is an example of the "bare minimum":
You are free to edit this file as you like, however, it is important that you follow the structure I have laid out. Below is a simple example:
```json
[
{
Expand All @@ -57,11 +57,10 @@ You are free to edit this file as you like, however, it is important that you fo
]
```

If you don't understand what you are doing when editing this file you should just replace the default values I have already put there rather than attempting to start from scratch. If you have made an irreparable mistake you can delete the file or folder and restart your client to re-initialise the file.
If you don't understand what you are doing when editing this file you should just replace the default values I have already put there rather than attempting to start from scratch. If you have made an irreparable mistake you can delete the file or folder and restart your client or press F9 to re-initialise the file.

- "group" can be any string you like
- UUIDs are a valid input for usernames
- "colour" can be any of the colours listed [here](https://www.digminecraft.com/lists/color_list_pc.php) i.e. BLACK, DARK_AQUA, RED etc. or you can choose a hexadecimal number, i.e. 4A412A
- All boolean values (bold-obfuscated) must be present even if you are not setting them to true

You can define as many groups as you like. If you make changes while in-game, you can press F9 to reload them on the fly. This is due to the JSON being cached to prevent lag.
34 changes: 0 additions & 34 deletions src/main/java/com/fwloopins/tabby/Tabby.java

This file was deleted.

55 changes: 55 additions & 0 deletions src/main/java/com/fwloopins/tabby/client/TabbyClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.fwloopins.tabby.client;

import com.fwloopins.tabby.client.config.TabbyConfig;
import com.fwloopins.tabby.client.config.DataManager;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.serializer.GsonConfigSerializer;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TabbyClient implements ClientModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("Tabby");

@Override
public void onInitializeClient() {
AutoConfig.register(TabbyConfig.class, GsonConfigSerializer::new);

DataManager.initFiles();
DataManager.cacheJson();

reload();

logInfo("Tabby initialised");
}

public static void logInfo(String msg) {
LOGGER.info("[Tabby] " + msg);
}

public static void logError(String msg) {
LOGGER.error("[Tabby] " + msg);
}

public static void reload() {
TabbyConfig config = AutoConfig.getConfigHolder(TabbyConfig.class).getConfig();

KeyBinding reloadBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
"key.reload",
InputUtil.Type.KEYSYM,
config.misc.reloadKey,
"category.tabby"
));

ClientTickEvents.END_CLIENT_TICK.register(client -> {
while (reloadBinding.wasPressed()) {
DataManager.initFiles();
DataManager.cacheJson();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.fwloopins.tabby.config;
package com.fwloopins.tabby.client.config;

import com.fwloopins.tabby.Tabby;
import com.fwloopins.tabby.client.TabbyClient;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
Expand All @@ -26,10 +26,11 @@ public static void initFiles() {
if (!Files.exists(dir))
Files.createDirectory(dir);

assert json != null;
Files.copy(json, dir.resolve("groups.json"));
}
} catch (IOException e) {
Tabby.logError("Failed to copy groups.json to " + dir + "\n" + e);
TabbyClient.logError("Failed to copy groups.json to " + dir + "\n" + e);
}
}

Expand All @@ -40,7 +41,7 @@ public static void cacheJson() {

cachedJson = element.getAsJsonArray();
} catch (IOException e) {
Tabby.logError("Failed to read groups.json\n" + e);
TabbyClient.logError("Failed to read groups.json\n" + e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fwloopins.tabby.config;
package com.fwloopins.tabby.client.config;

import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fwloopins.tabby.config;
package com.fwloopins.tabby.client.config;

import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.annotation.ConfigEntry;
Expand Down
165 changes: 165 additions & 0 deletions src/main/java/com/fwloopins/tabby/client/mixin/PlayerListHudMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.fwloopins.tabby.client.mixin;

import com.fwloopins.tabby.client.TabbyClient;
import com.fwloopins.tabby.client.config.DataManager;
import com.fwloopins.tabby.client.config.TabbyConfig;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import me.shedaniel.autoconfig.AutoConfig;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.PlayerListHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.MutableText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Mixin(PlayerListHud.class)
public abstract class PlayerListHudMixin {
@Shadow @Final private MinecraftClient client;
@Unique final List<String> colours = new ArrayList<>(Arrays.asList("DARK_RED", "RED", "GOLD", "YELLOW", "DARK_GREEN", "GREEN", "AQUA", "DARK_AQUA", "DARK_BLUE", "BLUE", "LIGHT_PURPLE", "DARK_PURPLE", "WHITE", "GRAY", "DARK_GRAY", "BLACK"));
@Shadow @Nullable private Text footer;
@Shadow @Nullable private Text header;
@Unique TabbyConfig config = AutoConfig.getConfigHolder(TabbyConfig.class).getConfig();

@ModifyConstant(constant = @Constant(longValue = 80L), method = "collectPlayerEntries")
private long modifyCount(long count) {
if (config.general.maxCount <= 0 && client.getNetworkHandler() != null)
return client.getNetworkHandler().getListedPlayerListEntries().size();

return config.general.maxCount;
}

@ModifyConstant(constant = @Constant(intValue = 20), method = "render")
private int modifyMaxRows(int MAX_ROWS) {
if (!config.general.adaptive)
return Math.max(1, config.general.maxRows);

if (config.general.maxCount <= 0 && client.getNetworkHandler() != null) {
int onlinePlayers = client.getNetworkHandler().getListedPlayerListEntries().size();
return Math.max(1, onlinePlayers / config.general.adaptiveDivisor);
}

return (int) Math.max(1, config.general.maxCount / config.general.adaptiveDivisor);
}

@Inject(method = "applyGameModeFormatting", at = @At("HEAD"))
private void modifyNameColour(PlayerListEntry entry, MutableText name, CallbackInfoReturnable<Text> cir) {
if (config.misc.customColours) {
String text = name.getString();

String uuid;
try {
if (client.getNetworkHandler() == null)
throw new NullPointerException();

PlayerListEntry playerListEntry = client.getNetworkHandler().getPlayerListEntry(text);

if (playerListEntry != null) {
uuid = playerListEntry.getProfile().getId().toString();
} else {
throw new NullPointerException();
}
} catch (NullPointerException e) {
uuid = "";
}

JsonArray jsonArray;
try {
jsonArray = DataManager.getCachedJson().getAsJsonArray();
} catch (Exception e) {
if (config.misc.debug)
TabbyClient.logError("Failed to read groups.json");

return;
}

try {
for (JsonElement group : jsonArray) {
JsonArray usernamesArray = group.getAsJsonObject().getAsJsonArray("usernames");

for (JsonElement username : usernamesArray) {
if (username.getAsString().equals(text) || username.getAsString().equals(uuid)) {
JsonObject jsonObject = group.getAsJsonObject();
Style style = getStyle(jsonObject, text);

name.setStyle(style);
}
}
}
} catch (Exception e) {
if (config.misc.debug)
TabbyClient.logError("Failed to parse groups.json, likely malformed JSON");
}
}
}

@Inject(method = "setHeader", at = @At("TAIL"))
private void setHeader(Text header, CallbackInfo ci) {
if (!config.misc.customHeader.isEmpty()) {
if (config.misc.customHeader.equals("null")) {
this.header = null;
} else {
this.header = Text.of(config.misc.customHeader);
}
}
}

@Inject(method = "setFooter", at = @At("TAIL"))
private void setFooter(Text footer, CallbackInfo ci) {
if (!config.misc.customFooter.isEmpty()) {
if (config.misc.customFooter.equals("null")) {
this.footer = null;
} else {
this.footer = Text.of(config.misc.customFooter);
}
}
}

@Unique
private Style getStyle(JsonObject jsonObject, String username) {
Style style = Style.EMPTY;

String colour = jsonObject.has("colour") ? jsonObject.get("colour").getAsString() : null;

boolean bold = jsonObject.has("bold") && jsonObject.get("bold").getAsBoolean();
boolean italic = jsonObject.has("italic") && jsonObject.get("italic").getAsBoolean();
boolean underline = jsonObject.has("underline") && jsonObject.get("underline").getAsBoolean();
boolean strikethrough = jsonObject.has("strikethrough") && jsonObject.get("strikethrough").getAsBoolean();
boolean obfuscated = jsonObject.has("obfuscated") && jsonObject.get("obfuscated").getAsBoolean();

style.withBold(bold).withItalic(italic).withUnderline(underline).withStrikethrough(strikethrough).withObfuscated(obfuscated);

if (colour == null) {
return style;
}

if (colours.contains(colour)) {
return style.withColor(Formatting.byName(colour));
} else {
try {
int rgb = Integer.parseInt(colour, 16);

return style.withColor(rgb);
} catch (NumberFormatException e) {
if (config.misc.debug)
TabbyClient.logError("Invalid value for colour found while setting style for " + username);

return style;
}
}
}
}
28 changes: 0 additions & 28 deletions src/main/java/com/fwloopins/tabby/misc/Reload.java

This file was deleted.

Loading

0 comments on commit 32bb36b

Please sign in to comment.