Skip to content

Commit

Permalink
Merge pull request #33 from UselessBullets/ModListPacket
Browse files Browse the repository at this point in the history
ModVersionHelper
  • Loading branch information
MartinSVK12 authored Nov 7, 2023
2 parents aa33a9a + d2a19cf commit 7f8c3f2
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/main/java/turniplabs/halplibe/HalpLibe.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import turniplabs.halplibe.helper.AchievementHelper;
import turniplabs.halplibe.helper.ModVersionHelper;
import turniplabs.halplibe.helper.NetworkHelper;
import turniplabs.halplibe.util.TomlConfigHandler;
import turniplabs.halplibe.util.achievements.AchievementPage;
import turniplabs.halplibe.util.achievements.VanillaAchievementsPage;
import turniplabs.halplibe.util.network.PacketExtendedMobSpawn;
import turniplabs.halplibe.util.version.PacketModList;
import turniplabs.halplibe.util.toml.Toml;

public class HalpLibe implements ModInitializer, PreLaunchEntrypoint {
Expand All @@ -31,7 +33,7 @@ public class HalpLibe implements ModInitializer, PreLaunchEntrypoint {
Class.forName("net.minecraft.core.item.Item");
} catch (ClassNotFoundException ignored) {
}

ModVersionHelper.initialize();
}
public static final AchievementPage VANILLA_ACHIEVEMENTS = new VanillaAchievementsPage();
public static String addModId(String modId, String name) {
Expand All @@ -42,6 +44,7 @@ public static String addModId(String modId, String name) {
public void onInitialize() {
AchievementHelper.addPage(VANILLA_ACHIEVEMENTS);
NetworkHelper.register(PacketExtendedMobSpawn.class, false, true);
NetworkHelper.register(PacketModList.class, false, true);
LOGGER.info("HalpLibe initialized.");
}

Expand Down
132 changes: 132 additions & 0 deletions src/main/java/turniplabs/halplibe/helper/ModVersionHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package turniplabs.halplibe.helper;

import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.Version;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Global;
import turniplabs.halplibe.HalpLibe;
import turniplabs.halplibe.util.version.EnumModList;
import turniplabs.halplibe.util.version.ModInfo;
import turniplabs.halplibe.util.version.PacketModList;

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

public class ModVersionHelper {
protected static boolean isDev = FabricLoader.getInstance().isDevelopmentEnvironment();
protected static List<ModInfo> localMods = new ArrayList<>();
protected static List<ModInfo> serverMods = null;
static {
for (ModContainer modContainer: FabricLoader.getInstance().getAllMods()) {
if (modContainer.getMetadata().getType().equals("fabric") && !modContainer.getMetadata().getId().equals("fabricloader")){
localMods.add(new ModInfo(modContainer));
}
}
}
public static void initialize(){}

/**
* @return List of mods installed in the current environment.
*/
public static List<ModInfo> getLocalModlist(){
return localMods;
}

/**
* @return List of mods from the current server, returns null if not connected to a server or the server does not support the mod list packet.
*/
public static List<ModInfo> getServerModlist(){
if (isClientOfServer()){
return serverMods;
}
return null;
}
/**
* @return Returns local mods when in single player or called from the server, returns server mods when a client of server
*/
public static List<ModInfo> getActiveModlist(){
if (isClientOfServer()){
return getServerModlist();
}
return getLocalModlist();
}

/**
* @return Returns true only if the player is currently connected to a server.
*/
public static boolean isClientOfServer(){
if (Global.isServer){
return false;
}
Minecraft mc = Minecraft.getMinecraft(Minecraft.class);
return mc.theWorld != null && mc.theWorld.isClientSide;
}
/**
* @return Returns true if the mod is present in the active mod list
*/
public static boolean isModPresent(String modIdToCheck){
return isModPresent(modIdToCheck, EnumModList.ACTIVE);
}
/**
* @return Returns true if the mod is present in the specified mod list
*/
public static boolean isModPresent(String modIdToCheck, EnumModList modList){
return getModInfo(modIdToCheck, modList) != null;
}
/**
* @return Returns 0 if versions match exactly, returns a positive integer when mod has a greater version number, returns a negative integer when a mod has a smaller version number, returns null if mod is not present or comparison fails.
*/
public static Integer isVersionPresent(String modIdToCheck, Version version){
return isVersionPresent(modIdToCheck, version, EnumModList.ACTIVE);
}
/**
* @return Returns 0 if versions match exactly, returns a positive integer when mod has a greater version number, returns a negative integer when a mod has a smaller version number, returns null if mod is not present or comparison fails.
*/
public static Integer isVersionPresent(String modIdToCheck, Version version, EnumModList modList){
ModInfo modInfo = getModInfo(modIdToCheck, modList);
if (modInfo == null) return null;
return modInfo.version.compareTo(version);
}
/**
* @return Returns the specified mod info if present, returns null if not present
*/
public static ModInfo getModInfo(String modId, EnumModList modList){
List<ModInfo> modInfoList = getModList(modList);
if (modInfoList == null) return null;
for (ModInfo info: modInfoList) {
if (info.id.equals(modId)) return info;
}
return null;
}
/**
* @return Returns the specified mod list.
*/
public static List<ModInfo> getModList(EnumModList modList){
switch (modList){
case LOCAL:
return getLocalModlist();
case SERVER:
return getServerModlist();
case ACTIVE:
return getActiveModlist();
default:
return null;
}
}
protected static void handleModListPacket(PacketModList packetModList){
serverMods = packetModList.modInfos;
if (isDev){
printModList();
}

}
protected static void printModList(){
HalpLibe.LOGGER.info("Server Mod List");
if (getServerModlist() != null){
for (ModInfo info: getServerModlist()) {
HalpLibe.LOGGER.info(info.id + " " + info.version);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import net.minecraft.client.world.WorldClient;
import net.minecraft.core.entity.EntityDispatcher;
import net.minecraft.core.entity.EntityLiving;
import net.minecraft.core.net.handler.NetHandler;
import net.minecraft.core.net.packet.Packet24MobSpawn;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -17,7 +18,7 @@
import java.util.List;

@Mixin(value = NetClientHandler.class, remap = false)
public class NetClientHandlerMixin {
public abstract class NetClientHandlerMixin extends NetHandler {
@Shadow private WorldClient worldClient;

@Shadow private Minecraft mc;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package turniplabs.halplibe.mixin.mixins.version;

import net.minecraft.client.net.handler.NetClientHandler;
import net.minecraft.core.net.handler.NetHandler;
import net.minecraft.core.net.packet.Packet2Handshake;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import turniplabs.halplibe.HalpLibe;
import turniplabs.halplibe.helper.ModVersionHelper;
import turniplabs.halplibe.util.version.IVersionPackets;
import turniplabs.halplibe.util.version.PacketModList;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

@Mixin(value = NetClientHandler.class, remap = false)
public abstract class NetClientHandlerMixin extends NetHandler implements IVersionPackets {
@Unique
public void handleModList(PacketModList packetModList) {
try {
Method m = ModVersionHelper.class.getDeclaredMethod("handleModListPacket", PacketModList.class);
m.setAccessible(true);
m.invoke(null, packetModList);
m.setAccessible(false);
} catch (Throwable err) {
err.printStackTrace();
}
}
@Inject(method = "handleHandshake(Lnet/minecraft/core/net/packet/Packet2Handshake;)V", at = @At("HEAD"))
private void resetServerModlist(Packet2Handshake packet2handshake, CallbackInfo ci){
try {
Field m = ModVersionHelper.class.getDeclaredField("serverMods");
m.setAccessible(true);
m.set(null, null);
m.setAccessible(false);
} catch (Throwable err) {
err.printStackTrace();
}
HalpLibe.LOGGER.info(String.valueOf(ModVersionHelper.getServerModlist() == null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package turniplabs.halplibe.mixin.mixins.version;

import net.minecraft.core.net.handler.NetHandler;
import net.minecraft.core.net.packet.Packet;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import turniplabs.halplibe.util.version.IVersionPackets;
import turniplabs.halplibe.util.version.PacketModList;
@Mixin(value = NetHandler.class, remap = false)
public abstract class NetHandlerMixin implements IVersionPackets {
@Shadow public abstract void handleInvalidPacket(Packet packet);

@Unique
public void handleModList(PacketModList packetModList) {
handleInvalidPacket(packetModList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package turniplabs.halplibe.mixin.mixins.version;

import net.minecraft.core.net.packet.Packet1Login;
import net.minecraft.server.entity.player.EntityPlayerMP;
import net.minecraft.server.net.handler.NetLoginHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import turniplabs.halplibe.helper.ModVersionHelper;
import turniplabs.halplibe.util.version.PacketModList;

@Mixin(value = NetLoginHandler.class, remap = false)
public class NetLoginHandlerMixin {
@Inject(method = "doLogin(Lnet/minecraft/core/net/packet/Packet1Login;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/net/handler/NetServerHandler;sendPacket(Lnet/minecraft/core/net/packet/Packet;)V", ordinal = 6, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
private void modlistPacket(Packet1Login packet1login, CallbackInfo ci, EntityPlayerMP entityplayermp){
entityplayermp.playerNetServerHandler.sendPacket(new PacketModList(ModVersionHelper.getLocalModlist()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package turniplabs.halplibe.util.version;

public enum EnumModList {
LOCAL,
SERVER,
ACTIVE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package turniplabs.halplibe.util.version;

public interface IVersionPackets {
void handleModList(PacketModList packetModList);
}
51 changes: 51 additions & 0 deletions src/main/java/turniplabs/halplibe/util/version/ModInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package turniplabs.halplibe.util.version;

import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.impl.util.version.StringVersion;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class ModInfo {
public String id;
public Version version;
public ModInfo(DataInputStream dataInputStream) throws IOException {
unpack(dataInputStream);
}
public ModInfo(ModContainer container){
this(container.getMetadata().getId(), container.getMetadata().getVersion());
}
public ModInfo(String id, Version version){
if (id.equals("")){
id = "Unknown ID";
}
this.id = id;
if (version.getFriendlyString().equals("")){
version = new StringVersion("-1.-1.-1");
}
this.version = version;
}
public void pack(DataOutputStream dos) throws IOException {
dos.writeChars(id);
dos.writeChar(3);
dos.writeChars(version.getFriendlyString());
dos.writeChar(3);
}
public void unpack(DataInputStream dis) throws IOException {
id = readString(dis);
version = new StringVersion(readString(dis));
}
public String readString(DataInputStream dis) throws IOException {
char data = 0;
StringBuilder stringBuilder = new StringBuilder();
while (data != 3){
data = dis.readChar();
if (data != 3){
stringBuilder.append(data);
}
}
return stringBuilder.toString();
}
}
52 changes: 52 additions & 0 deletions src/main/java/turniplabs/halplibe/util/version/PacketModList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package turniplabs.halplibe.util.version;

import net.minecraft.core.net.handler.NetHandler;
import net.minecraft.core.net.packet.Packet;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PacketModList extends Packet {
public List<ModInfo> modInfos = new ArrayList<>();
public PacketModList(){

}
public PacketModList(List<ModInfo> modInfos){
this.modInfos = modInfos;
}
@Override
public void readPacketData(DataInputStream dataInputStream) throws IOException {
this.modInfos = new ArrayList<>();
char data = 0;
while (data != 127){
modInfos.add(new ModInfo(dataInputStream));
data = dataInputStream.readChar();
}
}

@Override
public void writePacketData(DataOutputStream dataOutputStream) throws IOException {
int size = modInfos.size();
for (int i = 0; i < size; i++) {
modInfos.get(i).pack(dataOutputStream);
if (i == size -1){
dataOutputStream.writeChar(127);
} else {
dataOutputStream.writeChar(3);
}
}
}

@Override
public void processPacket(NetHandler netHandler) {
((IVersionPackets)netHandler).handleModList(this);
}

@Override
public int getPacketSize() {
return 0;
}
}
5 changes: 4 additions & 1 deletion src/main/resources/halplibe.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
"mixins.network.PacketMixin",
"mixins.registry.BlockMixin",
"mixins.registry.ItemMixin",
"mixins.registry.MinecraftServerMixin"
"mixins.registry.MinecraftServerMixin",
"mixins.version.NetClientHandlerMixin",
"mixins.version.NetHandlerMixin",
"mixins.version.NetLoginHandlerMixin"
],
"client": [
"mixins.network.MinecraftMixin",
Expand Down

0 comments on commit 7f8c3f2

Please sign in to comment.