Skip to content

Commit e9061e3

Browse files
committed
Merge branch 'develop'
2 parents 26ab9a9 + 476abed commit e9061e3

18 files changed

Lines changed: 229 additions & 285 deletions

File tree

build.gradle.kts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ allprojects {
3939
}
4040
}
4141

42+
@Suppress("UnstableApiUsage")
4243
configurations {
43-
val transitiveImplementation = create("transitiveImplementation")
44-
implementation.get().extendsFrom(transitiveImplementation)
44+
create("transitiveImplementation")
4545

4646
// Required cause loom 0.14 for some reason doesn't remove asm-all 4.1. Ew.
4747
all {
@@ -66,16 +66,16 @@ allprojects {
6666

6767
modImplementation("net.fabricmc:fabric-loader:${project.properties["loader_version"]}")
6868

69-
"transitiveImplementation"("org.apache.commons:commons-lang3:3.12.0")
70-
"transitiveImplementation"("commons-io:commons-io:2.11.0")
71-
"transitiveImplementation"("net.jodah:typetools:${project.properties["typetools_version"]}")
72-
"transitiveImplementation"("com.github.mineLdiver:UnsafeEvents:${project.properties["unsafeevents_version"]}")
73-
"transitiveImplementation"("it.unimi.dsi:fastutil:${project.properties["fastutil_version"]}")
74-
"transitiveImplementation"("com.github.ben-manes.caffeine:caffeine:${project.properties["caffeine_version"]}")
75-
"transitiveImplementation"("com.mojang:datafixerupper:${project.properties["dfu_version"]}")
76-
"transitiveImplementation"("maven.modrinth:spasm:${project.properties["spasm_version"]}")
77-
"transitiveImplementation"("me.carleslc:Simple-Yaml:1.8.4")
78-
"transitiveImplementation"("net.glasslauncher.mods:GlassConfigAPI:${project.properties["gcapi_version"]}")
69+
"transitiveImplementation"(implementation("org.apache.commons:commons-lang3:3.12.0") as Dependency)
70+
"transitiveImplementation"(implementation("commons-io:commons-io:2.11.0") as Dependency)
71+
"transitiveImplementation"(implementation("net.jodah:typetools:${project.properties["typetools_version"]}") as Dependency)
72+
"transitiveImplementation"(implementation("com.github.mineLdiver:UnsafeEvents:${project.properties["unsafeevents_version"]}") as Dependency)
73+
"transitiveImplementation"(implementation("it.unimi.dsi:fastutil:${project.properties["fastutil_version"]}") as Dependency)
74+
"transitiveImplementation"(implementation("com.github.ben-manes.caffeine:caffeine:${project.properties["caffeine_version"]}") as Dependency)
75+
"transitiveImplementation"(implementation("com.mojang:datafixerupper:${project.properties["dfu_version"]}") as Dependency)
76+
"transitiveImplementation"(implementation("maven.modrinth:spasm:${project.properties["spasm_version"]}") as Dependency)
77+
"transitiveImplementation"(implementation("me.carleslc:Simple-Yaml:1.8.4") as Dependency)
78+
"transitiveImplementation"(modImplementation("net.glasslauncher.mods:GlassConfigAPI:${project.properties["gcapi_version"]}") as Dependency)
7979

8080
// convenience stuff
8181
// adds some useful annotations for data classes. does not add any dependencies

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fabric.loom.multiProjectOptimisation=true
2222
spasm_version = 0.2.2
2323

2424
# Mod Properties
25-
mod_version = 2.0.0-alpha.5.1
25+
mod_version = 2.0.0-alpha.5.2
2626
maven_group = net.modificationstation
2727
archives_base_name = StationAPI
2828

src/test/resources/fabric.mod.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
"stationapi": "*"
6060
},
6161
"custom": {
62-
"stationapi:required_on_client": true,
63-
"stationapi:required_on_server": true
62+
"stationapi:verify_client": true
6463
}
6564
}

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

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

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

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

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

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

55
public interface ModdedPacketHandler {
6+
67
boolean isModded();
78

89
Map<String, String> getMods();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package net.modificationstation.stationapi.impl.client.network;
2+
3+
import net.fabricmc.loader.api.FabricLoader;
4+
import net.fabricmc.loader.api.ModContainer;
5+
import net.mine_diver.unsafeevents.listener.EventListener;
6+
import net.modificationstation.stationapi.api.StationAPI;
7+
import net.modificationstation.stationapi.api.client.event.network.ServerLoginSuccessEvent;
8+
import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint;
9+
import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager;
10+
import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy;
11+
import net.modificationstation.stationapi.api.network.packet.MessagePacket;
12+
import net.modificationstation.stationapi.impl.network.ModdedPacketHandlerSetter;
13+
14+
import java.lang.invoke.MethodHandles;
15+
import java.util.*;
16+
17+
import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE;
18+
import static net.modificationstation.stationapi.api.util.Identifier.of;
19+
20+
@Entrypoint(eventBus = @EventBusPolicy(registerInstance = false))
21+
@EventListener(phase = StationAPI.INTERNAL_PHASE)
22+
public class ClientVanillaChecker {
23+
static {
24+
EntrypointManager.registerLookup(MethodHandles.lookup());
25+
}
26+
27+
@EventListener
28+
private static void handleServerLogin(ServerLoginSuccessEvent event) {
29+
List<String> splitName = Arrays.asList(event.loginHelloPacket.username.split(";"));
30+
if (splitName.contains(NAMESPACE.toString())) {
31+
MessagePacket message = new MessagePacket(of(NAMESPACE, "modlist"));
32+
List<String> mods = new ArrayList<>();
33+
mods.add(NAMESPACE.getVersion().getFriendlyString());
34+
FabricLoader.getInstance().getAllMods().stream().map(ModContainer::getMetadata).forEach(modMetadata -> Collections.addAll(mods, modMetadata.getId(), modMetadata.getVersion().getFriendlyString()));
35+
message.strings = mods.toArray(new String[0]);
36+
event.clientNetworkHandler.sendPacket(message);
37+
38+
// This definitely doesn't have a modlist entry.
39+
if(splitName.size() <= splitName.indexOf(NAMESPACE.toString()))
40+
return;
41+
42+
String modListString = splitName.get(splitName.indexOf(NAMESPACE.toString()) + 1); // Mod list string should ALWAYS follow stapi's string.
43+
44+
// If this doesn't contain stationapi, this isn't a stationapi mod list.
45+
if(!modListString.contains("stationapi="))
46+
return;
47+
48+
Map<String, String> modList = new HashMap<>();
49+
Arrays.stream(modListString.split(":")).forEach(nameVersion -> {
50+
String[] nameVersionArr = nameVersion.split("=");
51+
modList.put(nameVersionArr[0], nameVersionArr[1]);
52+
});
53+
((ModdedPacketHandlerSetter) event.clientNetworkHandler).setModded(modList);
54+
}
55+
}
56+
}

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

Lines changed: 0 additions & 7 deletions
This file was deleted.
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.Map;
3+
import java.util.*;
44

55
public interface ModdedPacketHandlerSetter {
6-
void setModded(boolean value);
6+
77
void setModded(Map<String, String> mods);
88
}
Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package net.modificationstation.stationapi.impl.network;
22

3+
import com.google.common.hash.Hashing;
34
import net.fabricmc.loader.api.FabricLoader;
45
import net.fabricmc.loader.api.ModContainer;
56
import net.fabricmc.loader.api.metadata.ModMetadata;
67
import net.mine_diver.unsafeevents.listener.EventListener;
78
import net.modificationstation.stationapi.api.StationAPI;
8-
import net.modificationstation.stationapi.api.event.init.InitFinishedEvent;
9+
import net.modificationstation.stationapi.api.event.mod.PreInitEvent;
910
import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint;
1011
import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager;
1112
import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy;
@@ -24,32 +25,21 @@ public class VanillaChecker {
2425
EntrypointManager.registerLookup(MethodHandles.lookup());
2526
}
2627

27-
/**
28-
* A set of mods that are required client side when joining a server.
29-
*/
30-
public static final Set<ModContainer> CLIENT_REQUIRED_MODS = new HashSet<>();
28+
public static final long MASK = Hashing.sipHash24().hashUnencodedChars(NAMESPACE.toString()).asLong();
3129

3230
/**
33-
* A set of mods that are required on the server side when joining a server.
31+
* A set of mods that need client-side verification when the client joins server.
3432
*/
35-
public static final Set<ModContainer> SERVER_REQUIRED_MODS = new HashSet<>();
33+
public static final Set<ModContainer> CLIENT_REQUIRED_MODS = new HashSet<>();
3634

3735
@EventListener
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";
36+
private static void init(PreInitEvent event) {
37+
LOGGER.info("Gathering mods that require client verification...");
38+
String value = NAMESPACE + ":verify_client";
4439
FabricLoader.getInstance().getAllMods().forEach(modContainer -> {
4540
ModMetadata modMetadata = modContainer.getMetadata();
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())
41+
if (modMetadata.containsCustomValue(value) && modMetadata.getCustomValue(value).getAsBoolean())
4942
CLIENT_REQUIRED_MODS.add(modContainer);
50-
if (modMetadata.containsCustomValue(requiredOnServerKey) && modMetadata.getCustomValue(requiredOnServerKey).getAsBoolean())
51-
SERVER_REQUIRED_MODS.add(modContainer);
5243
});
53-
LOGGER.info("Found {} mods required on client, {} mods required on server.", CLIENT_REQUIRED_MODS.size(), SERVER_REQUIRED_MODS.size());
5444
}
5545
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package net.modificationstation.stationapi.impl.server.network;
2+
3+
import net.fabricmc.loader.api.FabricLoader;
4+
import net.fabricmc.loader.api.ModContainer;
5+
import net.fabricmc.loader.api.metadata.ModMetadata;
6+
import net.mine_diver.unsafeevents.listener.EventListener;
7+
import net.minecraft.client.resource.language.I18n;
8+
import net.minecraft.entity.player.ServerPlayerEntity;
9+
import net.modificationstation.stationapi.api.StationAPI;
10+
import net.modificationstation.stationapi.api.event.registry.MessageListenerRegistryEvent;
11+
import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint;
12+
import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager;
13+
import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy;
14+
import net.modificationstation.stationapi.api.server.event.network.PlayerAttemptLoginEvent;
15+
import net.modificationstation.stationapi.impl.network.ModdedPacketHandlerSetter;
16+
17+
import java.lang.invoke.MethodHandles;
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import java.util.stream.Collectors;
21+
22+
import static net.modificationstation.stationapi.api.StationAPI.LOGGER;
23+
import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE;
24+
import static net.modificationstation.stationapi.impl.network.VanillaChecker.CLIENT_REQUIRED_MODS;
25+
import static net.modificationstation.stationapi.impl.network.VanillaChecker.MASK;
26+
27+
@Entrypoint(eventBus = @EventBusPolicy(registerInstance = false))
28+
@EventListener(phase = StationAPI.INTERNAL_PHASE)
29+
public class ServerVanillaChecker {
30+
static {
31+
EntrypointManager.registerLookup(MethodHandles.lookup());
32+
}
33+
34+
@EventListener
35+
private static void onPlayerLogin(PlayerAttemptLoginEvent event) {
36+
if ((event.loginHelloPacket.worldSeed & MASK) == MASK) {
37+
Map<String, String> mods = new HashMap<>();
38+
FabricLoader.getInstance().getAllMods().forEach(modContainer -> mods.put(modContainer.getMetadata().getId(), modContainer.getMetadata().getVersion().getFriendlyString()));
39+
((ModdedPacketHandlerSetter) event.serverLoginNetworkHandler).setModded(mods);
40+
}
41+
else if (!CLIENT_REQUIRED_MODS.isEmpty()) {
42+
LOGGER.error("Player \"" + event.loginHelloPacket.username + "\" attempted joining the server without " + NAMESPACE.getName() + ", disconnecting.");
43+
event.serverLoginNetworkHandler.disconnect(I18n.getTranslation("disconnect." + NAMESPACE + ".missingStation"));
44+
}
45+
}
46+
47+
@EventListener
48+
private static void registerMessages(MessageListenerRegistryEvent event) {
49+
event.register(NAMESPACE.id("modlist"), (player, message) -> {
50+
if (!CLIENT_REQUIRED_MODS.isEmpty()) {
51+
LOGGER.info("Received a list of mods from player \"" + player.name + "\", verifying...");
52+
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
53+
String version = message.strings[0];
54+
String serverStationVersion = NAMESPACE.getVersion().getFriendlyString();
55+
if (!version.equals(serverStationVersion)) {
56+
LOGGER.error("Player \"" + player.name + "\" has a mismatching " + NAMESPACE.getName() + " version \"" + version + "\", disconnecting.");
57+
serverPlayer.field_255.method_833(I18n.getTranslation("disconnect." + NAMESPACE + ".stationVersionMismatch", serverStationVersion, version));
58+
return;
59+
}
60+
Map<String, String> clientMods = new HashMap<>();
61+
for (int i = 1; i < message.strings.length; i += 2)
62+
clientMods.put(message.strings[i], message.strings[i + 1]);
63+
LOGGER.info("Player \"" + player.name + "\"'s mods: " + clientMods.entrySet().stream().map(stringStringEntry -> "modid=" + stringStringEntry.getKey() + " version=" + stringStringEntry.getValue()).collect(Collectors.joining(", ", "[", "]")));
64+
String modid;
65+
String clientVersion;
66+
String serverVersion;
67+
for (ModContainer serverMod : CLIENT_REQUIRED_MODS) {
68+
ModMetadata modMetadata = serverMod.getMetadata();
69+
modid = modMetadata.getId();
70+
serverVersion = modMetadata.getVersion().getFriendlyString();
71+
if (clientMods.containsKey(modid)) {
72+
clientVersion = clientMods.get(modid);
73+
if (clientVersion == null || !clientVersion.equals(serverVersion)) {
74+
LOGGER.error("Player \"" + player.name + "\" has a mismatching " + modMetadata.getName() + " (" + modid + ")" + " version \"" + clientVersion + "\", disconnecting.");
75+
serverPlayer.field_255.method_833(I18n.getTranslation("disconnect." + NAMESPACE + ".modVersionMismatch", modMetadata.getName(), modid, serverVersion, clientVersion == null ? "null" : clientVersion));
76+
return;
77+
}
78+
} else {
79+
LOGGER.error("Player \"" + player.name + "\" has a missing mod " + modMetadata.getName() + " (" + modid + "), disconnecting.");
80+
serverPlayer.field_255.method_833(I18n.getTranslation("disconnect." + NAMESPACE + ".missingMod", modMetadata.getName(), modid, serverVersion));
81+
return;
82+
}
83+
}
84+
LOGGER.info("Player \"" + player.name + "\"'s mods have passed verification.");
85+
}
86+
});
87+
}
88+
}

0 commit comments

Comments
 (0)