Skip to content
This repository was archived by the owner on May 3, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ include("shearapi-conditions")
include("shearapi-network")
include("shearapi-holderset")
include("shearapi-resource")
include("shearapi-fmlstuff")
13 changes: 13 additions & 0 deletions shearapi-fmlstuff/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
repositories {
maven {
url "https://maven.neoforged.net/releases/"
name "NeoForged Releases"
}
}

dependencies {
implementation "net.neoforged.fancymodloader:loader:${project.fancy_mod_loader_version}"
api project(path: ":shearapi-runtime", configuration: "namedElements")
api project(path: ":shearapi-withpillow", configuration: "namedElements")
api project(path: ":shearapi-network", configuration: "namedElements")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package net.pillowmc.shearapi.fmlstuff.client;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.config.ConfigTracker;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
import net.neoforged.neoforge.network.handlers.ClientPayloadHandler;
import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
import net.pillowmc.shearapi.fmlstuff.ShearAPIFMLStuff;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import net.pillowmc.shearapi.runtime.ShearAPIVersion;
import net.pillowmc.shearapi.withpillow.ShearAPIWithPillow;

import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

public class ShearAPIFMLStuffClient implements ClientModInitializer {
public static Class<ShearAPIFMLStuffClient> clazz = ShearAPIFMLStuffClient.class;
private static final Map<ResourceLocation, RegistrySnapshot> synchronizedRegistries = Maps.newConcurrentMap();
private static final Set<ResourceLocation> toSynchronize = Sets.newConcurrentHashSet();

@Override
public void onInitializeClient() {
ShearAPIFMLStuff.clientHandleRegistrySyncCompleted = ShearAPIFMLStuffClient::handleRegistrySyncCompleted;
}

@SubscribeEvent
public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent event) {
if (!(ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow)) {
return;
}
final IPayloadRegistrar registrar = event.registrar(ShearAPIRuntime.MOD_ID)
.versioned(ShearAPIVersion.getSpec())
.optional();
registrar
.configuration(
FrozenRegistrySyncStartPayload.ID,
FrozenRegistrySyncStartPayload::new,
handlers -> handlers.client(ShearAPIFMLStuffClient::handleRegistrySyncStart))
.configuration(
FrozenRegistryPayload.ID,
FrozenRegistryPayload::new,
handlers -> handlers.client(ShearAPIFMLStuffClient::handleFrozenRegistry))
.configuration(
ConfigFilePayload.ID,
ConfigFilePayload::new,
handlers -> handlers.client(ShearAPIFMLStuffClient::handleConfigFile));
}

private static void handleConfigFile(ConfigFilePayload payload, IPayloadContext context) {
if (!Minecraft.getInstance().isLocalServer()) {
Optional.ofNullable(
ConfigTracker.INSTANCE.fileMap().get(payload.fileName())
).ifPresent(mc -> mc.acceptSyncedConfig(payload.contents()));
}
}

public static void handleFrozenRegistry(FrozenRegistryPayload payload, ConfigurationPayloadContext context) {
synchronizedRegistries.put(payload.registryName(), payload.snapshot());
toSynchronize.remove(payload.registryName());
}

public static void handleRegistrySyncStart(FrozenRegistrySyncStartPayload payload, ConfigurationPayloadContext context) {
toSynchronize.addAll(payload.toAccess());
synchronizedRegistries.clear();
}

public static void handleRegistrySyncCompleted(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
if (!toSynchronize.isEmpty()) {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.missing", this.toSynchronize.stream().map(Object::toString).collect(Collectors.joining(", "))));
return;
}

context.workHandler().submitAsync(() -> {
//This method normally returns missing entries, but we just accept what the server send us and ignore the rest.
Set<ResourceKey<?>> keysUnknownToClient = RegistryManager.applySnapshot(synchronizedRegistries, false, false);
if (!keysUnknownToClient.isEmpty()) {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.server-with-unknown-keys", keysUnknownToClient.stream().map(Object::toString).collect(Collectors.joining(", "))));
return;
}

toSynchronize.clear();
synchronizedRegistries.clear();
}).exceptionally(e -> {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.failed", e.getMessage()));
return null;
}).thenAccept(v -> {
context.replyHandler().send(new FrozenRegistrySyncCompletedPayload());
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
@ApiStatus.Internal
public record SyncRegistries() implements ICustomConfigurationTask {
private static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "sync_registries");
public static final Type TYPE = new Type(ID);
public static final Type TYPE = new Type(ID.toString());

@Override
public void run(Consumer<CustomPacketPayload> sender) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package net.pillowmc.shearapi.fmlstuff;

import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.network.configuration.SyncConfig;
import net.neoforged.neoforge.network.configuration.SyncRegistries;
import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
import net.neoforged.neoforge.network.handling.IConfigurationPayloadHandler;
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import net.pillowmc.shearapi.runtime.ShearAPIVersion;
import net.pillowmc.shearapi.withpillow.ShearAPIWithPillow;

public class ShearAPIFMLStuff {
public static Class<ShearAPIFMLStuff> clazz = ShearAPIFMLStuff.class;
public static IConfigurationPayloadHandler<FrozenRegistrySyncCompletedPayload> clientHandleRegistrySyncCompleted;

@SubscribeEvent
public static void onGameConfigurationEvent(OnGameConfigurationEvent event) {
if (event.getListener().isConnected(FrozenRegistrySyncStartPayload.ID) &&
event.getListener().isConnected(FrozenRegistryPayload.ID) &&
event.getListener().isConnected(FrozenRegistrySyncCompletedPayload.ID)) {
event.register(new SyncRegistries());
}
if (event.getListener().isConnected(ConfigFilePayload.ID) && ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow) {
event.register(new SyncConfig(event.getListener()));
}
}
@SubscribeEvent
public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent event) {
if (!(ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow)) {
return;
}
final IPayloadRegistrar registrar = event.registrar(ShearAPIRuntime.MOD_ID)
.versioned(ShearAPIVersion.getSpec())
.optional();
registrar
.configuration(
FrozenRegistrySyncCompletedPayload.ID,
FrozenRegistrySyncCompletedPayload::new,
handlers -> handlers.client(clientHandleRegistrySyncCompleted)
.server(ShearAPIFMLStuff::handleRegistrySyncCompleted));
}

public static void handleRegistrySyncCompleted(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
context.taskCompletedHandler().onTaskCompleted(SyncRegistries.TYPE);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions shearapi-fmlstuff/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"schemaVersion": 1,
"id": "shearapi-fmlstuff",
"version": "${version}",
"name": "Shear API (FML Stuff)",
"description": "Deal with stuff things if FML installed",
"authors": [
"PillowMC"
],
"contact": {
"homepage": "https://github.com/PillowMC/ShearAPI",
"sources": "https://github.com/PillowMC/ShearAPI"
},
"license": "LGPL-2.1",
"icon": "assets/shearapi-fmlstuff/icon.png",
"environment": "*",
"depends": {
"fabricloader": ">=0.15.6",
"minecraft": "~1.20.4",
"java": ">=17",
"fabric-api": "*",
"shearapi-runtime": "~${version}",
"shearapi-network": "~${version}",
"shearapi-withpillow": "~${version}"
},
"entrypoints": {
"client": ["net.pillowmc.shearapi.fmlstuff.client.ShearAPIFMLStuffClient"],
"shearapi-runtime:client_mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.client.ShearAPIFMLStuffClient::clazz"],
"shearapi-runtime:mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.ShearAPIFMLStuff::clazz"]
},
"custom": {
"modmenu": {
"parent": "shearapi",
"badges": ["library"]
}
}
}
6 changes: 5 additions & 1 deletion shearapi-network/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
loom {
accessWidenerPath = file("src/main/resources/shearapi-network.accesswidener")
}

dependencies {
api project(path: ":shearapi-utils", configuration: "namedElements")
api project(path: ":shearapi-runtime", configuration: "namedElements")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,21 @@

package net.neoforged.neoforge.network.handlers;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.netty.buffer.Unpooled;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
import net.neoforged.neoforge.common.TierSortingRegistry;
import net.neoforged.neoforge.common.world.AuxiliaryLightManager;
import net.neoforged.neoforge.common.world.LevelChunkAuxiliaryLightManager;
import net.neoforged.neoforge.network.ConfigSync;
import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
import net.neoforged.neoforge.network.payload.AdvancedContainerSetDataPayload;
import net.neoforged.neoforge.network.payload.AdvancedOpenScreenPayload;
import net.neoforged.neoforge.network.payload.AuxiliaryLightDataPayload;
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
import net.neoforged.neoforge.network.payload.TierSortingRegistryPayload;
import net.neoforged.neoforge.registries.RegistryManager;
import net.neoforged.neoforge.registries.RegistrySnapshot;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
Expand All @@ -48,52 +30,11 @@ public static ClientPayloadHandler getInstance() {
return INSTANCE;
}

private final Set<ResourceLocation> toSynchronize = Sets.newConcurrentHashSet();
private final Map<ResourceLocation, RegistrySnapshot> synchronizedRegistries = Maps.newConcurrentMap();

private ClientPayloadHandler() {}

public void handle(FrozenRegistryPayload payload, ConfigurationPayloadContext context) {
synchronizedRegistries.put(payload.registryName(), payload.snapshot());
toSynchronize.remove(payload.registryName());
}

public void handle(FrozenRegistrySyncStartPayload payload, ConfigurationPayloadContext context) {
this.toSynchronize.addAll(payload.toAccess());
this.synchronizedRegistries.clear();
}

public void handle(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
if (!this.toSynchronize.isEmpty()) {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.missing", this.toSynchronize.stream().map(Object::toString).collect(Collectors.joining(", "))));
return;
}

context.workHandler().submitAsync(() -> {
//This method normally returns missing entries, but we just accept what the server send us and ignore the rest.
Set<ResourceKey<?>> keysUnknownToClient = RegistryManager.applySnapshot(synchronizedRegistries, false, false);
if (!keysUnknownToClient.isEmpty()) {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.server-with-unknown-keys", keysUnknownToClient.stream().map(Object::toString).collect(Collectors.joining(", "))));
return;
}

this.toSynchronize.clear();
this.synchronizedRegistries.clear();
}).exceptionally(e -> {
context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.failed", e.getMessage()));
return null;
}).thenAccept(v -> {
context.replyHandler().send(new FrozenRegistrySyncCompletedPayload());
});
}

public void handle(ConfigFilePayload payload, IPayloadContext context) {
ConfigSync.INSTANCE.receiveSyncedConfig(payload.contents(), payload.fileName());
}

public void handle(TierSortingRegistryPayload payload, IPayloadContext context) {
TierSortingRegistry.handleSync(payload, context);
}
// public void handle(TierSortingRegistryPayload payload, IPayloadContext context) {
// TierSortingRegistry.handleSync(payload, context);
// }

public void handle(AdvancedOpenScreenPayload msg, PlayPayloadContext context) {
context.workHandler().submitAsync(() -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.pillowmc.shearapi.network.client;

import net.minecraft.client.multiplayer.resolver.ResolvedServerAddress;
import net.minecraft.client.multiplayer.resolver.ServerAddress;
import net.minecraft.client.multiplayer.resolver.ServerNameResolver;
import net.neoforged.neoforge.network.DualStackUtils;

import java.net.InetSocketAddress;
import java.util.Optional;

public class DualStackUtilsClient {

/**
* Resolve the address and see if Java and the OS return an IPv6 or IPv4 one, then let Netty know
* accordingly (it doesn't understand the {@code java.net.preferIPv6Addresses=system} property).
*
* @param hostAddress The address you want to check
* @return true if IPv6, false if IPv4
*/
public static boolean checkIPv6(final String hostAddress) {
final Optional<InetSocketAddress> hostAddr = ServerNameResolver.DEFAULT
.resolveAddress(ServerAddress.parseString(hostAddress))
.map(ResolvedServerAddress::asInetSocketAddress);

if (hostAddr.isPresent()) return DualStackUtils.checkIPv6(hostAddr.get().getAddress());
else return false;
}
}
Loading