Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c79f6e0
Implement new packets, add new API for logging, implement config via …
MesterMan03 Mar 25, 2026
22818ea
Merge branch 'ImBit:master' into master
MesterMan03 Mar 25, 2026
f556f9b
Replace JsonOps.COMPRESSED with JsonOps.INSTANCE to fix serialization…
MesterMan03 Mar 25, 2026
74f0d59
Clean up comments, replace PacketInfoSegment usage with PacketInfoRow…
MesterMan03 Mar 25, 2026
37cdafc
Merge remote-tracking branch 'upstream/master'
MesterMan03 Mar 25, 2026
68b8512
Readd cloth config and mod menu, add missing reflections library
MesterMan03 Mar 25, 2026
dfb9f1b
Move old build.yml to publish.yml, create new build.yml without publi…
MesterMan03 Mar 26, 2026
e2bf9e3
Merge remote-tracking branch 'upstream/master'
MesterMan03 Mar 26, 2026
4cb92a7
Merge remote-tracking branch 'origin/master' into fork/MesterMan03/ma…
ImBit Mar 26, 2026
617aab0
🎨 Update libs.versions.toml
ImBit Mar 26, 2026
8d79380
Begin review changes
MesterMan03 Mar 26, 2026
e22f100
Comment updates
MesterMan03 Mar 26, 2026
8f4910b
Remove quotes from gradle.properties, causing build failures
MesterMan03 Mar 26, 2026
9ea38ce
Remove PacketInfoBundle.ofRows constructor, fix crash for missing aud…
MesterMan03 Mar 26, 2026
6b5b905
Implement world border packets
MesterMan03 Mar 27, 2026
e535326
Fix clashing friendly names
MesterMan03 Mar 27, 2026
c185dcb
♻️ Refined use of Rows, Lists and values for packet formatting.
ImBit Mar 27, 2026
9a14155
🐛 Build cleanup.
ImBit Mar 27, 2026
fcbe2b1
🎨 Added todo.
ImBit Mar 27, 2026
47a58a5
🐛 Fixed modmenu configuration.
ImBit Mar 27, 2026
5793e29
🎨 Formatting tweaks.
ImBit Mar 27, 2026
6be1735
🎨 Added TODO for ListPacketData.
ImBit Mar 27, 2026
d93be89
🎨 Update TODO.
ImBit Mar 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
More refined packet filtering:
[ ] Per-packet customisation e.g. AddEntity range [1000, 99999]

Better config:
[ ] Nicer menu for packet enabling
[ ] Save packet filtering preferences to config

More info:
[ ] Hover on message to show more info:
[ ] Timestamp
[ ] Packet size?

Documentation:
[ ] Add better documentation to API methods (see Bits)
[ ] Improve README
[ ] More screenshots
[ ] Better explanation of features
[ ] Example use cases
13 changes: 12 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ repositories {
mavenCentral()
mavenLocal()
maven { url = uri("https://jitpack.io") }
maven {
name = "Terraformers"
url = uri("https://maven.terraformersmc.com/releases")
}
maven { url = uri("https://maven.shedaniel.me/") }
}

loom {
Expand All @@ -40,12 +45,18 @@ dependencies {
modImplementation(rootProject.libs.fabric.api)

modImplementation(rootProject.libs.adventure.platform)
include(rootProject.libs.adventure.platform)

modImplementation(rootProject.libs.bits.api)
include(rootProject.libs.bits.api)

include(rootProject.libs.javassist)

modImplementation(rootProject.libs.modmenu)
modApi(rootProject.libs.clothconfig) {
exclude(group = "net.fabricmc.fabric-api")
}
include(rootProject.libs.clothconfig)

errorprone(rootProject.libs.errorprone)
}

Expand Down
4 changes: 3 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ yarn_mappings=1.21.11+build.3
archives_base_name=packet-ninja
# Dependencies
fabric_version=0.140.2+1.21.11
# Modmenu
modmenu_version=17.0.0-beta.2
# Mod Version
version="0.0.6"
version=0.0.6
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ javassist = { group = "org.javassist", name = "javassist", version = "3.30.2-GA"

errorprone = { group = "com.google.errorprone", name = "error_prone_core", version = "2.45.0" }

modmenu = { group = "com.terraformersmc", name = "modmenu", version = "17.0.0-beta.2" }
clothconfig = { group = "me.shedaniel.cloth", name = "cloth-config-fabric", version = "21.11.153" }


[plugins]
fabric-loom = { id = "fabric-loom", version = "1.14-SNAPSHOT" }
Expand Down
Empty file modified gradlew
100644 → 100755
Empty file.
8 changes: 5 additions & 3 deletions src/client/java/xyz/bitsquidd/ninja/PacketInterceptorMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.slf4j.LoggerFactory;

import xyz.bitsquidd.ninja.command.PacketInterceptionCommand;
import xyz.bitsquidd.ninja.config.Config;
import xyz.bitsquidd.ninja.format.PacketLogger;

public final class PacketInterceptorMod implements ClientModInitializer {
Expand All @@ -30,9 +31,10 @@ public PacketInterceptorMod() {

@Override
public void onInitializeClient() {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
PacketInterceptionCommand.register(dispatcher);
});
Config.load();
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
PacketInterceptionCommand.register(dispatcher)
);
}

public @NotNull PacketFilter getPacketFilter() {
Expand Down
50 changes: 50 additions & 0 deletions src/client/java/xyz/bitsquidd/ninja/config/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package xyz.bitsquidd.ninja.config;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.fabricmc.loader.api.FabricLoader;

import xyz.bitsquidd.ninja.PacketInterceptorMod;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

public class Config {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Path FILE = FabricLoader.getInstance().getConfigDir().resolve("packetninja.json");

public static Duration packetDelay = Duration.ofMillis(500);

public static void load() {
if (Files.exists(FILE)) {
try {
String json = Files.readString(FILE);
ConfigData data = GSON.fromJson(json, ConfigData.class);
if (data != null) {
packetDelay = Duration.ofMillis(data.packetDelayMs);
}
} catch (Exception e) {
PacketInterceptorMod.LOGGER.error("Failed to load config, using defaults");
}
} else {
save(); // generate file on first run
}
}

public static void save() {
try {
ConfigData data = new ConfigData();
data.packetDelayMs = packetDelay.toMillis();

Files.writeString(FILE, GSON.toJson(data));
} catch (IOException e) {
PacketInterceptorMod.LOGGER.error("Failed to save config");
}
}

private static class ConfigData {
long packetDelayMs = 500;
}
}
11 changes: 11 additions & 0 deletions src/client/java/xyz/bitsquidd/ninja/config/ConfigMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package xyz.bitsquidd.ninja.config;

import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;

public class ConfigMenu implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return ConfigScreen::create;
}
}
45 changes: 45 additions & 0 deletions src/client/java/xyz/bitsquidd/ninja/config/ConfigScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package xyz.bitsquidd.ninja.config;

import me.shedaniel.clothconfig2.api.ConfigBuilder;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;

import java.time.Duration;

public class ConfigScreen {
public static Screen create(Screen parent) {
var builder = ConfigBuilder.create()
.setParentScreen(parent)
.setTitle(Component.literal("PacketNinja Settings"));

var general = builder.getOrCreateCategory(Component.literal("General"));
var entryBuilder = builder.entryBuilder();

general.addEntry(entryBuilder
.startLongSlider(
Component.literal("Packet Delay (ms)"),
Config.packetDelay.toMillis(),
0,
2000L
)
.setDefaultValue(500L)
.setTextGetter(value -> {
long step = 50L;
long snapped = (value / step) * step;
return Component.literal(snapped + " ms");
})
.setTooltip(Component.literal(
"The minimum delay in milliseconds between two packets required " +
"to actually log a packet, otherwise it'll be replaced with \"...\""
))
.setSaveConsumer(newValue -> {
long step = 50L;
Config.packetDelay = Duration.ofMillis((newValue / step) * step);
Config.save();
})
.build()
);

return builder.build();
}
}
41 changes: 41 additions & 0 deletions src/client/java/xyz/bitsquidd/ninja/format/ListPacketData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package xyz.bitsquidd.ninja.format;

import com.google.common.collect.ImmutableList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;

import xyz.bitsquidd.ninja.handler.PacketType;

import java.util.Collection;

// TODO Use MAX_DISPLAYED_ENTRIES here instead of in building packets.

/**
* Displays a titled list of entries inside a packet info bundle.
*/
public final class ListPacketData implements PacketInfo {
private final Component name;
private final ImmutableList<PacketInfo> subInfo;

ListPacketData(Component name, Collection<PacketInfo> subInfo) {
this.name = name;
this.subInfo = ImmutableList.copyOf(subInfo);
}

@Override
public Component format(PacketType type) {
TextComponent.Builder lineBuilder = Component.text();

lineBuilder.append(Component.empty()
.append(name.color(type.primaryColor))
.append(Component.text(": "))
);

subInfo.forEach(info -> lineBuilder
.appendNewline()
.append(Component.text(" ↪ "))
.append(info.format(type)));

return lineBuilder.build();
}
}
34 changes: 34 additions & 0 deletions src/client/java/xyz/bitsquidd/ninja/format/PacketInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package xyz.bitsquidd.ninja.format;

import net.kyori.adventure.text.Component;

import xyz.bitsquidd.ninja.handler.PacketType;

import java.util.Collection;
import java.util.List;

/**
* Any information that a packet can give. Convenience methods for pretty formatting.
*/
public interface PacketInfo {
Component format(PacketType type);


static PacketInfo data(Component name, Component value) {
return new SinglePacketData(name, value);
}

static PacketInfo value(Component value) {
return new SinglePacketValue(value);
}


static PacketInfo list(Component name, PacketInfo... subInfo) {
return list(name, List.of(subInfo));
}

static PacketInfo list(Component name, Collection<PacketInfo> subInfo) {
return new ListPacketData(name, subInfo);
}

}
40 changes: 13 additions & 27 deletions src/client/java/xyz/bitsquidd/ninja/format/PacketInfoBundle.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package xyz.bitsquidd.ninja.format;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.TextDecoration;
import org.jspecify.annotations.NullMarked;

import xyz.bitsquidd.ninja.handler.PacketType;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* A bundle of information about a packet sent to a client. This structure is used for pretty formatting.
Expand All @@ -19,38 +17,26 @@ public final class PacketInfoBundle {
private final PacketType type;

private final Component name;
private final List<PacketInfoSegment> segments;
private final List<PacketInfo> info;

private PacketInfoBundle(PacketType type, Component name, List<PacketInfoSegment> segments) {
private PacketInfoBundle(PacketType type, Component name, List<PacketInfo> info) {
this.type = type;
this.name = name;
this.segments = segments;
this.info = info;
}

public static PacketInfoBundle of(PacketType type, Component name, List<PacketInfoSegment> segments) {
return new PacketInfoBundle(type, name, segments);
public static PacketInfoBundle of(PacketType type, Component name, List<? extends PacketInfo> info) {
return new PacketInfoBundle(type, name, List.copyOf(info));
}

public Component format() {
Component titleComponent = Component.empty()
.append(Component.text(type.icon + " "))
.append(name
.color(type.primaryColor)
.decorate(TextDecoration.BOLD)
);

List<Component> segmentComponents = segments.stream().map(segment -> Component.empty()
.color(type.secondaryColor)
.append(Component.text(" ↪ "))
.append(segment.getName())
.append(Component.text(": "))
.append(segment.getValue())
).collect(Collectors.toList());

List<Component> allComponents = new ArrayList<>(List.of(titleComponent));
allComponents.addAll(segmentComponents);

return Component.join(JoinConfiguration.newlines(), allComponents);
TextComponent.Builder infoBuilder = Component.text().color(type.secondaryColor);

infoBuilder.append(Component.text(type.icon + " "));
infoBuilder.append(PacketInfo.list(name.decorate(TextDecoration.BOLD), info).format(type));
infoBuilder.appendNewline();

return infoBuilder.build();
}

}
30 changes: 0 additions & 30 deletions src/client/java/xyz/bitsquidd/ninja/format/PacketInfoSegment.java

This file was deleted.

Loading
Loading