mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-04 15:43:00 +00:00
Update to 1.20.4
This commit is contained in:
@@ -7,13 +7,13 @@ package dan200.computercraft.client;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.sound.SpeakerSound;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.level.LevelEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.client.event.*;
|
||||
import net.neoforged.neoforge.client.event.sound.PlayStreamingSourceEvent;
|
||||
import net.neoforged.neoforge.event.TickEvent;
|
||||
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||
|
||||
/**
|
||||
* Forge-specific dispatch for {@link ClientHooks}.
|
||||
|
||||
@@ -7,16 +7,15 @@ package dan200.computercraft.client;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent;
|
||||
import dan200.computercraft.client.model.turtle.TurtleModelLoader;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ModelEvent;
|
||||
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
|
||||
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
|
||||
import net.minecraftforge.client.event.RegisterShadersEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.ModLoader;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.neoforged.neoforge.client.event.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -33,7 +32,7 @@ public final class ForgeClientRegistry {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerModelLoaders(ModelEvent.RegisterGeometryLoaders event) {
|
||||
event.register("turtle", TurtleModelLoader.INSTANCE);
|
||||
event.register(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle"), TurtleModelLoader.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +48,7 @@ public final class ForgeClientRegistry {
|
||||
if (gatheredModellers) return;
|
||||
|
||||
gatheredModellers = true;
|
||||
ModLoader.get().postEvent(new RegisterTurtleModellersEvent());
|
||||
ModLoader.get().postEvent(new RegisterTurtleModellersEvent(TurtleUpgradeModellers::register));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +73,11 @@ public final class ForgeClientRegistry {
|
||||
ClientRegistry.registerItemColours(event::register);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerMenuScreens(RegisterMenuScreensEvent event) {
|
||||
ClientRegistry.registerMenuScreens(event::register);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerReloadListeners(RegisterClientReloadListenersEvent event) {
|
||||
ClientRegistry.registerReloadListeners(event::registerReloadListener, Minecraft.getInstance());
|
||||
|
||||
@@ -10,7 +10,7 @@ import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.irisshaders.iris.api.v0.IrisTextVertexSink;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.neoforged.fml.ModList;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -12,8 +12,8 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.client.model.BakedModelWrapper;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
import net.neoforged.neoforge.client.model.BakedModelWrapper;
|
||||
import net.neoforged.neoforge.client.model.data.ModelData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,8 +12,8 @@ import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.client.model.BakedModelWrapper;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
import net.neoforged.neoforge.client.model.BakedModelWrapper;
|
||||
import net.neoforged.neoforge.client.model.data.ModelData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
@@ -9,7 +9,7 @@ import dan200.computercraft.client.model.TransformedBakedModel;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.client.model.BakedModelWrapper;
|
||||
import net.neoforged.neoforge.client.model.BakedModelWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -15,9 +15,9 @@ import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
|
||||
import net.minecraftforge.client.model.geometry.IGeometryLoader;
|
||||
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
|
||||
import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext;
|
||||
import net.neoforged.neoforge.client.model.geometry.IGeometryLoader;
|
||||
import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import dan200.computercraft.client.model.FoiledModel;
|
||||
import dan200.computercraft.client.render.ModelRenderer;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import dan200.computercraft.shared.platform.NetworkHandler;
|
||||
import dan200.computercraft.shared.platform.ForgeMessageType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
@@ -18,12 +18,13 @@ import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.network.protocol.common.ServerCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
import net.neoforged.neoforge.client.model.data.ModelData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
@@ -44,8 +45,8 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<ServerGamePacketListener> createPacket(NetworkMessage<ServerNetworkContext> message) {
|
||||
return NetworkHandler.createServerboundPacket(message);
|
||||
public Packet<ServerCommonPacketListener> createPacket(NetworkMessage<ServerNetworkContext> message) {
|
||||
return new ServerboundCustomPayloadPacket(ForgeMessageType.createPayload(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
import net.neoforged.neoforge.client.model.data.ModelData;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@@ -6,7 +6,7 @@ package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraftforge.client.ClientCommandHandler;
|
||||
import net.neoforged.neoforge.client.ClientCommandHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
||||
@@ -8,60 +8,73 @@ import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.ForgeComputerCraftAPI;
|
||||
import dan200.computercraft.api.detail.ForgeDetailRegistries;
|
||||
import dan200.computercraft.api.network.wired.WiredElement;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
import dan200.computercraft.api.network.wired.WiredElementCapability;
|
||||
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.CommonHooks;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.details.FluidData;
|
||||
import dan200.computercraft.shared.integration.MoreRedIntegration;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.generic.methods.EnergyMethods;
|
||||
import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods;
|
||||
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.ForgeConfigFile;
|
||||
import dan200.computercraft.shared.platform.NetworkHandler;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.registries.NewRegistryEvent;
|
||||
import net.minecraftforge.registries.RegistryBuilder;
|
||||
import dan200.computercraft.shared.platform.ForgeMessageType;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.ModLoadingContext;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.config.ModConfig;
|
||||
import net.neoforged.fml.event.config.ModConfigEvent;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
||||
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
|
||||
import net.neoforged.neoforge.registries.NewRegistryEvent;
|
||||
import net.neoforged.neoforge.registries.RegistryBuilder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mod(ComputerCraftAPI.MOD_ID)
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public final class ComputerCraft {
|
||||
public ComputerCraft() {
|
||||
ModRegistry.register();
|
||||
private static @Nullable IEventBus eventBus;
|
||||
|
||||
public ComputerCraft(IEventBus eventBus) {
|
||||
withEventBus(eventBus, ModRegistry::register);
|
||||
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ((ForgeConfigFile) ConfigSpec.serverSpec).spec());
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ((ForgeConfigFile) ConfigSpec.clientSpec).spec());
|
||||
}
|
||||
|
||||
NetworkHandler.setup();
|
||||
private static void withEventBus(IEventBus eventBus, Runnable task) {
|
||||
ComputerCraft.eventBus = eventBus;
|
||||
task.run();
|
||||
ComputerCraft.eventBus = null;
|
||||
}
|
||||
|
||||
public static IEventBus getEventBus() {
|
||||
var bus = eventBus;
|
||||
if (bus == null) throw new NullPointerException("Bus is not available.");
|
||||
return bus;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerRegistries(NewRegistryEvent event) {
|
||||
event.create(new RegistryBuilder<TurtleUpgradeSerialiser<?>>()
|
||||
.setName(TurtleUpgradeSerialiser.registryId().location())
|
||||
.disableSaving().disableSync());
|
||||
|
||||
event.create(new RegistryBuilder<PocketUpgradeSerialiser<?>>()
|
||||
.setName(PocketUpgradeSerialiser.registryId().location())
|
||||
.disableSaving().disableSync());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerCapabilities(RegisterCapabilitiesEvent event) {
|
||||
event.register(WiredElement.class);
|
||||
event.register(IPeripheral.class);
|
||||
event.create(new RegistryBuilder<>(ITurtleUpgrade.serialiserRegistryKey()));
|
||||
event.create(new RegistryBuilder<>(IPocketUpgrade.serialiserRegistryKey()));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -72,13 +85,61 @@ public final class ComputerCraft {
|
||||
ComputerCraftAPI.registerGenericSource(new FluidMethods());
|
||||
ComputerCraftAPI.registerGenericSource(new EnergyMethods());
|
||||
|
||||
ForgeComputerCraftAPI.registerGenericCapability(ForgeCapabilities.ITEM_HANDLER);
|
||||
ForgeComputerCraftAPI.registerGenericCapability(ForgeCapabilities.ENERGY);
|
||||
ForgeComputerCraftAPI.registerGenericCapability(ForgeCapabilities.FLUID_HANDLER);
|
||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.ItemHandler.BLOCK);
|
||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.FluidHandler.BLOCK);
|
||||
ForgeComputerCraftAPI.registerGenericCapability(Capabilities.EnergyStorage.BLOCK);
|
||||
|
||||
ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill);
|
||||
}
|
||||
|
||||
if (ModList.get().isLoaded(MoreRedIntegration.MOD_ID)) MoreRedIntegration.setup();
|
||||
@SubscribeEvent
|
||||
public static void registerNetwork(RegisterPayloadHandlerEvent event) {
|
||||
var registrar = event.registrar(ComputerCraftAPI.MOD_ID).versioned(ComputerCraftAPI.getInstalledVersion());
|
||||
|
||||
for (var type : NetworkMessages.getServerbound()) {
|
||||
var forgeType = ForgeMessageType.cast(type);
|
||||
registrar.play(forgeType.id(), forgeType.reader(), builder -> builder.server(
|
||||
(t, context) -> context.workHandler().execute(() -> t.payload().handle(() -> (ServerPlayer) context.player().orElseThrow()))
|
||||
));
|
||||
}
|
||||
|
||||
for (var type : NetworkMessages.getClientbound()) {
|
||||
var forgeType = ForgeMessageType.cast(type);
|
||||
registrar.play(forgeType.id(), forgeType.reader(), builder -> builder.client(
|
||||
(t, context) -> context.workHandler().execute(() -> t.payload().handle(ClientHolderHolder.get()))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach capabilities to our block entities.
|
||||
*
|
||||
* @param event The event to register capabilities with.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onRegisterCapabilities(RegisterCapabilitiesEvent event) {
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.COMPUTER_NORMAL.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.COMPUTER_ADVANCED.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.TURTLE_NORMAL.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.SPEAKER.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.PRINTER.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.DISK_DRIVE.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.MONITOR_NORMAL.get(), (b, d) -> b.peripheral());
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), (b, d) -> b.peripheral());
|
||||
|
||||
event.registerBlockEntity(
|
||||
PeripheralCapability.get(), BlockEntityType.COMMAND_BLOCK,
|
||||
(b, d) -> Config.enableCommandBlock ? new CommandBlockPeripheral(b) : null
|
||||
);
|
||||
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.WIRELESS_MODEM_NORMAL.get(), WirelessModemBlockEntity::getPeripheral);
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.WIRELESS_MODEM_ADVANCED.get(), WirelessModemBlockEntity::getPeripheral);
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.WIRED_MODEM_FULL.get(), WiredModemFullBlockEntity::getPeripheral);
|
||||
event.registerBlockEntity(PeripheralCapability.get(), ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getPeripheral);
|
||||
|
||||
event.registerBlockEntity(WiredElementCapability.get(), ModRegistry.BlockEntities.WIRED_MODEM_FULL.get(), (b, d) -> b.getElement());
|
||||
event.registerBlockEntity(WiredElementCapability.get(), ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getWiredElement);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -107,4 +168,24 @@ public final class ComputerCraft {
|
||||
public static void onCreativeTab(BuildCreativeModeTabContentsEvent event) {
|
||||
CommonHooks.onBuildCreativeTab(event.getTabKey(), event.getParameters(), event);
|
||||
}
|
||||
|
||||
/**
|
||||
* This holds an instance of {@link ClientNetworkContext}. This is a separate class to ensure that the instance is
|
||||
* lazily created when needed on the client.
|
||||
*/
|
||||
private static final class ClientHolderHolder {
|
||||
private static final @Nullable ClientNetworkContext INSTANCE;
|
||||
private static final @Nullable Throwable ERROR;
|
||||
|
||||
static {
|
||||
var helper = Services.tryLoad(ClientNetworkContext.class);
|
||||
INSTANCE = helper.instance();
|
||||
ERROR = helper.error();
|
||||
}
|
||||
|
||||
static ClientNetworkContext get() {
|
||||
var instance = INSTANCE;
|
||||
return instance == null ? Services.raise(ClientNetworkContext.class, ERROR) : instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
package dan200.computercraft.data;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.platform.RegistryWrappers;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.loot.LootTableProvider;
|
||||
import net.minecraft.data.models.BlockModelGenerators;
|
||||
import net.minecraft.data.models.ItemModelGenerators;
|
||||
@@ -21,16 +21,14 @@ import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.common.data.BlockTagsProvider;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import net.minecraftforge.common.data.JsonCodecProvider;
|
||||
import net.minecraftforge.data.event.GatherDataEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.common.data.BlockTagsProvider;
|
||||
import net.neoforged.neoforge.common.data.ExistingFileHelper;
|
||||
import net.neoforged.neoforge.common.data.JsonCodecProvider;
|
||||
import net.neoforged.neoforge.data.event.GatherDataEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -57,9 +55,16 @@ public class Generators {
|
||||
@Override
|
||||
public <T> void addFromCodec(String name, PackType type, String directory, Codec<T> codec, Consumer<BiConsumer<ResourceLocation, T>> output) {
|
||||
add(out -> {
|
||||
Map<ResourceLocation, T> map = new HashMap<>();
|
||||
output.accept(map::put);
|
||||
return new JsonCodecProvider<>(out, existingFiles, ComputerCraftAPI.MOD_ID, JsonOps.INSTANCE, type, directory, codec, map);
|
||||
var target = switch (type) {
|
||||
case SERVER_DATA -> PackOutput.Target.DATA_PACK;
|
||||
case CLIENT_RESOURCES -> PackOutput.Target.RESOURCE_PACK;
|
||||
};
|
||||
return new JsonCodecProvider<T>(out, target, directory, type, codec, registries, ComputerCraftAPI.MOD_ID, existingFiles) {
|
||||
@Override
|
||||
protected void gather() {
|
||||
output.accept(this::unconditional);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +78,7 @@ public class Generators {
|
||||
return add(out -> new BlockTagsProvider(out, registries, ComputerCraftAPI.MOD_ID, existingFiles) {
|
||||
@Override
|
||||
protected void addTags(HolderLookup.Provider registries) {
|
||||
tags.accept(x -> new TagProvider.TagAppender<>(RegistryWrappers.BLOCKS, getOrCreateRawBuilder(x)));
|
||||
tags.accept(x -> new TagProvider.TagAppender<>(BuiltInRegistries.BLOCK, getOrCreateRawBuilder(x)));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -87,7 +92,7 @@ public class Generators {
|
||||
tags.accept(new TagProvider.ItemTagConsumer() {
|
||||
@Override
|
||||
public TagProvider.TagAppender<Item> tag(TagKey<Item> tag) {
|
||||
return new TagProvider.TagAppender<>(RegistryWrappers.ITEMS, getOrCreateRawBuilder(tag));
|
||||
return new TagProvider.TagAppender<>(BuiltInRegistries.ITEM, getOrCreateRawBuilder(tag));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,21 +7,20 @@ package dan200.computercraft.impl;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.detail.DetailRegistry;
|
||||
import dan200.computercraft.api.network.wired.WiredElement;
|
||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||
import dan200.computercraft.impl.detail.DetailRegistryImpl;
|
||||
import dan200.computercraft.shared.details.FluidData;
|
||||
import dan200.computercraft.shared.peripheral.generic.ComponentLookup;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.neoforged.fml.ModList;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapability;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT;
|
||||
import java.util.Objects;
|
||||
|
||||
@AutoService(ComputerCraftAPIService.class)
|
||||
public final class ComputerCraftAPIImpl extends AbstractComputerCraftAPI implements ComputerCraftAPIForgeService {
|
||||
@@ -38,23 +37,30 @@ public final class ComputerCraftAPIImpl extends AbstractComputerCraftAPI impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPeripheralProvider(IPeripheralProvider provider) {
|
||||
Peripherals.register(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGenericCapability(Capability<?> capability) {
|
||||
Peripherals.registerGenericCapability(capability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyOptional<WiredElement> getWiredElementAt(BlockGetter world, BlockPos pos, Direction side) {
|
||||
var tile = world.getBlockEntity(pos);
|
||||
return tile == null ? LazyOptional.empty() : tile.getCapability(CAPABILITY_WIRED_ELEMENT, side);
|
||||
public void registerGenericCapability(BlockCapability<?, Direction> capability) {
|
||||
Objects.requireNonNull(capability, "Capability cannot be null");
|
||||
Peripherals.addGenericLookup(new CapabilityLookup<>(capability));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetailRegistry<FluidStack> getFluidStackDetailRegistry() {
|
||||
return fluidStackDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ComponentLookup} for {@linkplain BlockCapability capabilities}.
|
||||
* <p>
|
||||
* This is a record to ensure that adding the same capability multiple times only results in one lookup being
|
||||
* present in the resulting list.
|
||||
*
|
||||
* @param capability The capability to lookup
|
||||
* @param <T> The type of the capability we look up.
|
||||
*/
|
||||
private record CapabilityLookup<T>(BlockCapability<T, Direction> capability) implements ComponentLookup {
|
||||
@Nullable
|
||||
@Override
|
||||
public T find(ServerLevel level, BlockPos pos, BlockState state, BlockEntity blockEntity, Direction side) {
|
||||
return level.getCapability(capability, pos, state, blockEntity, side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
|
||||
package dan200.computercraft.impl;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||
import dan200.computercraft.shared.peripheral.generic.ComponentLookup;
|
||||
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
||||
import dan200.computercraft.shared.platform.InvalidateCallback;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
/**
|
||||
* The registry for peripheral providers.
|
||||
* <p>
|
||||
* This lives in the {@code impl} package despite it not being part of the public API, in order to mirror Forge's class.
|
||||
*/
|
||||
public final class Peripherals {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Peripherals.class);
|
||||
|
||||
private static final Collection<IPeripheralProvider> providers = new LinkedHashSet<>();
|
||||
private static final GenericPeripheralProvider<InvalidateCallback> genericProvider = new GenericPeripheralProvider<>();
|
||||
|
||||
private Peripherals() {
|
||||
}
|
||||
|
||||
public static synchronized void register(IPeripheralProvider provider) {
|
||||
Objects.requireNonNull(provider, "provider cannot be null");
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
public static void registerGenericLookup(ComponentLookup<InvalidateCallback> lookup) {
|
||||
genericProvider.registerLookup(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ComponentLookup} for {@linkplain Capability capabilities}.
|
||||
* <p>
|
||||
* This is a record to ensure that adding the same capability multiple times only results in one lookup being
|
||||
* present in the resulting list.
|
||||
*
|
||||
* @param capability The capability to lookup
|
||||
* @param <T> The type of the capability we look up.
|
||||
*/
|
||||
private record CapabilityLookup<T>(Capability<T> capability) implements ComponentLookup<InvalidateCallback> {
|
||||
@Nullable
|
||||
@Override
|
||||
public T find(ServerLevel level, BlockPos pos, BlockState state, BlockEntity blockEntity, Direction side, InvalidateCallback invalidate) {
|
||||
return CapabilityUtil.unwrap(CapabilityUtil.getCapability(blockEntity, this.capability(), side), invalidate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerGenericCapability(Capability<?> capability) {
|
||||
Objects.requireNonNull(capability, "Capability cannot be null");
|
||||
registerGenericLookup(new CapabilityLookup<>(capability));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IPeripheral getPeripheral(ServerLevel world, BlockPos pos, Direction side, InvalidateCallback invalidate) {
|
||||
if (!world.isInWorldBounds(pos)) return null;
|
||||
|
||||
var block = world.getBlockEntity(pos);
|
||||
if (block != null) {
|
||||
var peripheral = block.getCapability(CAPABILITY_PERIPHERAL, side);
|
||||
if (peripheral.isPresent()) return CapabilityUtil.unwrap(peripheral, invalidate);
|
||||
}
|
||||
|
||||
// Try the handlers in order:
|
||||
for (var peripheralProvider : providers) {
|
||||
try {
|
||||
var peripheral = peripheralProvider.getPeripheral(world, pos, side);
|
||||
if (peripheral.isPresent()) return CapabilityUtil.unwrap(peripheral, invalidate);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Peripheral provider " + peripheralProvider + " errored.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return genericProvider.getPeripheral(world, pos, side, block, invalidate);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared;
|
||||
|
||||
import dan200.computercraft.api.network.wired.WiredElement;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||
|
||||
public final class Capabilities {
|
||||
public static final Capability<IPeripheral> CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>() {
|
||||
});
|
||||
|
||||
public static final Capability<WiredElement> CAPABILITY_WIRED_ELEMENT = CapabilityManager.get(new CapabilityToken<>() {
|
||||
});
|
||||
|
||||
private Capabilities() {
|
||||
}
|
||||
}
|
||||
@@ -6,38 +6,18 @@ package dan200.computercraft.shared;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.CapabilityProvider;
|
||||
import dan200.computercraft.shared.util.SidedCapabilityProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
||||
import net.minecraftforge.event.*;
|
||||
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
||||
import net.minecraftforge.event.level.ChunkWatchEvent;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppedEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
import static net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.event.*;
|
||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.neoforged.neoforge.event.entity.living.LivingDropsEvent;
|
||||
import net.neoforged.neoforge.event.level.ChunkWatchEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartingEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStoppedEvent;
|
||||
|
||||
/**
|
||||
* Forge-specific dispatch for {@link CommonHooks}.
|
||||
@@ -57,6 +37,11 @@ public class ForgeCommonHooks {
|
||||
CommonHooks.onServerStarting(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStarted(ServerStartedEvent event) {
|
||||
CommonHooks.onServerStarted(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStopped(ServerStoppedEvent event) {
|
||||
CommonHooks.onServerStopped();
|
||||
@@ -68,7 +53,7 @@ public class ForgeCommonHooks {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onChunkWatch(ChunkWatchEvent.Watch event) {
|
||||
public static void onChunkWatch(ChunkWatchEvent.Sent event) {
|
||||
CommonHooks.onChunkWatch(event.getChunk(), event.getPlayer());
|
||||
}
|
||||
|
||||
@@ -87,57 +72,6 @@ public class ForgeCommonHooks {
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation PERIPHERAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "peripheral");
|
||||
private static final ResourceLocation WIRED_ELEMENT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_node");
|
||||
private static final ResourceLocation INVENTORY = new ResourceLocation(ComputerCraftAPI.MOD_ID, "inventory");
|
||||
|
||||
/**
|
||||
* Attach capabilities to our block entities.
|
||||
*
|
||||
* @param event The {@link AttachCapabilitiesEvent} event.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onCapability(AttachCapabilitiesEvent<BlockEntity> event) {
|
||||
var blockEntity = event.getObject();
|
||||
if (blockEntity instanceof ComputerBlockEntity computer) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, computer::peripheral);
|
||||
} else if (blockEntity instanceof TurtleBlockEntity turtle) {
|
||||
CapabilityProvider.attach(event, INVENTORY, ITEM_HANDLER, () -> new InvWrapper(turtle));
|
||||
|
||||
var peripheral = CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, turtle::peripheral);
|
||||
turtle.onMoved(peripheral::invalidate);
|
||||
} else if (blockEntity instanceof DiskDriveBlockEntity diskDrive) {
|
||||
CapabilityProvider.attach(event, INVENTORY, ITEM_HANDLER, () -> new InvWrapper(diskDrive));
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, diskDrive::peripheral);
|
||||
} else if (blockEntity instanceof CableBlockEntity cable) {
|
||||
var peripheralHandler = SidedCapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, cable::getPeripheral);
|
||||
var elementHandler = SidedCapabilityProvider.attach(event, WIRED_ELEMENT, Capabilities.CAPABILITY_WIRED_ELEMENT, cable::getWiredElement);
|
||||
cable.onModemChanged(() -> {
|
||||
peripheralHandler.invalidate();
|
||||
elementHandler.invalidate();
|
||||
});
|
||||
} else if (blockEntity instanceof WiredModemFullBlockEntity modem) {
|
||||
SidedCapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, modem::getPeripheral);
|
||||
CapabilityProvider.attach(event, WIRED_ELEMENT, Capabilities.CAPABILITY_WIRED_ELEMENT, modem::getElement);
|
||||
} else if (blockEntity instanceof WirelessModemBlockEntity modem) {
|
||||
var peripheral = SidedCapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, modem::getPeripheral);
|
||||
modem.onModemChanged(peripheral::invalidate);
|
||||
} else if (blockEntity instanceof MonitorBlockEntity monitor) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, monitor::peripheral);
|
||||
} else if (blockEntity instanceof SpeakerBlockEntity speaker) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, speaker::peripheral);
|
||||
} else if (blockEntity instanceof PrinterBlockEntity printer) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, printer::peripheral);
|
||||
// We don't need to invalidate here as the block's can't be rotated on the X axis!
|
||||
SidedCapabilityProvider.attach(
|
||||
event, INVENTORY, ITEM_HANDLER,
|
||||
s -> s == null ? new InvWrapper(printer) : new SidedInvWrapper(printer, s)
|
||||
);
|
||||
} else if (Config.enableCommandBlock && blockEntity instanceof CommandBlockEntity commandBlock) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, () -> new CommandBlockPeripheral(commandBlock));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void lootLoad(LootTableLoadEvent event) {
|
||||
var pool = CommonHooks.getExtraLootPool(event.getName());
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
package dan200.computercraft.shared.details;
|
||||
|
||||
import dan200.computercraft.shared.platform.RegistryWrappers;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class FluidData {
|
||||
public static void fillBasic(Map<? super String, Object> data, FluidStack stack) {
|
||||
data.put("name", DetailHelpers.getId(RegistryWrappers.FLUIDS, stack.getFluid()));
|
||||
data.put("name", DetailHelpers.getId(BuiltInRegistries.FLUID, stack.getFluid()));
|
||||
data.put("amount", stack.getAmount());
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.server.permission.PermissionAPI;
|
||||
import net.minecraftforge.server.permission.events.PermissionGatherEvent;
|
||||
import net.minecraftforge.server.permission.nodes.PermissionNode;
|
||||
import net.minecraftforge.server.permission.nodes.PermissionType;
|
||||
import net.minecraftforge.server.permission.nodes.PermissionTypes;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.server.permission.PermissionAPI;
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -52,7 +52,7 @@ public final class ForgePermissionRegistry extends PermissionRegistry {
|
||||
@Override
|
||||
public void register() {
|
||||
super.register();
|
||||
MinecraftForge.EVENT_BUS.addListener((PermissionGatherEvent.Nodes event) -> event.addNodes(nodes));
|
||||
NeoForge.EVENT_BUS.addListener((PermissionGatherEvent.Nodes event) -> event.addNodes(nodes));
|
||||
}
|
||||
|
||||
@AutoService(PermissionRegistry.Provider.class)
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration;
|
||||
|
||||
import commoble.morered.api.MoreRedAPI;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||
import dan200.computercraft.shared.util.SidedCapabilityProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
public class MoreRedIntegration {
|
||||
public static final String MOD_ID = "morered";
|
||||
|
||||
private static final ResourceLocation ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, MOD_ID);
|
||||
|
||||
@SubscribeEvent
|
||||
public static void attachBlockCapabilities(AttachCapabilitiesEvent<BlockEntity> event) {
|
||||
var blockEntity = event.getObject();
|
||||
|
||||
if (blockEntity.getBlockState().getBlock() instanceof IBundledRedstoneBlock bundledBlock) {
|
||||
// The API is a little unclear on whether this needs to be sided. The API design mirrors Block.getSignal
|
||||
// (suggesting we can use wireFace.getOpposite(), which is what we did on older versions), but on the other
|
||||
// hand that parameter is not guaranteed to be non-null (suggesting we should use the cap side instead).
|
||||
SidedCapabilityProvider.attach(event, ID, MoreRedAPI.CHANNELED_POWER_CAPABILITY, side -> (world, wirePos, wireState, wireFace, channel) -> {
|
||||
if (side == null) return 0; // It's not clear if there's a sensible implementation here.
|
||||
|
||||
var level = bundledBlock.getBundledRedstoneOutput(world, blockEntity.getBlockPos(), side);
|
||||
return (level & (1 << channel)) != 0 ? 31 : 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void setup() {
|
||||
MinecraftForge.EVENT_BUS.register(MoreRedIntegration.class);
|
||||
ComputerCraftAPI.registerBundledRedstoneProvider(MoreRedIntegration::getBundledPower);
|
||||
}
|
||||
|
||||
private static int getBundledPower(Level world, BlockPos pos, Direction side) {
|
||||
var blockEntity = world.getBlockEntity(pos);
|
||||
if (blockEntity == null) return -1;
|
||||
|
||||
var blockState = blockEntity.getBlockState();
|
||||
|
||||
// Skip ones already handled by CC. We can do this more efficiently.
|
||||
if (blockState.getBlock() instanceof IBundledRedstoneBlock) return -1;
|
||||
|
||||
var powerCap = blockEntity.getCapability(MoreRedAPI.CHANNELED_POWER_CAPABILITY, side);
|
||||
if (!powerCap.isPresent()) return -1;
|
||||
var power = powerCap.orElseThrow(NullPointerException::new);
|
||||
|
||||
var mask = 0;
|
||||
for (var i = 0; i < 16; i++) {
|
||||
mask |= power.getPowerOnChannel(world, pos, blockState, side, i) > 0 ? (1 << i) : 0;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import net.minecraftforge.energy.IEnergyStorage;
|
||||
import net.neoforged.neoforge.energy.IEnergyStorage;
|
||||
|
||||
/**
|
||||
* Fluid methods for Forge's {@link IEnergyStorage}.
|
||||
|
||||
@@ -8,12 +8,12 @@ import dan200.computercraft.api.detail.ForgeDetailRegistries;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.shared.platform.RegistryWrappers;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
@@ -46,7 +46,7 @@ public final class FluidMethods extends AbstractFluidMethods<IFluidHandler> {
|
||||
String toName, Optional<Integer> limit, Optional<String> fluidName
|
||||
) throws LuaException {
|
||||
var fluid = fluidName.isPresent()
|
||||
? getRegistryEntry(fluidName.get(), "fluid", RegistryWrappers.FLUIDS)
|
||||
? getRegistryEntry(fluidName.get(), "fluid", BuiltInRegistries.FLUID)
|
||||
: null;
|
||||
|
||||
// Find location to transfer to
|
||||
@@ -71,7 +71,7 @@ public final class FluidMethods extends AbstractFluidMethods<IFluidHandler> {
|
||||
String fromName, Optional<Integer> limit, Optional<String> fluidName
|
||||
) throws LuaException {
|
||||
var fluid = fluidName.isPresent()
|
||||
? getRegistryEntry(fluidName.get(), "fluid", RegistryWrappers.FLUIDS)
|
||||
? getRegistryEntry(fluidName.get(), "fluid", BuiltInRegistries.FLUID)
|
||||
: null;
|
||||
|
||||
// Find location to transfer to
|
||||
@@ -91,11 +91,14 @@ public final class FluidMethods extends AbstractFluidMethods<IFluidHandler> {
|
||||
|
||||
@Nullable
|
||||
private static IFluidHandler extractHandler(@Nullable Object object) {
|
||||
if (object instanceof BlockEntity blockEntity && blockEntity.isRemoved()) return null;
|
||||
if (object instanceof BlockEntity blockEntity) {
|
||||
if (blockEntity.isRemoved()) return null;
|
||||
|
||||
if (object instanceof ICapabilityProvider provider) {
|
||||
var cap = provider.getCapability(ForgeCapabilities.FLUID_HANDLER);
|
||||
if (cap.isPresent()) return cap.orElseThrow(NullPointerException::new);
|
||||
var level = blockEntity.getLevel();
|
||||
if (!(level instanceof ServerLevel serverLevel)) return null;
|
||||
|
||||
var result = serverLevel.getCapability(Capabilities.FluidHandler.BLOCK, blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, null);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
if (object instanceof IFluidHandler handler) return handler;
|
||||
|
||||
@@ -9,12 +9,12 @@ import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.shared.platform.ForgeContainerTransfer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
import net.neoforged.neoforge.items.wrapper.InvWrapper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
@@ -109,11 +109,14 @@ public final class InventoryMethods extends AbstractInventoryMethods<IItemHandle
|
||||
|
||||
@Nullable
|
||||
private static IItemHandler extractHandler(@Nullable Object object) {
|
||||
if (object instanceof BlockEntity blockEntity && blockEntity.isRemoved()) return null;
|
||||
if (object instanceof BlockEntity blockEntity) {
|
||||
if (blockEntity.isRemoved()) return null;
|
||||
|
||||
if (object instanceof ICapabilityProvider provider) {
|
||||
var cap = provider.getCapability(ForgeCapabilities.ITEM_HANDLER);
|
||||
if (cap.isPresent()) return cap.orElseThrow(NullPointerException::new);
|
||||
var level = blockEntity.getLevel();
|
||||
if (!(level instanceof ServerLevel serverLevel)) return null;
|
||||
|
||||
var result = serverLevel.getCapability(Capabilities.ItemHandler.BLOCK, blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, null);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
if (object instanceof IItemHandler handler) return handler;
|
||||
|
||||
@@ -12,7 +12,7 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.neoforged.neoforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
@@ -6,7 +6,7 @@ package dan200.computercraft.shared.platform;
|
||||
|
||||
import dan200.computercraft.shared.config.ConfigFile;
|
||||
import dan200.computercraft.shared.util.Trie;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
@@ -18,15 +18,15 @@ import java.util.stream.Stream;
|
||||
* A {@link ConfigFile} which wraps Forge's config implementation.
|
||||
*/
|
||||
public final class ForgeConfigFile implements ConfigFile {
|
||||
private final ForgeConfigSpec spec;
|
||||
private final ModConfigSpec spec;
|
||||
private final Trie<String, ConfigFile.Entry> entries;
|
||||
|
||||
public ForgeConfigFile(ForgeConfigSpec spec, Trie<String, Entry> entries) {
|
||||
public ForgeConfigFile(ModConfigSpec spec, Trie<String, Entry> entries) {
|
||||
this.spec = spec;
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public ForgeConfigSpec spec() {
|
||||
public ModConfigSpec spec() {
|
||||
return spec;
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@ public final class ForgeConfigFile implements ConfigFile {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link ForgeConfigSpec.Builder} into our own config builder abstraction.
|
||||
* Wraps {@link ModConfigSpec.Builder} into our own config builder abstraction.
|
||||
*/
|
||||
static class Builder extends ConfigFile.Builder {
|
||||
private final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
|
||||
private final ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
|
||||
private final Trie<String, ConfigFile.Entry> entries = new Trie<>();
|
||||
|
||||
private void translation(String name) {
|
||||
@@ -80,7 +80,7 @@ public final class ForgeConfigFile implements ConfigFile {
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> ConfigFile.Value<T> defineValue(ForgeConfigSpec.ConfigValue<T> value) {
|
||||
private <T> ConfigFile.Value<T> defineValue(ModConfigSpec.ConfigValue<T> value) {
|
||||
var wrapped = new ValueImpl<>(value);
|
||||
entries.setValue(value.getPath(), wrapped);
|
||||
return wrapped;
|
||||
@@ -129,7 +129,7 @@ public final class ForgeConfigFile implements ConfigFile {
|
||||
|
||||
private static final class GroupImpl implements ConfigFile.Group {
|
||||
private final List<String> path;
|
||||
private @Nullable ForgeConfigSpec owner;
|
||||
private @Nullable ModConfigSpec owner;
|
||||
|
||||
private GroupImpl(List<String> path) {
|
||||
this.path = path;
|
||||
@@ -149,14 +149,14 @@ public final class ForgeConfigFile implements ConfigFile {
|
||||
}
|
||||
|
||||
private static final class ValueImpl<T> implements ConfigFile.Value<T> {
|
||||
private final ForgeConfigSpec.ConfigValue<T> value;
|
||||
private @Nullable ForgeConfigSpec owner;
|
||||
private final ModConfigSpec.ConfigValue<T> value;
|
||||
private @Nullable ModConfigSpec owner;
|
||||
|
||||
private ValueImpl(ForgeConfigSpec.ConfigValue<T> value) {
|
||||
private ValueImpl(ModConfigSpec.ConfigValue<T> value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private ForgeConfigSpec.ValueSpec spec() {
|
||||
private ModConfigSpec.ValueSpec spec() {
|
||||
if (owner == null) throw new IllegalStateException("Config has not been built yet");
|
||||
return owner.getSpec().get(value.getPath());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
|
||||
public class ForgeContainerTransfer implements ContainerTransfer.Slotted {
|
||||
private final IItemHandler handler;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import dan200.computercraft.shared.network.MessageType;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* A {@link MessageType} implementation for Forge.
|
||||
* <p>
|
||||
* This wraps {@link NetworkMessage}s into a {@link CustomPacketPayload}, allowing us to easily use Minecraft's existing
|
||||
* custom packets.
|
||||
*
|
||||
* @param id The id of this message.
|
||||
* @param reader Read this message from a network buffer.
|
||||
* @param <T> The type of our {@link NetworkMessage}.
|
||||
*/
|
||||
public record ForgeMessageType<T extends NetworkMessage<?>>(
|
||||
ResourceLocation id, FriendlyByteBuf.Reader<Payload<T>> reader
|
||||
) implements MessageType<T> {
|
||||
public static <T extends NetworkMessage<?>> ForgeMessageType<T> cast(MessageType<T> type) {
|
||||
return (ForgeMessageType<T>) type;
|
||||
}
|
||||
|
||||
public static CustomPacketPayload createPayload(NetworkMessage<?> message) {
|
||||
return new Payload<>(message);
|
||||
}
|
||||
|
||||
public record Payload<T extends NetworkMessage<?>>(T payload) implements CustomPacketPayload {
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
payload().write(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return payload().type().id();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import dan200.computercraft.shared.peripheral.generic.ComponentLookup;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
/**
|
||||
* A function which may be called when a capability (or some other object) has been invalidated.
|
||||
* <p>
|
||||
* This extends {@link NonNullConsumer} for use with {@link LazyOptional#addListener(NonNullConsumer)}, and
|
||||
* {@link Runnable} for use with {@link ComponentLookup}.
|
||||
*/
|
||||
public interface InvalidateCallback extends Runnable, NonNullConsumer<Object> {
|
||||
@Override
|
||||
default void accept(Object o) {
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast this callback to a {@link NonNullConsumer} of an arbitrary type.
|
||||
*
|
||||
* @param <T> The type of the consumer, normally a {@link LazyOptional}.
|
||||
* @return {@code this}, but with a compatible type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> NonNullConsumer<T> castConsumer() {
|
||||
return (NonNullConsumer<T>) this;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.network.MessageType;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
public final class NetworkHandler {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NetworkHandler.class);
|
||||
|
||||
private static final SimpleChannel network;
|
||||
|
||||
static {
|
||||
var version = ComputerCraftAPI.getInstalledVersion();
|
||||
network = NetworkRegistry.ChannelBuilder.named(new ResourceLocation(ComputerCraftAPI.MOD_ID, "network"))
|
||||
.networkProtocolVersion(() -> version)
|
||||
.clientAcceptedVersions(version::equals).serverAcceptedVersions(version::equals)
|
||||
.simpleChannel();
|
||||
}
|
||||
|
||||
private NetworkHandler() {
|
||||
}
|
||||
|
||||
public static void setup() {
|
||||
for (var type : NetworkMessages.getServerbound()) {
|
||||
var forgeType = (MessageTypeImpl<? extends NetworkMessage<ServerNetworkContext>>) type;
|
||||
registerMainThread(forgeType, NetworkDirection.PLAY_TO_SERVER, c -> () -> assertNonNull(c.getSender()));
|
||||
}
|
||||
|
||||
for (var type : NetworkMessages.getClientbound()) {
|
||||
var forgeType = (MessageTypeImpl<? extends NetworkMessage<ClientNetworkContext>>) type;
|
||||
registerMainThread(forgeType, NetworkDirection.PLAY_TO_CLIENT, x -> ClientHolder.get());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Packet<ClientGamePacketListener> createClientboundPacket(NetworkMessage<ClientNetworkContext> packet) {
|
||||
return (Packet<ClientGamePacketListener>) network.toVanillaPacket(packet, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Packet<ServerGamePacketListener> createServerboundPacket(NetworkMessage<ServerNetworkContext> packet) {
|
||||
return (Packet<ServerGamePacketListener>) network.toVanillaPacket(packet, NetworkDirection.PLAY_TO_SERVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register packet, and a thread-unsafe handler for it.
|
||||
*
|
||||
* @param <T> The type of the packet to send.
|
||||
* @param <H> The context this packet is evaluated under.
|
||||
* @param type The message type to register.
|
||||
* @param direction A network direction which will be asserted before any processing of this message occurs
|
||||
* @param handler Gets or constructs the handler for this packet.
|
||||
*/
|
||||
static <H, T extends NetworkMessage<H>> void registerMainThread(
|
||||
MessageTypeImpl<T> type, NetworkDirection direction, Function<NetworkEvent.Context, H> handler
|
||||
) {
|
||||
network.messageBuilder(type.klass(), type.id(), direction)
|
||||
.encoder(NetworkMessage::write)
|
||||
.decoder(type.reader())
|
||||
.consumerMainThread((packet, contextSup) -> {
|
||||
try {
|
||||
packet.handle(handler.apply(contextSup.get()));
|
||||
} catch (RuntimeException | Error e) {
|
||||
LOG.error("Failed handling packet", e);
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
.add();
|
||||
}
|
||||
|
||||
public record MessageTypeImpl<T extends NetworkMessage<?>>(
|
||||
int id, Class<T> klass, Function<FriendlyByteBuf, T> reader
|
||||
) implements MessageType<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* This holds an instance of {@link ClientNetworkContext}. This is a separate class to ensure that the instance is
|
||||
* lazily created when needed on the client.
|
||||
*/
|
||||
private static final class ClientHolder {
|
||||
private static final @Nullable ClientNetworkContext INSTANCE;
|
||||
private static final @Nullable Throwable ERROR;
|
||||
|
||||
static {
|
||||
var helper = Services.tryLoad(ClientNetworkContext.class);
|
||||
INSTANCE = helper.instance();
|
||||
ERROR = helper.error();
|
||||
}
|
||||
|
||||
static ClientNetworkContext get() {
|
||||
var instance = INSTANCE;
|
||||
return instance == null ? Services.raise(ClientNetworkContext.class, ERROR) : instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,34 +9,39 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.network.wired.WiredElement;
|
||||
import dan200.computercraft.api.network.wired.WiredElementCapability;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
||||
import dan200.computercraft.impl.Peripherals;
|
||||
import dan200.computercraft.shared.Capabilities;
|
||||
import dan200.computercraft.shared.config.ConfigFile;
|
||||
import dan200.computercraft.shared.network.MessageType;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.common.ClientCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.world.*;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
@@ -55,29 +60,28 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.common.ToolActions;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.crafting.CraftingHelper;
|
||||
import net.minecraftforge.common.crafting.conditions.ICondition;
|
||||
import net.minecraftforge.common.crafting.conditions.ModLoadedCondition;
|
||||
import net.minecraftforge.common.extensions.IForgeMenuType;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapability;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapabilityCache;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.common.CommonHooks;
|
||||
import net.neoforged.neoforge.common.Tags;
|
||||
import net.neoforged.neoforge.common.ToolActions;
|
||||
import net.neoforged.neoforge.common.conditions.ConditionalOps;
|
||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||
import net.neoforged.neoforge.common.conditions.ModLoadedCondition;
|
||||
import net.neoforged.neoforge.common.extensions.IMenuTypeExtension;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import net.neoforged.neoforge.items.wrapper.InvWrapper;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.*;
|
||||
|
||||
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
||||
@@ -92,50 +96,27 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return new ForgeConfigFile.Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResourceLocation getRegistryKey(ResourceKey<Registry<T>> registry, T object) {
|
||||
var key = RegistryManager.ACTIVE.getRegistry(registry).getKey(object);
|
||||
if (key == null) throw new IllegalArgumentException(object + " was not registered in " + registry);
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getRegistryObject(ResourceKey<Registry<T>> registry, ResourceLocation id) {
|
||||
var value = RegistryManager.ACTIVE.getRegistry(registry).getValue(id);
|
||||
if (value == null) throw new IllegalArgumentException(id + " was not registered in " + registry);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RegistryWrappers.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> key) {
|
||||
return new RegistryWrapperImpl<>(key.location(), RegistryManager.ACTIVE.getRegistry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RegistrationHelper<T> createRegistrationHelper(ResourceKey<Registry<T>> registry) {
|
||||
return new RegistrationHelperImpl<>(DeferredRegister.create(registry, ComputerCraftAPI.MOD_ID));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <K> K tryGetRegistryObject(ResourceKey<Registry<K>> registry, ResourceLocation id) {
|
||||
return RegistryManager.ACTIVE.getRegistry(registry).getValue(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldLoadResource(JsonObject object) {
|
||||
return ICondition.shouldRegisterEntry(object);
|
||||
return ICondition.conditionsMatched(JsonOps.INSTANCE, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRequiredModCondition(JsonObject object, String modId) {
|
||||
var conditions = GsonHelper.getAsJsonArray(object, "forge:conditions", null);
|
||||
// FIXME: Test this, though maybe this should be implemented a different way anyway?
|
||||
var conditions = GsonHelper.getAsJsonArray(object, ConditionalOps.DEFAULT_CONDITIONS_KEY, null);
|
||||
if (conditions == null) {
|
||||
conditions = new JsonArray();
|
||||
object.add("forge:conditions", conditions);
|
||||
object.add(ConditionalOps.DEFAULT_CONDITIONS_KEY, conditions);
|
||||
}
|
||||
|
||||
conditions.add(CraftingHelper.serialize(new ModLoadedCondition(modId)));
|
||||
conditions.add(ICondition.CODEC.encodeStart(JsonOps.INSTANCE, new ModLoadedCondition(modId)).getOrThrow(false, x -> {
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,22 +131,27 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public <C extends AbstractContainerMenu, T extends ContainerData> MenuType<C> createMenuType(Function<FriendlyByteBuf, T> reader, ContainerData.Factory<C, T> factory) {
|
||||
return IForgeMenuType.create((id, player, data) -> factory.create(id, player, reader.apply(data)));
|
||||
return IMenuTypeExtension.create((id, player, data) -> factory.create(id, player, reader.apply(data)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMenu(Player player, MenuProvider owner, ContainerData menu) {
|
||||
NetworkHooks.openScreen((ServerPlayer) player, owner, menu::toBytes);
|
||||
((ServerPlayer) player).openMenu(owner, menu::toBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NetworkMessage<?>> MessageType<T> createMessageType(int id, ResourceLocation channel, Class<T> klass, FriendlyByteBuf.Reader<T> reader) {
|
||||
return new NetworkHandler.MessageTypeImpl<>(id, klass, reader);
|
||||
public <T extends NetworkMessage<?>> MessageType<T> createMessageType(ResourceLocation id, FriendlyByteBuf.Reader<T> reader) {
|
||||
return new ForgeMessageType<>(id, b -> new ForgeMessageType.Payload<>(reader.apply(b)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<ClientGamePacketListener> createPacket(NetworkMessage<ClientNetworkContext> message) {
|
||||
return NetworkHandler.createClientboundPacket(message);
|
||||
public Packet<ClientCommonPacketListener> createPacket(NetworkMessage<ClientNetworkContext> message) {
|
||||
return new ClientboundCustomPayloadPacket(ForgeMessageType.createPayload(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateComponent(BlockEntity owner) {
|
||||
owner.invalidateCapabilities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,15 +161,13 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public ComponentAccess<WiredElement> createWiredElementAccess(BlockEntity owner, Consumer<Direction> invalidate) {
|
||||
return new CapabilityAccess<>(owner, Capabilities.CAPABILITY_WIRED_ELEMENT, invalidate);
|
||||
return new ComponentAccessImpl<>(owner, WiredElementCapability.get(), invalidate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasWiredElementIn(Level level, BlockPos pos, Direction direction) {
|
||||
if (!level.isLoaded(pos)) return false;
|
||||
|
||||
var blockEntity = level.getBlockEntity(pos.relative(direction));
|
||||
return blockEntity != null && blockEntity.getCapability(Capabilities.CAPABILITY_WIRED_ELEMENT, direction.getOpposite()).isPresent();
|
||||
return level.getCapability(WiredElementCapability.get(), pos.relative(direction), direction.getOpposite()) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,30 +178,13 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
@Nullable
|
||||
@Override
|
||||
public ContainerTransfer getContainer(ServerLevel level, BlockPos pos, Direction side) {
|
||||
var block = level.getBlockState(pos);
|
||||
if (block.getBlock() instanceof WorldlyContainerHolder holder) {
|
||||
var container = holder.getContainer(block, level, pos);
|
||||
return new ForgeContainerTransfer(new SidedInvWrapper(container, side));
|
||||
}
|
||||
|
||||
var blockEntity = level.getBlockEntity(pos);
|
||||
if (blockEntity != null) {
|
||||
var inventory = blockEntity.getCapability(ForgeCapabilities.ITEM_HANDLER, side);
|
||||
if (inventory.isPresent()) {
|
||||
return new ForgeContainerTransfer(inventory.orElseThrow(NullPointerException::new));
|
||||
}
|
||||
}
|
||||
var inventory = level.getCapability(Capabilities.ItemHandler.BLOCK, pos, side);
|
||||
if (inventory != null) return new ForgeContainerTransfer(inventory);
|
||||
|
||||
var entity = InventoryUtil.getEntityContainer(level, pos, side);
|
||||
return entity == null ? null : new ForgeContainerTransfer(new InvWrapper(entity));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag getShareTag(ItemStack item) {
|
||||
return item.getShareTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeIngredients getRecipeIngredients() {
|
||||
return new RecipeIngredients(
|
||||
@@ -260,7 +227,7 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public int getBurnTime(ItemStack stack) {
|
||||
return ForgeHooks.getBurnTime(stack, null);
|
||||
return CommonHooks.getBurnTime(stack, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -275,20 +242,20 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getRecipeRemainingItems(ServerPlayer player, Recipe<CraftingContainer> recipe, CraftingContainer container) {
|
||||
ForgeHooks.setCraftingPlayer(player);
|
||||
CommonHooks.setCraftingPlayer(player);
|
||||
var result = recipe.getRemainingItems(container);
|
||||
ForgeHooks.setCraftingPlayer(null);
|
||||
CommonHooks.setCraftingPlayer(null);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemCrafted(ServerPlayer player, CraftingContainer container, ItemStack stack) {
|
||||
ForgeEventFactory.firePlayerCraftingEvent(player, stack, container);
|
||||
EventHooks.firePlayerCraftingEvent(player, stack, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNotifyNeighbour(Level level, BlockPos pos, BlockState block, Direction direction) {
|
||||
return !ForgeEventFactory.onNeighborNotify(level, pos, block, EnumSet.of(direction), false).isCanceled();
|
||||
return !EventHooks.onNeighborNotify(level, pos, block, EnumSet.of(direction), false).isCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -308,14 +275,14 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public InteractionResult canAttackEntity(ServerPlayer player, Entity entity) {
|
||||
return ForgeHooks.onPlayerAttackTarget(player, entity) ? InteractionResult.PASS : InteractionResult.SUCCESS;
|
||||
return CommonHooks.onPlayerAttackTarget(player, entity) ? InteractionResult.PASS : InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interactWithEntity(ServerPlayer player, Entity entity, Vec3 hitPos) {
|
||||
// Our behaviour is slightly different here - we call onInteractEntityAt before the interact methods, while
|
||||
// Forge does the call afterwards (on the server, not on the client).
|
||||
var interactAt = ForgeHooks.onInteractEntityAt(player, entity, hitPos, InteractionHand.MAIN_HAND);
|
||||
var interactAt = CommonHooks.onInteractEntityAt(player, entity, hitPos, InteractionHand.MAIN_HAND);
|
||||
if (interactAt == null) {
|
||||
interactAt = entity.interactAt(player, hitPos.subtract(entity.position()), InteractionHand.MAIN_HAND);
|
||||
}
|
||||
@@ -327,7 +294,7 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
public InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit, Predicate<BlockState> canUseBlock) {
|
||||
var level = player.level();
|
||||
var pos = hit.getBlockPos();
|
||||
var event = ForgeHooks.onRightClickBlock(player, InteractionHand.MAIN_HAND, pos, hit);
|
||||
var event = CommonHooks.onRightClickBlock(player, InteractionHand.MAIN_HAND, pos, hit);
|
||||
if (event.isCanceled()) return event.getCancellationResult();
|
||||
|
||||
var context = new UseOnContext(player, InteractionHand.MAIN_HAND, hit);
|
||||
@@ -345,63 +312,19 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return event.getUseItem() == Event.Result.DENY ? InteractionResult.PASS : stack.useOn(context);
|
||||
}
|
||||
|
||||
private record RegistryWrapperImpl<T>(
|
||||
ResourceLocation name, ForgeRegistry<T> registry
|
||||
) implements RegistryWrappers.RegistryWrapper<T> {
|
||||
private record RegistrationHelperImpl<R>(DeferredRegister<R> registry) implements RegistrationHelper<R> {
|
||||
@Override
|
||||
public int getId(T object) {
|
||||
return registry.getID(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getKey(T object) {
|
||||
var key = registry.getKey(object);
|
||||
if (key == null) throw new IllegalStateException(object + " was not registered in " + name);
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(ResourceLocation location) {
|
||||
var object = registry.getValue(location);
|
||||
if (object == null) throw new IllegalStateException(location + " was not registered in " + name);
|
||||
return object;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T tryGet(ResourceLocation location) {
|
||||
return registry.getValue(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable T byId(int id) {
|
||||
return registry.getValue(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return registry.getKeys().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return registry.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
private record RegistrationHelperImpl<T>(DeferredRegister<T> registry) implements RegistrationHelper<T> {
|
||||
@Override
|
||||
public <U extends T> RegistryEntry<U> register(String name, Supplier<U> create) {
|
||||
public <T extends R> RegistryEntry<T> register(String name, Supplier<T> create) {
|
||||
return new RegistryEntryImpl<>(registry().register(name, create));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
registry().register(FMLJavaModLoadingContext.get().getModEventBus());
|
||||
registry().register(ComputerCraft.getEventBus());
|
||||
}
|
||||
}
|
||||
|
||||
private record RegistryEntryImpl<T>(RegistryObject<T> object) implements RegistryEntry<T> {
|
||||
private record RegistryEntryImpl<R, T extends R>(DeferredHolder<R, T> object) implements RegistryEntry<T> {
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return object().getId();
|
||||
@@ -413,61 +336,52 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class ComponentAccessImpl<T> implements ComponentAccess<T> {
|
||||
private static class ComponentAccessImpl<T> implements ComponentAccess<T> {
|
||||
private final BlockEntity owner;
|
||||
private final InvalidateCallback[] invalidators;
|
||||
private final BlockCapability<T, Direction> capability;
|
||||
private final Consumer<Direction> invalidate;
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final BlockCapabilityCache<T, Direction>[] caches = new BlockCapabilityCache[6];
|
||||
|
||||
ComponentAccessImpl(BlockEntity owner, Consumer<Direction> invalidate) {
|
||||
ComponentAccessImpl(BlockEntity owner, BlockCapability<T, Direction> capability, Consumer<Direction> invalidate) {
|
||||
this.owner = owner;
|
||||
|
||||
// Generate a cache of invalidation functions so we can guarantee we only ever have one registered per
|
||||
// capability - there's no way to remove these callbacks!
|
||||
var invalidators = this.invalidators = new InvalidateCallback[6];
|
||||
for (var dir : Direction.values()) invalidators[dir.ordinal()] = () -> invalidate.accept(dir);
|
||||
this.capability = capability;
|
||||
this.invalidate = invalidate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract T get(ServerLevel world, BlockPos pos, Direction side, InvalidateCallback invalidate);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T get(Direction direction) {
|
||||
return get(getLevel(), owner.getBlockPos().relative(direction), direction.getOpposite(), invalidators[direction.ordinal()]);
|
||||
var level = getLevel();
|
||||
var cache = caches[direction.ordinal()];
|
||||
if (cache == null) {
|
||||
cache = caches[direction.ordinal()] = BlockCapabilityCache.create(
|
||||
capability, level, owner.getBlockPos().relative(direction),
|
||||
direction.getOpposite(), () -> !owner.isRemoved(), () -> this.invalidate.accept(direction)
|
||||
);
|
||||
}
|
||||
|
||||
return cache.getCapability();
|
||||
}
|
||||
|
||||
final ServerLevel getLevel() {
|
||||
return Objects.requireNonNull((ServerLevel) owner.getLevel(), "Block entity is not in a level");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class PeripheralAccess extends ComponentAccessImpl<IPeripheral> {
|
||||
PeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
|
||||
super(owner, invalidate);
|
||||
super(owner, PeripheralCapability.get(), invalidate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected IPeripheral get(ServerLevel world, BlockPos pos, Direction side, InvalidateCallback invalidate) {
|
||||
return Peripherals.getPeripheral(world, pos, side, invalidate);
|
||||
}
|
||||
}
|
||||
public IPeripheral get(Direction direction) {
|
||||
var result = super.get(direction);
|
||||
if (result != null) return result;
|
||||
|
||||
private static class CapabilityAccess<T> extends ComponentAccessImpl<T> {
|
||||
private final Capability<T> capability;
|
||||
|
||||
CapabilityAccess(BlockEntity owner, Capability<T> capability, Consumer<Direction> invalidate) {
|
||||
super(owner, invalidate);
|
||||
this.capability = capability;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected T get(ServerLevel world, BlockPos pos, Direction side, InvalidateCallback invalidate) {
|
||||
if (!world.isLoaded(pos)) return null;
|
||||
|
||||
var blockEntity = world.getBlockEntity(pos);
|
||||
return blockEntity != null ? CapabilityUtil.unwrap(blockEntity.getCapability(capability, side), invalidate) : null;
|
||||
var cache = caches[direction.ordinal()];
|
||||
return Peripherals.getGenericPeripheral(cache.level(), cache.pos(), cache.context(), cache.level().getBlockEntity(cache.pos()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A basic {@link ICapabilityProvider} which provides a single capability, returning the same instance for every
|
||||
* direction.
|
||||
* <p>
|
||||
* This is designed for use with {@link AttachCapabilitiesEvent}, to attach individual capabilities to a specific
|
||||
* block entity.
|
||||
*
|
||||
* @param <T> The capability to provide.
|
||||
*/
|
||||
public final class CapabilityProvider<T> implements ICapabilityProvider {
|
||||
private final Capability<T> cap;
|
||||
private final Supplier<T> supplier;
|
||||
private final BooleanSupplier isRemoved;
|
||||
private @Nullable LazyOptional<T> instance;
|
||||
|
||||
private CapabilityProvider(Capability<T> cap, Supplier<T> supplier, BooleanSupplier isRemoved) {
|
||||
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
||||
this.supplier = supplier;
|
||||
this.isRemoved = isRemoved;
|
||||
}
|
||||
|
||||
public static <T> CapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Supplier<T> instance) {
|
||||
BooleanSupplier isRemoved
|
||||
= event.getObject() instanceof BlockEntity be ? be::isRemoved
|
||||
: event.getObject() instanceof Entity entity ? entity::isRemoved
|
||||
: () -> true;
|
||||
var provider = new CapabilityProvider<>(cap, instance, isRemoved);
|
||||
event.addCapability(id, provider);
|
||||
event.addListener(provider::invalidate);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
instance = CapabilityUtil.invalidate(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
||||
if (cap != this.cap || isRemoved.getAsBoolean()) return LazyOptional.empty();
|
||||
|
||||
var instance = this.instance;
|
||||
if (instance == null) {
|
||||
var created = supplier.get();
|
||||
instance = this.instance = created == null ? LazyOptional.empty() : LazyOptional.of(() -> created);
|
||||
}
|
||||
return instance.cast();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.shared.platform.InvalidateCallback;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class CapabilityUtil {
|
||||
private CapabilityUtil() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> LazyOptional<T> invalidate(@Nullable LazyOptional<T> cap) {
|
||||
if (cap != null) cap.invalidate();
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> void invalidate(@Nullable LazyOptional<T>[] caps) {
|
||||
if (caps == null) return;
|
||||
|
||||
for (var i = 0; i < caps.length; i++) {
|
||||
var cap = caps[i];
|
||||
if (cap != null) cap.invalidate();
|
||||
caps[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> T unwrap(LazyOptional<T> p, InvalidateCallback invalidate) {
|
||||
if (!p.isPresent()) return null;
|
||||
|
||||
p.addListener(invalidate.castConsumer());
|
||||
return p.orElseThrow(NullPointerException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a capability, preferring the internal/null side but falling back to a given side if a mod doesn't support
|
||||
* the internal one.
|
||||
*
|
||||
* @param provider The capability provider to get the capability from.
|
||||
* @param capability The capability to get.
|
||||
* @param side The side we'll fall back to.
|
||||
* @param <T> The type of the underlying capability.
|
||||
* @return The extracted capability, if present.
|
||||
*/
|
||||
public static <T> LazyOptional<T> getCapability(ICapabilityProvider provider, Capability<T> capability, Direction side) {
|
||||
var cap = provider.getCapability(capability);
|
||||
return cap.isPresent() ? cap : provider.getCapability(capability, side);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* A {@link ICapabilityProvider} which provides a different single capability, with different instances for each
|
||||
* direction.
|
||||
* <p>
|
||||
* This is designed for use with {@link AttachCapabilitiesEvent}, to attach individual capabilities to a specific
|
||||
* block entity.
|
||||
*
|
||||
* @param <T> The capability to provide.
|
||||
* @see CapabilityProvider
|
||||
*/
|
||||
public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
||||
private final Capability<T> cap;
|
||||
private final Provider<T> supplier;
|
||||
private final BooleanSupplier isRemoved;
|
||||
private @Nullable LazyOptional<T>[] instances;
|
||||
|
||||
private SidedCapabilityProvider(Capability<T> cap, Provider<T> supplier, BooleanSupplier isRemoved) {
|
||||
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
||||
this.supplier = supplier;
|
||||
this.isRemoved = isRemoved;
|
||||
}
|
||||
|
||||
public static <T> SidedCapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Provider<T> supplier) {
|
||||
BooleanSupplier isRemoved
|
||||
= event.getObject() instanceof BlockEntity be ? be::isRemoved
|
||||
: event.getObject() instanceof Entity entity ? entity::isRemoved
|
||||
: () -> true;
|
||||
var provider = new SidedCapabilityProvider<>(cap, supplier, isRemoved);
|
||||
event.addCapability(id, provider);
|
||||
event.addListener(provider::invalidate);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
CapabilityUtil.invalidate(instances);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
||||
if (cap != this.cap || isRemoved.getAsBoolean()) return LazyOptional.empty();
|
||||
|
||||
var instances = this.instances;
|
||||
if (instances == null) instances = this.instances = new LazyOptional[6];
|
||||
|
||||
var index = side == null ? 6 : side.ordinal();
|
||||
|
||||
var instance = instances[index];
|
||||
if (instance == null) {
|
||||
var created = supplier.get(side);
|
||||
instance = instances[index] = created == null ? LazyOptional.empty() : LazyOptional.of(() -> created);
|
||||
}
|
||||
|
||||
return instance.cast();
|
||||
}
|
||||
|
||||
public interface Provider<T> {
|
||||
@Nullable
|
||||
T get(@Nullable Direction direction);
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,33 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# DirectVertexBuffer
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_231217_ # vertexBufferId
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_166861_ # indexType
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_166863_ # indexCount
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_166864_ # mode
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_166865_ # sequentialIndices
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer f_85917_ # format
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer vertexBufferId
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer indexType
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer indexCount
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer mode
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer sequentialIndices
|
||||
protected com.mojang.blaze3d.vertex.VertexBuffer format
|
||||
|
||||
# ClientTableFormatter
|
||||
public net.minecraft.client.gui.components.ChatComponent f_93760_ # allMessages
|
||||
public net.minecraft.client.gui.components.ChatComponent m_241120_()V # refreshTrimmedMessage
|
||||
public net.minecraft.client.gui.components.ChatComponent allMessages
|
||||
public net.minecraft.client.gui.components.ChatComponent refreshTrimmedMessage()V
|
||||
|
||||
# ItemPocketRenderer/ItemPrintoutRenderer
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer m_109312_(F)F # calculateMapTilt
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer m_109361_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/HumanoidArm;)V # renderMapHand
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer m_109346_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IFFLnet/minecraft/world/entity/HumanoidArm;)V # renderPlayerArm
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer calculateMapTilt(F)F
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer renderMapHand(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer renderPlayerArm(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IFFLnet/minecraft/world/entity/HumanoidArm;)V
|
||||
|
||||
# SpeakerInstance/SpeakerManager
|
||||
public com.mojang.blaze3d.audio.Channel m_83652_(I)V # pumpBuffers
|
||||
public net.minecraft.client.sounds.SoundEngine f_120223_ # executor
|
||||
public com.mojang.blaze3d.audio.Channel pumpBuffers(I)V
|
||||
public net.minecraft.client.sounds.SoundEngine executor
|
||||
|
||||
# Data generators
|
||||
public net.minecraft.data.models.BlockModelGenerators f_124477_ # blockStateOutput
|
||||
public net.minecraft.data.models.BlockModelGenerators f_124478_ # modelOutput
|
||||
public net.minecraft.data.models.BlockModelGenerators m_124797_(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)V # delegateItemModel
|
||||
public net.minecraft.data.models.BlockModelGenerators m_124519_(Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;)V # delegateItemModel
|
||||
public net.minecraft.data.models.BlockModelGenerators m_124744_(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/data/models/model/TexturedModel$Provider;)V # createHorizontallyRotatedBlock
|
||||
public net.minecraft.data.models.ItemModelGenerators f_125080_ # output
|
||||
public net.minecraft.data.models.ItemModelGenerators m_125091_(Lnet/minecraft/world/item/Item;Ljava/lang/String;Lnet/minecraft/data/models/model/ModelTemplate;)V # generateFlatItem
|
||||
public net.minecraft.data.models.ItemModelGenerators m_125088_(Lnet/minecraft/world/item/Item;Lnet/minecraft/data/models/model/ModelTemplate;)V # generateFlatItem
|
||||
public net.minecraft.data.models.model.TextureSlot m_125898_(Ljava/lang/String;)Lnet/minecraft/data/models/model/TextureSlot; # create
|
||||
public net.minecraft.data.models.BlockModelGenerators blockStateOutput
|
||||
public net.minecraft.data.models.BlockModelGenerators modelOutput
|
||||
public net.minecraft.data.models.BlockModelGenerators delegateItemModel(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)V
|
||||
public net.minecraft.data.models.BlockModelGenerators delegateItemModel(Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;)V
|
||||
public net.minecraft.data.models.BlockModelGenerators createHorizontallyRotatedBlock(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/data/models/model/TexturedModel$Provider;)V
|
||||
public net.minecraft.data.models.ItemModelGenerators output
|
||||
public net.minecraft.data.models.ItemModelGenerators generateFlatItem(Lnet/minecraft/world/item/Item;Lnet/minecraft/data/models/model/ModelTemplate;)V
|
||||
public net.minecraft.data.models.ItemModelGenerators generateFlatItem(Lnet/minecraft/world/item/Item;Ljava/lang/String;Lnet/minecraft/data/models/model/ModelTemplate;)V
|
||||
public net.minecraft.data.models.model.TextureSlot create(Ljava/lang/String;)Lnet/minecraft/data/models/model/TextureSlot;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
modLoader="javafml"
|
||||
loaderVersion="[47,48)"
|
||||
loaderVersion="[1,)"
|
||||
|
||||
issueTrackerURL="https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||
logoFile="pack.png"
|
||||
@@ -24,8 +24,11 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
|
||||
'''
|
||||
|
||||
[[dependencies.computercraft]]
|
||||
modId="forge"
|
||||
mandatory=true
|
||||
versionRange="[${forgeVersion},48)"
|
||||
modId="neoforge"
|
||||
type="required"
|
||||
versionRange="[${neoVersion},20.5)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
|
||||
[[mixins]]
|
||||
config = "computercraft-client.forge.mixins.json"
|
||||
|
||||
@@ -7,7 +7,7 @@ package dan200.computercraft.shared.platform;
|
||||
import dan200.computercraft.test.shared.WithMinecraft;
|
||||
import dan200.computercraft.test.shared.platform.ContainerTransferContract;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.neoforged.neoforge.items.wrapper.InvWrapper;
|
||||
|
||||
@WithMinecraft
|
||||
public class ForgeContainerTransferTest implements ContainerTransferContract {
|
||||
|
||||
@@ -5,35 +5,34 @@
|
||||
package dan200.computercraft.gametest.core;
|
||||
|
||||
import dan200.computercraft.export.Exporter;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RegisterClientCommandsEvent;
|
||||
import net.minecraftforge.client.event.ScreenEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.RegisterGameTestsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.loading.FMLEnvironment;
|
||||
import net.neoforged.neoforge.client.event.RegisterClientCommandsEvent;
|
||||
import net.neoforged.neoforge.client.event.ScreenEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||
import net.neoforged.neoforge.event.RegisterGameTestsEvent;
|
||||
import net.neoforged.neoforge.event.TickEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||
|
||||
@Mod("cctest")
|
||||
public class TestMod {
|
||||
public TestMod() {
|
||||
public TestMod(IEventBus modBus) {
|
||||
TestHooks.init();
|
||||
|
||||
var bus = MinecraftForge.EVENT_BUS;
|
||||
var bus = NeoForge.EVENT_BUS;
|
||||
bus.addListener(EventPriority.LOW, (ServerStartedEvent e) -> TestHooks.onServerStarted(e.getServer()));
|
||||
bus.addListener((RegisterCommandsEvent e) -> CCTestCommand.register(e.getDispatcher()));
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> TestMod::onInitializeClient);
|
||||
if (FMLEnvironment.dist == Dist.CLIENT) TestMod.onInitializeClient();
|
||||
|
||||
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
modBus.addListener((RegisterGameTestsEvent event) -> TestHooks.loadTests(event::register));
|
||||
}
|
||||
|
||||
private static void onInitializeClient() {
|
||||
var bus = MinecraftForge.EVENT_BUS;
|
||||
var bus = NeoForge.EVENT_BUS;
|
||||
|
||||
bus.addListener((TickEvent.ServerTickEvent e) -> {
|
||||
if (e.phase == TickEvent.Phase.START) ClientTestHooks.onServerTick(e.getServer());
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
modLoader="javafml"
|
||||
loaderVersion="[30,)"
|
||||
loaderVersion="[1,)"
|
||||
|
||||
issueTrackerURL="https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||
displayURL="https://github.com/cc-tweaked/CC-Tweaked"
|
||||
@@ -22,7 +22,10 @@ A test framework for ensuring CC: Tweaked works correctly.
|
||||
|
||||
[[dependencies.cctest]]
|
||||
modId="computercraft"
|
||||
mandatory=true
|
||||
type="required"
|
||||
versionRange="[1.0,)"
|
||||
ordering="AFTER"
|
||||
side="BOTH"
|
||||
|
||||
[[mixins]]
|
||||
config="computercraft-gametest.mixins.json"
|
||||
|
||||
Reference in New Issue
Block a user