[0.2.0] add pick item callback (#82)

This commit is contained in:
Adrian Siekierka 2019-02-10 02:44:07 +01:00 committed by GitHub
parent 403d0c5a96
commit b5b9f82997
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 200 additions and 0 deletions

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
public interface ContextSensitivePickable {
ItemStack getPickStack(BlockState state, BlockView view, BlockPos pos, /* nullable */ PlayerEntity player, /* nullable */ HitResult result);
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.hit.HitResult;
public interface ContextSensitivePickable {
ItemStack getPickStack(/* nullable */ PlayerEntity player, /* nullable */ HitResult result);
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.event.client.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.hit.HitResult;
/**
* This interaction event is called on the CLIENT SIDE ONLY when the player
* attempts to pick up an item.
*
* Use {@link Container} to change the picked stack. Return true if you
* wish for execution to continue, return false to cancel the item picking
* operation (for example, if you want to route to the server side, etc.)
*/
public interface ClientPickItemCallback {
public static final class Container {
private ItemStack stack;
public Container(ItemStack stack) {
this.stack = stack;
}
public ItemStack getStack() {
return stack;
}
public void setStack(ItemStack stack) {
this.stack = stack;
}
}
public static final Event<ClientPickItemCallback> EVENT = EventFactory.arrayBacked(ClientPickItemCallback.class,
(listeners) -> (player, result, container) -> {
for (ClientPickItemCallback event : listeners) {
if (!event.pick(player, result, container)) {
return false;
}
}
return true;
}
);
boolean pick(PlayerEntity player, HitResult result, Container container);
}

View file

@ -17,10 +17,18 @@
package net.fabricmc.fabric.impl; package net.fabricmc.fabric.impl;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.block.ContextSensitivePickable;
import net.fabricmc.fabric.api.event.client.player.ClientPickItemCallback;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.fabricmc.fabric.impl.client.gui.ScreenProviderRegistryImpl; import net.fabricmc.fabric.impl.client.gui.ScreenProviderRegistryImpl;
import net.fabricmc.fabric.impl.registry.RegistrySyncManager; import net.fabricmc.fabric.impl.registry.RegistrySyncManager;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
public class FabricAPIClientInitializer implements ClientModInitializer { public class FabricAPIClientInitializer implements ClientModInitializer {
@Override @Override
@ -30,6 +38,26 @@ public class FabricAPIClientInitializer implements ClientModInitializer {
RegistrySyncManager.receivePacket(ctx, buf, !MinecraftClient.getInstance().isInSingleplayer()); RegistrySyncManager.receivePacket(ctx, buf, !MinecraftClient.getInstance().isInSingleplayer());
}); });
ClientPickItemCallback.EVENT.register(((player, result, container) -> {
if (result instanceof BlockHitResult) {
BlockView view = player.getEntityWorld();
BlockPos pos = ((BlockHitResult) result).getBlockPos();
BlockState state = view.getBlockState(pos);
if (state.getBlock() instanceof ContextSensitivePickable) {
container.setStack(((ContextSensitivePickable) state.getBlock()).getPickStack(state, view, pos, player, result));
}
} else if (result instanceof EntityHitResult) {
Entity entity = ((EntityHitResult) result).getEntity();
if (entity instanceof net.fabricmc.fabric.api.entity.ContextSensitivePickable) {
container.setStack(((net.fabricmc.fabric.api.entity.ContextSensitivePickable) entity).getPickStack(player, result));
}
}
return true;
}));
((ScreenProviderRegistryImpl) ScreenProviderRegistryImpl.INSTANCE).init(); ((ScreenProviderRegistryImpl) ScreenProviderRegistryImpl.INSTANCE).init();
} }
} }

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.events.playerinteraction;
import net.fabricmc.fabric.api.event.client.player.ClientPickItemCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public class MixinMinecraftClient {
private boolean fabric_itemPickCancelled;
@ModifyVariable(at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isEmpty()Z", ordinal = 2), method = "doItemPick", ordinal = 0)
public ItemStack modifyItemPick(ItemStack stack) {
ClientPickItemCallback.Container ctr = new ClientPickItemCallback.Container(stack);
//noinspection ConstantConditions
MinecraftClient client = (MinecraftClient) (Object) this;
boolean toContinue = ClientPickItemCallback.EVENT.invoker().pick(client.player, client.hitResult, ctr);
if (!toContinue) {
fabric_itemPickCancelled = true;
return ItemStack.EMPTY;
} else {
fabric_itemPickCancelled = false;
return ctr.getStack();
}
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isEmpty()Z", ordinal = 2), method = "doItemPick", cancellable = true)
public void cancelItemPick(CallbackInfo info) {
if (fabric_itemPickCancelled) {
fabric_itemPickCancelled = false;
info.cancel();
}
}
}

View file

@ -16,6 +16,7 @@
"client.render.MixinItemColorMap", "client.render.MixinItemColorMap",
"client.texture.MixinSpriteAtlasTexture", "client.texture.MixinSpriteAtlasTexture",
"events.playerinteraction.MixinClientPlayerInteractionManager", "events.playerinteraction.MixinClientPlayerInteractionManager",
"events.playerinteraction.MixinMinecraftClient",
"events.tick.MixinMinecraftClient", "events.tick.MixinMinecraftClient",
"networking.MixinClientPlayNetworkHandler", "networking.MixinClientPlayNetworkHandler",
"registry.client.MixinBlockColorMap", "registry.client.MixinBlockColorMap",