Skip to content

Commit d750c35

Browse files
Fix Multiplayer Mod Validation (#207)
* Holy shit it works somehow * Make message nicer * damn it, **cal** * General cleanup * It is, now * Revert "It is, now" This reverts commit 1ef63bb. * There's no point in this then --------- Co-authored-by: mineLdiver <arsbsdn@gmail.com>
1 parent 56493e2 commit d750c35

16 files changed

Lines changed: 272 additions & 216 deletions

File tree

src/test/resources/fabric.mod.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"stationapi": "*"
5959
},
6060
"custom": {
61-
"stationapi:verify_client": true
61+
"stationapi:required_on_client": true,
62+
"stationapi:required_on_server": true
6263
}
6364
}

station-api-base/src/main/resources/fabric.mod.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737

3838
"custom": {
39-
"modmenu:api": true
39+
"modmenu:api": true,
40+
"stationapi:required_on_client": true
4041
}
4142
}

station-vanilla-checker-v0/src/main/java/net/modificationstation/stationapi/api/network/ModdedPacketHandler.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package net.modificationstation.stationapi.api.network;
22

3-
import java.util.*;
3+
import java.util.Map;
44

55
public interface ModdedPacketHandler {
6-
76
boolean isModded();
87

98
Map<String, String> getMods();

station-vanilla-checker-v0/src/main/java/net/modificationstation/stationapi/impl/client/network/ClientVanillaChecker.java

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.modificationstation.stationapi.impl.network;
2+
3+
import java.util.Map;
4+
5+
public interface ModListHelloPacket {
6+
Map<String, String> stationapi_getModList();
7+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package net.modificationstation.stationapi.impl.network;
22

3-
import java.util.*;
3+
import java.util.Map;
44

55
public interface ModdedPacketHandlerSetter {
6-
6+
void setModded(boolean value);
77
void setModded(Map<String, String> mods);
88
}

station-vanilla-checker-v0/src/main/java/net/modificationstation/stationapi/impl/network/VanillaChecker.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package net.modificationstation.stationapi.impl.network;
22

3-
import com.google.common.hash.Hashing;
43
import net.fabricmc.loader.api.FabricLoader;
54
import net.fabricmc.loader.api.ModContainer;
65
import net.fabricmc.loader.api.metadata.ModMetadata;
76
import net.mine_diver.unsafeevents.listener.EventListener;
87
import net.modificationstation.stationapi.api.StationAPI;
9-
import net.modificationstation.stationapi.api.event.mod.PreInitEvent;
8+
import net.modificationstation.stationapi.api.event.init.InitFinishedEvent;
109
import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint;
1110
import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager;
1211
import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy;
@@ -25,21 +24,32 @@ public class VanillaChecker {
2524
EntrypointManager.registerLookup(MethodHandles.lookup());
2625
}
2726

28-
public static final long MASK = Hashing.sipHash24().hashUnencodedChars(NAMESPACE.toString()).asLong();
29-
3027
/**
31-
* A set of mods that need client-side verification when the client joins server.
28+
* A set of mods that are required client side when joining a server.
3229
*/
3330
public static final Set<ModContainer> CLIENT_REQUIRED_MODS = new HashSet<>();
3431

32+
/**
33+
* A set of mods that are required on the server side when joining a server.
34+
*/
35+
public static final Set<ModContainer> SERVER_REQUIRED_MODS = new HashSet<>();
36+
3537
@EventListener
36-
private static void init(PreInitEvent event) {
37-
LOGGER.info("Gathering mods that require client verification...");
38-
String value = NAMESPACE + ":verify_client";
38+
private static void init(InitFinishedEvent event) {
39+
LOGGER.info("Checking mod metadata for client/server-side requirements...");
40+
41+
String oldVerifyClientKey = NAMESPACE + ":verify_client";
42+
String requiredOnClientKey = NAMESPACE + ":required_on_client";
43+
String requiredOnServerKey = NAMESPACE + ":required_on_server";
3944
FabricLoader.getInstance().getAllMods().forEach(modContainer -> {
4045
ModMetadata modMetadata = modContainer.getMetadata();
41-
if (modMetadata.containsCustomValue(value) && modMetadata.getCustomValue(value).getAsBoolean())
46+
if (modMetadata.containsCustomValue(requiredOnClientKey) && modMetadata.getCustomValue(requiredOnClientKey).getAsBoolean())
47+
CLIENT_REQUIRED_MODS.add(modContainer);
48+
else if (modMetadata.containsCustomValue(oldVerifyClientKey) && modMetadata.getCustomValue(oldVerifyClientKey).getAsBoolean())
4249
CLIENT_REQUIRED_MODS.add(modContainer);
50+
if (modMetadata.containsCustomValue(requiredOnServerKey) && modMetadata.getCustomValue(requiredOnServerKey).getAsBoolean())
51+
SERVER_REQUIRED_MODS.add(modContainer);
4352
});
53+
LOGGER.info("Found {} mods required on client, {} mods required on server.", CLIENT_REQUIRED_MODS.size(), SERVER_REQUIRED_MODS.size());
4454
}
4555
}

station-vanilla-checker-v0/src/main/java/net/modificationstation/stationapi/impl/server/network/ServerVanillaChecker.java

Lines changed: 0 additions & 88 deletions
This file was deleted.
Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,76 @@
11
package net.modificationstation.stationapi.mixin.network;
22

3+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
35
import net.fabricmc.api.EnvType;
46
import net.fabricmc.api.Environment;
57
import net.fabricmc.loader.api.FabricLoader;
8+
import net.minecraft.client.Minecraft;
69
import net.minecraft.network.packet.login.LoginHelloPacket;
10+
import net.modificationstation.stationapi.api.StationAPI;
11+
import net.modificationstation.stationapi.api.network.ModdedPacketHandler;
12+
import net.modificationstation.stationapi.impl.network.ModListHelloPacket;
13+
import net.modificationstation.stationapi.mixin.network.client.ConnectScreenAccessor;
714
import org.spongepowered.asm.mixin.Mixin;
815
import org.spongepowered.asm.mixin.Shadow;
16+
import org.spongepowered.asm.mixin.Unique;
917
import org.spongepowered.asm.mixin.injection.At;
1018
import org.spongepowered.asm.mixin.injection.Constant;
1119
import org.spongepowered.asm.mixin.injection.Inject;
1220
import org.spongepowered.asm.mixin.injection.ModifyConstant;
1321
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
1422

15-
import java.util.*;
16-
import java.util.stream.*;
17-
18-
import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE;
19-
import static net.modificationstation.stationapi.impl.network.VanillaChecker.MASK;
23+
import java.io.DataInputStream;
24+
import java.io.DataOutputStream;
25+
import java.util.Arrays;
26+
import java.util.HashMap;
27+
import java.util.Map;
2028

2129
@Mixin(LoginHelloPacket.class)
22-
class LoginHelloPacketMixin {
30+
class LoginHelloPacketMixin implements ModListHelloPacket {
2331
@Shadow public String username;
32+
@Unique
33+
private HashMap<String, String> modList;
2434

25-
@Shadow public long worldSeed;
35+
@Environment(EnvType.CLIENT)
36+
@WrapOperation(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/login/LoginHelloPacket;writeString(Ljava/lang/String;Ljava/io/DataOutputStream;)V"))
37+
private void stationapi_giveTheSauce(String s, DataOutputStream dataOutputStream, Operation<Void> original) {
38+
//noinspection deprecation
39+
if (((ModdedPacketHandler) ((ConnectScreenAccessor) ((Minecraft) FabricLoader.getInstance().getGameInstance()).currentScreen).getNetworkHandler()).isModded()) {
40+
StringBuilder builder = new StringBuilder(";");
41+
FabricLoader.getInstance().getAllMods().forEach(mod -> builder.append(mod.getMetadata().getId()).append("=").append(mod.getMetadata().getVersion()).append(";"));
42+
s += builder.toString();
43+
StationAPI.LOGGER.info("Sending modlist to server.");
44+
}
45+
original.call(s, dataOutputStream);
46+
}
2647

27-
@Inject(
28-
method = "<init>(Ljava/lang/String;IJB)V",
29-
at = @At("RETURN")
30-
)
3148
@Environment(EnvType.SERVER)
32-
private void stationapi_injectStAPIFlagAndModList(String username, int protocolVersion, long worldSeed, byte dimensionId, CallbackInfo ci) {
33-
this.username += NAMESPACE + ";";
34-
35-
List<String> mods = FabricLoader.getInstance().getAllMods().stream().map((modContainer -> modContainer.getMetadata().getId() + "=" + modContainer.getMetadata().getVersion().getFriendlyString())).toList();
36-
mods.forEach(mod -> this.username += mod + ":");
37-
this.username = this.username.replaceFirst(":$", "");
38-
this.username += ";";
49+
@Inject(method = "read", at = @At("TAIL"))
50+
private void stationapi_readTheSauce(DataInputStream par1, CallbackInfo ci) {
51+
if (username.contains(";")) {
52+
modList = new HashMap<>();
53+
Arrays.asList(username.split(";")).forEach(modString -> {
54+
String[] mod = modString.split("=");
55+
if (mod.length == 2) {
56+
modList.put(mod[0], mod[1]);
57+
}
58+
});
59+
username = username.split(";")[0];
60+
StationAPI.LOGGER.info("Got modlist from client, containing {} mods.", modList.size());
61+
}
3962
}
4063

41-
@Inject(
42-
method = "<init>(Ljava/lang/String;I)V",
43-
at = @At("RETURN")
44-
)
45-
@Environment(EnvType.CLIENT)
46-
private void stationapi_injectStAPIFlag(String username, int protocolVersion, CallbackInfo ci) {
47-
worldSeed |= MASK;
64+
@Override
65+
public Map<String, String> stationapi_getModList() {
66+
return modList;
4867
}
4968

5069
@ModifyConstant(
5170
method = "read",
52-
constant = @Constant(
53-
ordinal = 0,
54-
intValue = 16
55-
),
56-
require = 0
71+
constant = @Constant(intValue = 16)
5772
)
58-
private int stationapi_injectHugeStringLimit(int constant) {
73+
private int stationapi_preventTheWorldFromExploding(int constant) {
5974
return Short.MAX_VALUE;
6075
}
61-
6276
}

station-vanilla-checker-v0/src/main/java/net/modificationstation/stationapi/mixin/network/NetworkHandlerMixin.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,36 @@
66
import org.spongepowered.asm.mixin.Mixin;
77
import org.spongepowered.asm.mixin.Unique;
88

9-
import java.util.*;
9+
import java.util.Map;
1010

1111
@Mixin(NetworkHandler.class)
1212
class NetworkHandlerMixin implements ModdedPacketHandler, ModdedPacketHandlerSetter {
13-
13+
@Unique
1414
private Map<String, String> mods;
15+
@Unique
16+
private boolean modded = false;
1517

1618
@Override
1719
@Unique
1820
public boolean isModded() {
19-
return mods != null;
21+
return modded;
22+
}
23+
24+
@Override
25+
@Unique
26+
public void setModded(boolean value) {
27+
modded = value;
2028
}
2129

2230
@Override
2331
@Unique
2432
public void setModded(Map<String, String> mods) {
33+
modded = true;
2534
this.mods = mods;
2635
}
2736

37+
@Override
38+
@Unique
2839
public Map<String, String> getMods() {
2940
return mods;
3041
}

0 commit comments

Comments
 (0)