1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-14 20:20:30 +00:00

Move many Forge-specific methods behind PlatformHelper

There's still a lot of work to be done on turtles (TurtlePlayer, all the
turtle tool stuff), but we're a good way along now.
This commit is contained in:
Jonathan Coates 2022-11-09 14:41:46 +00:00
parent 22729f6f16
commit cc73fcd85d
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
15 changed files with 175 additions and 53 deletions

View File

@ -12,6 +12,8 @@ import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser; import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.api.turtle.event.TurtleRefuelEvent;
import dan200.computercraft.impl.TurtleRefuelHandlers;
import dan200.computercraft.shared.Config; import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.peripheral.generic.data.FluidData; import dan200.computercraft.shared.peripheral.generic.data.FluidData;
@ -20,6 +22,7 @@ import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods;
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.platform.NetworkHandler; import dan200.computercraft.shared.platform.NetworkHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -31,6 +34,8 @@ import net.minecraftforge.registries.RegistryBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.OptionalInt;
@Mod(ComputerCraft.MOD_ID) @Mod(ComputerCraft.MOD_ID)
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) @Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public final class ComputerCraft { public final class ComputerCraft {
@ -77,8 +82,18 @@ public final class ComputerCraft {
public ComputerCraft() { public ComputerCraft() {
Config.setup(); Config.setup();
ModRegistry.register(); ModRegistry.register();
}
// Register a fallback handler for the turtle refuel event.
TurtleRefuelHandlers.register((turtle, stack, slot, limit) -> {
@SuppressWarnings("removal") var event = new TurtleRefuelEvent(turtle, stack);
MinecraftForge.EVENT_BUS.post(event);
if (event.getHandler() == null) return OptionalInt.empty();
if (limit == 0) return OptionalInt.of(0);
return OptionalInt.of(event.getHandler().refuel(turtle, stack, slot, limit));
});
NetworkHandler.setup();
}
@SubscribeEvent @SubscribeEvent
public static void registerRegistries(NewRegistryEvent event) { public static void registerRegistries(NewRegistryEvent event) {
@ -99,8 +114,6 @@ public final class ComputerCraft {
@SubscribeEvent @SubscribeEvent
public static void init(FMLCommonSetupEvent event) { public static void init(FMLCommonSetupEvent event) {
NetworkHandler.setup();
event.enqueueWork(ModRegistry::registerMainThread); event.enqueueWork(ModRegistry::registerMainThread);
ComputerCraftAPI.registerGenericSource(new InventoryMethods()); ComputerCraftAPI.registerGenericSource(new InventoryMethods());

View File

@ -7,9 +7,7 @@ package dan200.computercraft.impl;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleRefuelHandler; import dan200.computercraft.api.turtle.TurtleRefuelHandler;
import dan200.computercraft.api.turtle.event.TurtleRefuelEvent;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -22,17 +20,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
public final class TurtleRefuelHandlers { public final class TurtleRefuelHandlers {
private static final List<TurtleRefuelHandler> handlers = new CopyOnWriteArrayList<>(); private static final List<TurtleRefuelHandler> handlers = new CopyOnWriteArrayList<>();
static {
// Register a fallback handler for our event.
handlers.add((turtle, stack, slot, limit) -> {
@SuppressWarnings("removal") var event = new TurtleRefuelEvent(turtle, stack);
MinecraftForge.EVENT_BUS.post(event);
if (event.getHandler() == null) return OptionalInt.empty();
if (limit == 0) return OptionalInt.of(0);
return OptionalInt.of(event.getHandler().refuel(turtle, stack, slot, limit));
});
}
private TurtleRefuelHandlers() { private TurtleRefuelHandlers() {
} }

View File

@ -8,10 +8,10 @@ package dan200.computercraft.shared.command;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder; import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.util.FakePlayer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
@ -24,9 +24,7 @@ public final class CommandUtils {
public static boolean isPlayer(CommandSourceStack output) { public static boolean isPlayer(CommandSourceStack output) {
var sender = output.getEntity(); var sender = output.getEntity();
return sender instanceof ServerPlayer return sender instanceof ServerPlayer player && !PlatformHelper.get().isFakePlayer(player);
&& !(sender instanceof FakePlayer)
&& ((ServerPlayer) sender).connection != null;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -19,10 +19,10 @@ import dan200.computercraft.core.lua.ILuaMachine;
import dan200.computercraft.shared.CommonHooks; import dan200.computercraft.shared.CommonHooks;
import dan200.computercraft.shared.computer.metrics.GlobalMetrics; import dan200.computercraft.shared.computer.metrics.GlobalMetrics;
import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.SharedConstants;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelResource;
import net.minecraftforge.versions.mcp.MCPVersion;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -192,7 +192,8 @@ public final class ServerContext {
@Nonnull @Nonnull
@Override @Override
public String getHostString() { public String getHostString() {
return String.format("ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), MCPVersion.getMCVersion()); var version = SharedConstants.getCurrentVersion().getName();
return String.format("ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), version);
} }
@Nonnull @Nonnull

View File

@ -6,6 +6,7 @@
package dan200.computercraft.shared.peripheral.generic.data; package dan200.computercraft.shared.peripheral.generic.data;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.Registries;
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
@ -99,7 +100,7 @@ public class ItemData {
private static List<Map<String, Object>> getItemGroups(@Nonnull ItemStack stack) { private static List<Map<String, Object>> getItemGroups(@Nonnull ItemStack stack) {
List<Map<String, Object>> groups = new ArrayList<>(1); List<Map<String, Object>> groups = new ArrayList<>(1);
for (var group : stack.getItem().getCreativeTabs()) { for (var group : PlatformHelper.get().getCreativeTabs(stack)) {
if (group == null) continue; if (group == null) continue;
Map<String, Object> groupData = new HashMap<>(2); Map<String, Object> groupData = new HashMap<>(2);

View File

@ -6,9 +6,11 @@
package dan200.computercraft.shared.peripheral.monitor; package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.RegistryEntry; import dan200.computercraft.shared.platform.RegistryEntry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
@ -22,7 +24,6 @@ import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -90,7 +91,7 @@ public class BlockMonitor extends BlockGeneric {
var entity = world.getBlockEntity(pos); var entity = world.getBlockEntity(pos);
if (entity instanceof TileMonitor monitor && !world.isClientSide) { if (entity instanceof TileMonitor monitor && !world.isClientSide) {
// Defer the block update if we're being placed by another TE. See #691 // Defer the block update if we're being placed by another TE. See #691
if (livingEntity == null || livingEntity instanceof FakePlayer) { if (livingEntity == null || (livingEntity instanceof ServerPlayer player && PlatformHelper.get().isFakePlayer(player))) {
monitor.updateNeighborsDeferred(); monitor.updateNeighborsDeferred();
return; return;
} }

View File

@ -26,9 +26,13 @@ import net.minecraft.world.MenuProvider;
import net.minecraft.world.WorldlyContainer; import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -235,4 +239,81 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper
* @return A list of tags. * @return A list of tags.
*/ */
List<TagKey<Item>> getDyeTags(); List<TagKey<Item>> getDyeTags();
/**
* Get the amount of fuel an item provides.
*
* @param stack The item to burn.
* @return The amount of fuel it provides.
*/
int getBurnTime(ItemStack stack);
/**
* Get the creative tabs this stack belongs to.
*
* @param stack The current item.
* @return The creative tabs the item belongs to.
*/
Collection<CreativeModeTab> getCreativeTabs(ItemStack stack);
/**
* Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return
* an empty bucket.
*
* @param stack The original item.
* @return The "remainder" item. May be {@link ItemStack#EMPTY}.
*/
ItemStack getCraftingRemainingItem(ItemStack stack);
/**
* A more general version of {@link #getCraftingRemainingItem(ItemStack)} which gets all remaining items for a
* recipe.
*
* @param player The player performing the crafting.
* @param recipe The recipe currently doing the crafting.
* @param container The crafting container.
* @return A list of items to return to the player after crafting.
*/
List<ItemStack> getRecipeRemainingItems(ServerPlayer player, Recipe<CraftingContainer> recipe, CraftingContainer container);
/**
* Fire an event after crafting has occurred.
*
* @param player The player performing the crafting.
* @param container The current crafting container.
* @param stack The resulting stack from crafting.
*/
void onItemCrafted(ServerPlayer player, CraftingContainer container, ItemStack stack);
/**
* Check whether we should notify neighbours in a particular direction.
*
* @param level The current level.
* @param pos The position of the current block.
* @param block The block which is performing the notification, should be equal to {@code level.getBlockState(pos)}.
* @param direction The direction we're notifying in.
* @return {@code true} if neighbours should be notified or {@code false} otherwise.
*/
boolean onNotifyNeighbour(Level level, BlockPos pos, BlockState block, Direction direction);
/**
* Determine if a player is not a real player.
*
* @param player The player to check.
* @return Whether this player is fake.
*/
default boolean isFakePlayer(ServerPlayer player) {
// Any subclass of ServerPlayer (i.e. Forge's FakePlayer) is assumed to be a fake.
return player.connection == null || player.getClass() != ServerPlayer.class;
}
/**
* Get the distance a player can reach.
*
* @param player The player who is reaching.
* @return The distance (in blocks) that a player can reach.
*/
default double getReachDistance(Player player) {
return player.isCreative() ? 5 : 4.5;
}
} }

View File

@ -32,10 +32,13 @@ import net.minecraft.world.MenuProvider;
import net.minecraft.world.WorldlyContainerHolder; import net.minecraft.world.WorldlyContainerHolder;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -43,11 +46,13 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.Tags; import net.minecraftforge.common.Tags;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.extensions.IForgeMenuType; import net.minecraftforge.common.extensions.IForgeMenuType;
import net.minecraftforge.common.util.NonNullConsumer; import net.minecraftforge.common.util.NonNullConsumer;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.InvWrapper;
@ -59,10 +64,7 @@ import net.minecraftforge.registries.RegistryManager;
import net.minecraftforge.registries.RegistryObject; import net.minecraftforge.registries.RegistryObject;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -236,6 +238,44 @@ public class PlatformHelperImpl implements PlatformHelper {
); );
} }
@Override
public int getBurnTime(ItemStack stack) {
return ForgeHooks.getBurnTime(stack, null);
}
@Override
public Collection<CreativeModeTab> getCreativeTabs(ItemStack stack) {
return stack.getItem().getCreativeTabs();
}
@Override
public ItemStack getCraftingRemainingItem(ItemStack stack) {
return stack.getCraftingRemainingItem();
}
@Override
public List<ItemStack> getRecipeRemainingItems(ServerPlayer player, Recipe<CraftingContainer> recipe, CraftingContainer container) {
ForgeHooks.setCraftingPlayer(player);
var result = recipe.getRemainingItems(container);
ForgeHooks.setCraftingPlayer(null);
return result;
}
@Override
public void onItemCrafted(ServerPlayer player, CraftingContainer container, ItemStack stack) {
ForgeEventFactory.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();
}
@Override
public double getReachDistance(Player player) {
return player.getReachDistance();
}
private record RegistryWrapperImpl<T>( private record RegistryWrapperImpl<T>(
ResourceLocation name, ForgeRegistry<T> registry ResourceLocation name, ForgeRegistry<T> registry
) implements Registries.RegistryWrapper<T> { ) implements Registries.RegistryWrapper<T> {

View File

@ -7,8 +7,8 @@ package dan200.computercraft.shared.turtle;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleRefuelHandler; import dan200.computercraft.api.turtle.TurtleRefuelHandler;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.ForgeHooks;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.OptionalInt; import java.util.OptionalInt;
@ -27,7 +27,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelHandler {
var stack = turtle.getInventory().removeItem(slot, limit); var stack = turtle.getInventory().removeItem(slot, limit);
var fuelToGive = fuelPerItem * stack.getCount(); var fuelToGive = fuelPerItem * stack.getCount();
// Store the replacement item in the inventory // Store the replacement item in the inventory
var replacementStack = ForgeHooks.getCraftingRemainingItem(stack); var replacementStack = PlatformHelper.get().getCraftingRemainingItem(stack);
if (!replacementStack.isEmpty()) TurtleUtil.storeItemOrDrop(turtle, replacementStack); if (!replacementStack.isEmpty()) TurtleUtil.storeItemOrDrop(turtle, replacementStack);
turtle.getInventory().setChanged(); turtle.getInventory().setChanged();
@ -36,6 +36,6 @@ public final class FurnaceRefuelHandler implements TurtleRefuelHandler {
} }
private static int getFuelPerItem(@Nonnull ItemStack stack) { private static int getFuelPerItem(@Nonnull ItemStack stack) {
return (ForgeHooks.getBurnTime(stack, null) * 5) / 100; return (PlatformHelper.get().getBurnTime(stack) * 5) / 100;
} }
} }

View File

@ -6,6 +6,7 @@
package dan200.computercraft.shared.turtle.upgrades; package dan200.computercraft.shared.turtle.upgrades;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -15,8 +16,6 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.ForgeEventFactory;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -81,12 +80,9 @@ public class TurtleInventoryCrafting extends CraftingContainer {
results.add(result); results.add(result);
result.onCraftedBy(world, player, result.getCount()); result.onCraftedBy(world, player, result.getCount());
ForgeEventFactory.firePlayerCraftingEvent(player, result, this); PlatformHelper.get().onItemCrafted(player, this, result);
ForgeHooks.setCraftingPlayer(player);
var remainders = recipe.getRemainingItems(this);
ForgeHooks.setCraftingPlayer(null);
var remainders = PlatformHelper.get().getRecipeRemainingItems(player, recipe, this);
for (var slot = 0; slot < remainders.size(); slot++) { for (var slot = 0; slot < remainders.size(); slot++) {
var existing = getItem(slot); var existing = getItem(slot);
var remainder = remainders.get(slot); var remainder = remainders.get(slot);

View File

@ -17,7 +17,6 @@ import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraftforge.common.crafting.CraftingHelper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -58,7 +57,7 @@ public final class ImpostorRecipe extends ShapedRecipe {
public ImpostorRecipe fromJson(@Nonnull ResourceLocation identifier, @Nonnull JsonObject json) { public ImpostorRecipe fromJson(@Nonnull ResourceLocation identifier, @Nonnull JsonObject json) {
var group = GsonHelper.getAsString(json, "group", ""); var group = GsonHelper.getAsString(json, "group", "");
var recipe = RecipeSerializer.SHAPED_RECIPE.fromJson(identifier, json); var recipe = RecipeSerializer.SHAPED_RECIPE.fromJson(identifier, json);
var result = CraftingHelper.getItemStack(GsonHelper.getAsJsonObject(json, "result"), true); var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
return new ImpostorRecipe(identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result); return new ImpostorRecipe(identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result);
} }
@ -68,7 +67,7 @@ public final class ImpostorRecipe extends ShapedRecipe {
var height = buf.readVarInt(); var height = buf.readVarInt();
var group = buf.readUtf(Short.MAX_VALUE); var group = buf.readUtf(Short.MAX_VALUE);
var items = NonNullList.withSize(width * height, Ingredient.EMPTY); var items = NonNullList.withSize(width * height, Ingredient.EMPTY);
for (var k = 0; k < items.size(); ++k) items.set(k, Ingredient.fromNetwork(buf)); for (var k = 0; k < items.size(); k++) items.set(k, Ingredient.fromNetwork(buf));
var result = buf.readItem(); var result = buf.readItem();
return new ImpostorRecipe(identifier, group, width, height, items, result); return new ImpostorRecipe(identifier, group, width, height, items, result);
} }

View File

@ -17,9 +17,9 @@ import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraftforge.common.crafting.CraftingHelper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -66,8 +66,8 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe {
throw new JsonParseException("Too many ingredients for shapeless recipe the max is 9"); throw new JsonParseException("Too many ingredients for shapeless recipe the max is 9");
} }
var itemstack = CraftingHelper.getItemStack(GsonHelper.getAsJsonObject(json, "result"), true); var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
return new ImpostorShapelessRecipe(id, s, itemstack, ingredients); return new ImpostorShapelessRecipe(id, s, result, ingredients);
} }
private NonNullList<Ingredient> readIngredients(JsonArray arrays) { private NonNullList<Ingredient> readIngredients(JsonArray arrays) {

View File

@ -5,6 +5,7 @@
*/ */
package dan200.computercraft.shared.util; package dan200.computercraft.shared.util;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -12,9 +13,6 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DiodeBlock; import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.RedStoneWireBlock; import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.event.ForgeEventFactory;
import java.util.EnumSet;
public final class RedstoneUtil { public final class RedstoneUtil {
private RedstoneUtil() { private RedstoneUtil() {
@ -39,10 +37,17 @@ public final class RedstoneUtil {
: power; : power;
} }
/**
* Propagate a redstone output to a particular side.
*
* @param world The current level.
* @param pos The current block's position.
* @param side The direction we're propagating to.
* @see DiodeBlock#updateNeighborsInFront(Level, BlockPos, BlockState)
*/
public static void propagateRedstoneOutput(Level world, BlockPos pos, Direction side) { public static void propagateRedstoneOutput(Level world, BlockPos pos, Direction side) {
// Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors
var block = world.getBlockState(pos); var block = world.getBlockState(pos);
if (ForgeEventFactory.onNeighborNotify(world, pos, block, EnumSet.of(side), false).isCanceled()) return; if (!PlatformHelper.get().onNotifyNeighbour(world, pos, block, side)) return;
var neighbourPos = pos.relative(side); var neighbourPos = pos.relative(side);
world.neighborChanged(neighbourPos, block.getBlock(), pos); world.neighborChanged(neighbourPos, block.getBlock(), pos);

View File

@ -5,6 +5,7 @@
*/ */
package dan200.computercraft.shared.util; package dan200.computercraft.shared.util;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -23,7 +24,6 @@ import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.common.ForgeMod;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -113,7 +113,7 @@ public final class WorldUtil {
} }
public static Vec3 getRayEnd(Player player) { public static Vec3 getRayEnd(Player player) {
var reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue(); var reach = PlatformHelper.get().getReachDistance(player);
var look = player.getLookAngle(); var look = player.getLookAngle();
return getRayStart(player).add(look.x * reach, look.y * reach, look.z * reach); return getRayStart(player).add(look.x * reach, look.y * reach, look.z * reach);
} }

View File

@ -409,7 +409,7 @@ class Turtle_Test {
turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward") turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward")
turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward") turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward")
} }
thenIdle(1) thenIdle(2) // Should happen immediately, but computers might be slow.
thenExecute { thenExecute {
assertEquals( assertEquals(
listOf( listOf(