Skip to content

Commit

Permalink
reorganize mixin package, refactor offline data api, rename ParticleS…
Browse files Browse the repository at this point in the history
…ystemManager to ParticleSystemController, generify handshake and synchronize particle controllers as well, document particle api and offline data api
  • Loading branch information
gliscowo committed Jan 23, 2022
1 parent 99afda7 commit 2a96747
Show file tree
Hide file tree
Showing 33 changed files with 593 additions and 334 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ allprojects {
options.compilerArgs << "-Xlint:unchecked"
}

loom {
shareRemapCaches = true
}

dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ minecraft_version=1.18.1
yarn_mappings=1.18.1+build.22
loader_version=0.12.12
# Mod Properties
mod_version=0.4.1+pre1
mod_version=0.5.0
maven_group=io.wispforest
archives_base_name=owo-lib
# Dependencies
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/io/wispforest/owo/Owo.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class Owo implements ModInitializer {
*/
public static final boolean DEBUG;
public static final Logger LOGGER = LogManager.getLogger("owo");
public static MinecraftServer SERVER;
private static MinecraftServer SERVER;

public static final Text PREFIX = new LiteralText("[").formatted(Formatting.GRAY)
.append(withColor("o", 0x3955e5))
Expand All @@ -47,17 +47,16 @@ public void onInitialize() {
ModDataLoader.load(new GroupTabLoader());
LootOps.registerListener();

ServerLifecycleEvents.SERVER_STARTING.register(server -> {
SERVER = server;
});

ServerLifecycleEvents.SERVER_STOPPED.register(server -> {
SERVER = null;
});
ServerLifecycleEvents.SERVER_STARTING.register(server -> SERVER = server);
ServerLifecycleEvents.SERVER_STOPPED.register(server -> SERVER = null);

if (!DEBUG) return;

OwoDebugCommands.register();
}

public static MinecraftServer currentServer() {
return SERVER;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.itemgroup;

import com.mojang.blaze3d.systems.RenderSystem;
import io.wispforest.owo.itemgroup.OwoItemGroup;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.itemgroup;

import io.wispforest.owo.itemgroup.OwoItemGroup;
import io.wispforest.owo.itemgroup.json.GroupTabLoader;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.itemgroup;

import io.wispforest.owo.itemgroup.OwoItemExtensions;
import io.wispforest.owo.itemgroup.OwoItemGroup;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.itemgroup;

import io.wispforest.owo.itemgroup.OwoItemSettingsExtensions;
import net.minecraft.item.Item;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.offline;

import net.minecraft.advancement.AdvancementProgress;
import net.minecraft.advancement.criterion.CriterionProgress;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.offline;

import io.wispforest.owo.offline.PlayerAdvancementsSaved;
import io.wispforest.owo.offline.DataSavedEvents;
import net.minecraft.advancement.AdvancementProgress;
import net.minecraft.advancement.PlayerAdvancementTracker;
import net.minecraft.server.network.ServerPlayerEntity;
Expand All @@ -19,7 +19,7 @@ public class PlayerAdvancementTrackerMixin {
@SuppressWarnings("unchecked")
@ModifyArg(method = "save", at = @At(value = "INVOKE", target = "Lcom/google/gson/Gson;toJsonTree(Ljava/lang/Object;)Lcom/google/gson/JsonElement;"))
private Object onAdvancementsSaved(Object map) {
PlayerAdvancementsSaved.EVENT.invoker().onPlayerAdvancementsSaved(owner.getUuid(), (Map<Identifier, AdvancementProgress>)map);
DataSavedEvents.ADVANCEMENTS.invoker().onSaved(owner.getUuid(), (Map<Identifier, AdvancementProgress>) map);
return map;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.offline;

import io.wispforest.owo.offline.PlayerDataSaved;
import io.wispforest.owo.offline.DataSavedEvents;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.world.WorldSaveHandler;
Expand All @@ -14,6 +14,6 @@
public class WorldSaveHandlerMixin {
@Inject(method = "savePlayerData", at = @At(value = "INVOKE", target = "Ljava/io/File;createTempFile(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)Ljava/io/File;"), locals = LocalCapture.CAPTURE_FAILHARD)
public void onPlayerDataSaved(PlayerEntity player, CallbackInfo ci, NbtCompound tag) {
PlayerDataSaved.EVENT.invoker().onPlayerDataSaved(player.getUuid(), tag);
DataSavedEvents.PLAYER_DATA.invoker().onSaved(player.getUuid(), tag);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.tweaks;

import net.minecraft.server.dedicated.EulaReader;
import org.apache.logging.log4j.Logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.tweaks;

import io.wispforest.owo.Owo;
import net.fabricmc.loader.api.FabricLoader;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.tweaks;

import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Util;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.wispforest.owo.mixin;
package io.wispforest.owo.mixin.tweaks;

import io.wispforest.owo.Owo;
import net.minecraft.client.gui.widget.TextFieldWidget;
Expand Down
119 changes: 87 additions & 32 deletions src/main/java/io/wispforest/owo/network/OwoHandshake.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import io.wispforest.owo.Owo;
import io.wispforest.owo.network.serialization.PacketBufSerializer;
import io.wispforest.owo.ops.TextOps;
import io.wispforest.owo.particles.systems.ParticleSystemController;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientLoginNetworkHandler;
import net.minecraft.network.PacketByteBuf;
Expand All @@ -21,41 +25,59 @@
import net.minecraft.util.Pair;
import org.jetbrains.annotations.ApiStatus;

import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.ToIntFunction;

@ApiStatus.Internal
class OwoHandshake {
public class OwoHandshake {

@SuppressWarnings("unchecked")
private static final PacketBufSerializer<Map<Identifier, Integer>> RESPONSE_SERIALIZER = (PacketBufSerializer<Map<Identifier, Integer>>)(Object)PacketBufSerializer.createMapSerializer(Map.class, Identifier.class, Integer.class);
private static final PacketBufSerializer<Map<Identifier, Integer>> RESPONSE_SERIALIZER = (PacketBufSerializer<Map<Identifier, Integer>>) (Object) PacketBufSerializer.createMapSerializer(Map.class, Identifier.class, Integer.class);
private static final MutableText PREFIX = TextOps.concat(Owo.PREFIX, Text.of("§chandshake failure\n"));
static final Identifier CHANNEL_ID = new Identifier("owo", "handshake");

static void queryStart(ServerLoginNetworkHandler serverLoginNetworkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer loginSynchronizer) {
public static final Identifier CHANNEL_ID = new Identifier("owo", "handshake");

// ------------
// Registration
// ------------

public static void enable() {}

static {
ServerLoginConnectionEvents.QUERY_START.register(OwoHandshake::queryStart);
ServerLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncServer);

if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
ClientLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncClient);
}
}

// -------
// Packets
// -------

private static void queryStart(ServerLoginNetworkHandler serverLoginNetworkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer loginSynchronizer) {
sender.sendPacket(OwoHandshake.CHANNEL_ID, PacketByteBufs.create());
Owo.LOGGER.info("[Handshake] Sending channel query");
}

@Environment(EnvType.CLIENT)
public static CompletableFuture<PacketByteBuf> syncClient(MinecraftClient client, ClientLoginNetworkHandler clientLoginNetworkHandler, PacketByteBuf buf, Consumer<GenericFutureListener<? extends Future<? super Void>>> genericFutureListenerConsumer) {
private static CompletableFuture<PacketByteBuf> syncClient(MinecraftClient client, ClientLoginNetworkHandler clientLoginNetworkHandler, PacketByteBuf buf, Consumer<GenericFutureListener<? extends Future<? super Void>>> genericFutureListenerConsumer) {
Owo.LOGGER.info("[Handshake] Sending client channels");

var response = PacketByteBufs.create();

Map<Identifier, Integer> channelMap = new HashMap<>();

for (OwoNetChannel channel : OwoNetChannel.REGISTERED_CHANNELS.values()) {
channelMap.put(channel.packetId, hashChannel(channel));
}

RESPONSE_SERIALIZER.serializer().accept(response, channelMap);
writeHashes(response, OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel);
writeHashes(response, ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController);

return CompletableFuture.completedFuture(response);
}

public static void syncServer(MinecraftServer server, ServerLoginNetworkHandler handler, boolean responded, PacketByteBuf buf, ServerLoginNetworking.LoginSynchronizer loginSynchronizer, PacketSender packetSender) {
private static void syncServer(MinecraftServer server, ServerLoginNetworkHandler handler, boolean responded, PacketByteBuf buf, ServerLoginNetworking.LoginSynchronizer loginSynchronizer, PacketSender packetSender) {
Owo.LOGGER.info("[Handshake] Receiving client channels");
if (!responded) {
handler.disconnect(TextOps.concat(PREFIX, Text.of("incompatible client")));
Expand All @@ -64,46 +86,71 @@ public static void syncServer(MinecraftServer server, ServerLoginNetworkHandler
}

final var clientChannels = RESPONSE_SERIALIZER.deserializer().apply(buf);
final var clientParticleControllers = RESPONSE_SERIALIZER.deserializer().apply(buf);

StringBuilder disconnectMessage = new StringBuilder();

boolean isAllGood = verifyReceivedHashes("channels", clientChannels, OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel, disconnectMessage);
isAllGood &= verifyReceivedHashes("controllers", clientParticleControllers, ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController, disconnectMessage);

if (!isAllGood) {
handler.disconnect(TextOps.concat(PREFIX, Text.of(disconnectMessage.toString())));
} else {
Owo.LOGGER.info("[Handshake] Handshake completed successfully");
}
}

// -------
// Utility
// -------

private static <T> boolean verifyReceivedHashes(String serviceNamePlural, Map<Identifier, Integer> clientMap, Map<Identifier, T> serverMap, ToIntFunction<T> hashFunction, StringBuilder disconnectMessage) {
boolean isAllGood = true;
StringBuilder lines = new StringBuilder();
if (!OwoNetChannel.REGISTERED_CHANNELS.keySet().equals(clientChannels.keySet())) {

if (!clientMap.keySet().equals(serverMap.keySet())) {
isAllGood = false;

var leftovers = findCollisions(clientChannels.keySet(), OwoNetChannel.REGISTERED_CHANNELS.keySet());
var leftovers = findCollisions(clientMap.keySet(), serverMap.keySet());

if (!leftovers.getLeft().isEmpty()) {
lines.append("server is missing channels:\n");
leftovers.getLeft().forEach(identifier -> lines.append("§7").append(identifier).append("§r\n"));
disconnectMessage.append("server is missing ").append(serviceNamePlural).append(":\n");
leftovers.getLeft().forEach(identifier -> disconnectMessage.append("§7").append(identifier).append("§r\n"));
}

if (!leftovers.getRight().isEmpty()) {
lines.append("client is missing channels:\n");
leftovers.getRight().forEach(identifier -> lines.append("§7").append(identifier).append("§r\n"));
disconnectMessage.append("client is missing ").append(serviceNamePlural).append(":\n");
leftovers.getRight().forEach(identifier -> disconnectMessage.append("§7").append(identifier).append("§r\n"));
}
}


boolean hasMismatchedHashes = false;
for (var entry : clientChannels.entrySet()) {
var actualChannel = OwoNetChannel.REGISTERED_CHANNELS.get(entry.getKey());
for (var entry : clientMap.entrySet()) {
var actualServiceObject = serverMap.get(entry.getKey());
if (actualServiceObject == null) continue;

if (actualChannel == null) continue;

int localHash = hashChannel(actualChannel);
int localHash = hashFunction.applyAsInt(actualServiceObject);

if (localHash != entry.getValue()) {
if (!hasMismatchedHashes) lines.append("channels have mismatched hashes:\n");
if (!hasMismatchedHashes) disconnectMessage.append(serviceNamePlural).append(" with mismatched hashes:\n");

lines.append("§7").append(entry.getKey()).append("§r\n");
disconnectMessage.append("§7").append(entry.getKey()).append("§r\n");

isAllGood = false;
hasMismatchedHashes = true;
}
}

if (!isAllGood) {
handler.disconnect(TextOps.concat(PREFIX, Text.of(lines.toString())));
return isAllGood;
}

private static <T> void writeHashes(PacketByteBuf buffer, Map<Identifier, T> values, ToIntFunction<T> hashFunction) {
Map<Identifier, Integer> hashes = new HashMap<>();

for (var entry : values.entrySet()) {
hashes.put(entry.getKey(), hashFunction.applyAsInt(entry.getValue()));
}

RESPONSE_SERIALIZER.serializer().accept(buffer, hashes);
}

private static Pair<Set<Identifier>, Set<Identifier>> findCollisions(Set<Identifier> first, Set<Identifier> second) {
Expand All @@ -128,4 +175,12 @@ private static int hashChannel(OwoNetChannel channel) {
}
return 31 * channel.packetId.hashCode() + serializersHash;
}

private static int hashController(ParticleSystemController controller) {
int serializersHash = 0;
for (var entry : controller.systemsByIndex.int2ObjectEntrySet()) {
serializersHash += entry.getIntKey();
}
return 31 * controller.channelId.hashCode() + serializersHash;
}
}
15 changes: 6 additions & 9 deletions src/main/java/io/wispforest/owo/network/OwoNetChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.fabricmc.api.EnvType;
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.*;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
Expand Down Expand Up @@ -37,7 +38,8 @@
* <p>To register a packet onto this channel, use either {@link #registerClientbound(Class, ChannelHandler)}
* or {@link #registerServerbound(Class, ChannelHandler)}, depending on which direction the packet goes.
* Bidirectional registration of the same class is explicitly supported. <b>For synchronization purposes,
* all registration must happen on both client and server, even for clientbound packets.</b>
* all registration must happen on both client and server, even for clientbound packets. Otherwise,
* joining the server will fail with a handshake error</b>
*
* <p>To send a packet, use any of the {@code handle} methods to obtain a handle for sending. These are
* named after where the packet is sent <i>from</i>, meaning the {@link #clientHandle()} is used for sending
Expand Down Expand Up @@ -379,12 +381,7 @@ public interface EnvironmentAccess<P extends PlayerEntity, R, N> {
}

static {
ServerLoginConnectionEvents.QUERY_START.register(OwoHandshake::queryStart);
ServerLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncServer);

if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
ClientLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncClient);
}
OwoHandshake.enable();
}

static final class IndexedSerializer<R extends Record> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

package io.wispforest.owo.network.serialization;

import io.wispforest.owo.network.annotations.ElementType;
Expand Down Expand Up @@ -218,7 +217,7 @@ public static <E> PacketBufSerializer<Optional<E>> createOptionalSerializer(Clas
*/
@SuppressWarnings("unchecked")
public static PacketBufSerializer<?> createArraySerializer(Class<?> elementClass) {
var elementSerializer = (PacketBufSerializer<Object>)get(elementClass);
var elementSerializer = (PacketBufSerializer<Object>) get(elementClass);
return new PacketBufSerializer<>((buf, t) -> {
final int length = Array.getLength(t);
buf.writeVarInt(length);
Expand Down
Loading

0 comments on commit 2a96747

Please sign in to comment.