Merge 0.2.0-style Event API

This commit is contained in:
Adrian Siekierka 2019-02-06 21:50:51 +01:00
parent fe18b98757
commit 16d32490f6
39 changed files with 833 additions and 559 deletions

View file

@ -14,8 +14,14 @@
* limitations under the License.
*/
package net.fabricmc.fabric.util;
package net.fabricmc.fabric.api.event;
public interface HandlerRegistry<T> {
void register(T handler);
public abstract class Event<T> {
protected T invoker;
public final T invoker() {
return invoker;
}
public abstract void register(T listener);
}

View file

@ -0,0 +1,46 @@
/*
* 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;
import net.fabricmc.fabric.impl.event.EventFactoryImpl;
import net.fabricmc.loader.launch.common.FabricLauncherBase;
import java.util.function.Function;
public final class EventFactory {
private static boolean profilingEnabled = true;
private EventFactory() {
}
public static boolean isProfilingEnabled() {
return profilingEnabled;
}
public static void invalidate() {
EventFactoryImpl.invalidate();
}
public static <T> Event<T> arrayBacked(Class<T> type, Function<T[], T> joiner) {
return EventFactoryImpl.arrayBacked(type, joiner);
}
public static <T> Event<T> arrayBacked(Class<T> type, T emptyInvoker, Function<T[], T> joiner) {
return EventFactoryImpl.arrayBacked(type, emptyInvoker, joiner);
}
}

View file

@ -0,0 +1,49 @@
/*
* 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;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.ActionResult;
public interface ClientTickCallback {
public static final Event<ClientTickCallback> EVENT = EventFactory.arrayBacked(ClientTickCallback.class,
(listeners) -> {
if (EventFactory.isProfilingEnabled()) {
return (client) -> {
client.getProfiler().push("fabricClientTick");
for (ClientTickCallback event : listeners) {
client.getProfiler().push(event.getClass().getName());
event.tick(client);
client.getProfiler().pop();
}
client.getProfiler().pop();
};
} else {
return (client) -> {
for (ClientTickCallback event : listeners) {
event.tick(client);
}
};
}
}
);
void tick(MinecraftClient client);
}

View file

@ -0,0 +1,75 @@
/*
* 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;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.util.Identifier;
import java.util.Map;
import java.util.function.Consumer;
public interface SpriteRegistrationCallback {
public static final Event<SpriteRegistrationCallback> EVENT = EventFactory.arrayBacked(SpriteRegistrationCallback.class,
(listeners) -> (atlasTexture, registry) -> {
for (SpriteRegistrationCallback callback : listeners) {
callback.registerSprites(atlasTexture, registry);
}
}
);
void registerSprites(SpriteAtlasTexture atlasTexture, Registry registry);
static void registerBlockAtlas(SpriteRegistrationCallback callback) {
EVENT.register((atlasTexture, registry) -> {
if (atlasTexture == MinecraftClient.getInstance().getSpriteAtlas()) {
callback.registerSprites(atlasTexture, registry);
}
});
}
public static class Registry {
private final Map<Identifier, Sprite> spriteMap;
private final Consumer<Identifier> defaultSpriteRegister;
public Registry(Map<Identifier, Sprite> spriteMap, Consumer<Identifier> defaultSpriteRegister) {
this.spriteMap = spriteMap;
this.defaultSpriteRegister = defaultSpriteRegister;
}
/**
* Register a sprite to be loaded using the default implementation.
*
* @param id The sprite identifier.
*/
public void register(Identifier id) {
this.defaultSpriteRegister.accept(id);
}
/**
* Register a custom sprite to be added and loaded.
*
* @param sprite The sprite to be added.
*/
public void register(Sprite sprite) {
this.spriteMap.put(sprite.getId(), sprite);
}
}
}

View file

@ -0,0 +1,43 @@
/*
* 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.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
public interface AttackBlockCallback {
public static final Event<AttackBlockCallback> EVENT = EventFactory.arrayBacked(AttackBlockCallback.class,
(listeners) -> (player, world, hand, pos, direction) -> {
for (AttackBlockCallback event : listeners) {
ActionResult result = event.interact(player, world, hand, pos, direction);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
}
);
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction);
}

View file

@ -0,0 +1,43 @@
/*
* 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.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.world.World;
public interface AttackEntityCallback {
public static final Event<AttackEntityCallback> EVENT = EventFactory.arrayBacked(AttackEntityCallback.class,
(listeners) -> (player, world, hand, entity, hitResult) -> {
for (AttackEntityCallback event : listeners) {
ActionResult result = event.interact(player, world, hand, entity, hitResult);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
}
);
ActionResult interact(PlayerEntity player, World world, Hand hand, Entity entity, /* Nullable */ EntityHitResult hitResult);
}

View file

@ -0,0 +1,44 @@
/*
* 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.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
public interface UseBlockCallback {
public static final Event<UseBlockCallback> EVENT = EventFactory.arrayBacked(UseBlockCallback.class,
(listeners) -> (player, world, hand, hitResult) -> {
for (UseBlockCallback event : listeners) {
ActionResult result = event.interact(player, world, hand, hitResult);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
}
);
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult);
}

View file

@ -0,0 +1,43 @@
/*
* 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.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.world.World;
public interface UseEntityCallback {
public static final Event<UseEntityCallback> EVENT = EventFactory.arrayBacked(UseEntityCallback.class,
(listeners) -> (player, world, hand, entity, hitResult) -> {
for (UseEntityCallback event : listeners) {
ActionResult result = event.interact(player, world, hand, entity, hitResult);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
}
);
ActionResult interact(PlayerEntity player, World world, Hand hand, Entity entity, /* Nullable */ EntityHitResult hitResult);
}

View file

@ -0,0 +1,41 @@
/*
* 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.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
public interface UseItemCallback {
public static final Event<UseItemCallback> EVENT = EventFactory.arrayBacked(UseItemCallback.class,
(listeners) -> (player, world, hand) -> {
for (UseItemCallback event : listeners) {
ActionResult result = event.interact(player, world, hand);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
}
);
ActionResult interact(PlayerEntity player, World world, Hand hand);
}

View file

@ -14,24 +14,20 @@
* limitations under the License.
*/
package net.fabricmc.fabric.events.client;
package net.fabricmc.fabric.api.event.registry;
import net.fabricmc.fabric.events.TickEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.minecraft.client.MinecraftClient;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.block.Block;
import java.util.function.Consumer;
public interface BlockBuildingCallback {
public static Event<BlockBuildingCallback> EVENT = EventFactory.arrayBacked(BlockBuildingCallback.class,
(listeners) -> (settings, builtBlock) -> {
for (BlockBuildingCallback callback : listeners) {
callback.building(settings, builtBlock);
}
}
);
/**
* Events emitted during the ticking process for Minecraft client objects.
*
* @see TickEvent
*/
public final class ClientTickEvent {
public static final HandlerRegistry<Consumer<MinecraftClient>> CLIENT = new HandlerArray<>(Consumer.class);
private ClientTickEvent() {
}
void building(Block.Settings settings, Block builtBlock);
}

View file

@ -0,0 +1,33 @@
/*
* 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.registry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.item.Item;
public interface ItemBuildingCallback {
public static Event<ItemBuildingCallback> EVENT = EventFactory.arrayBacked(ItemBuildingCallback.class,
(listeners) -> (settings, builtItem) -> {
for (ItemBuildingCallback callback : listeners) {
callback.building(settings, builtItem);
}
}
);
void building(Item.Settings settings, Item builtItem);
}

View file

@ -14,17 +14,20 @@
* limitations under the License.
*/
package net.fabricmc.fabric.events.client;
package net.fabricmc.fabric.api.event.server;
import net.fabricmc.fabric.client.texture.SpriteRegistry;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.MinecraftServer;
public class SpriteEvent {
@FunctionalInterface
public interface Provider {
void registerSprites(SpriteRegistry registry);
}
public interface ServerStartCallback {
public static final Event<ServerStartCallback> EVENT = EventFactory.arrayBacked(ServerStartCallback.class,
(listeners) -> (server) -> {
for (ServerStartCallback event : listeners) {
event.onStartServer(server);
}
}
);
public static final HandlerRegistry<Provider> PROVIDE = new HandlerArray<>(Provider.class);
void onStartServer(MinecraftServer server);
}

View file

@ -14,19 +14,20 @@
* limitations under the License.
*/
package net.fabricmc.fabric.events;
package net.fabricmc.fabric.api.event.server;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.MinecraftServer;
import java.util.function.Consumer;
public interface ServerStopCallback {
public static final Event<ServerStopCallback> EVENT = EventFactory.arrayBacked(ServerStopCallback.class,
(listeners) -> (server) -> {
for (ServerStopCallback event : listeners) {
event.onStopServer(server);
}
}
);
public final class ServerEvent {
public static final HandlerRegistry<Consumer<MinecraftServer>> START = new HandlerArray<>(Consumer.class);
public static final HandlerRegistry<Consumer<MinecraftServer>> STOP = new HandlerArray<>(Consumer.class);
private ServerEvent() {
}
void onStopServer(MinecraftServer server);
}

View file

@ -0,0 +1,47 @@
/*
* 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.server;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.MinecraftServer;
public interface ServerTickCallback {
public static final Event<ServerTickCallback> EVENT = EventFactory.arrayBacked(ServerTickCallback.class,
(listeners) -> {
if (EventFactory.isProfilingEnabled()) {
return (server) -> {
server.getProfiler().push("fabricServerTick");
for (ServerTickCallback event : listeners) {
server.getProfiler().push(event.getClass().getName());
event.tick(server);
server.getProfiler().pop();
}
server.getProfiler().pop();
};
} else {
return (server) -> {
for (ServerTickCallback event : listeners) {
event.tick(server);
}
};
}
}
);
void tick(MinecraftServer server);
}

View file

@ -0,0 +1,47 @@
/*
* 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.world;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.world.World;
public interface WorldTickCallback {
public static final Event<WorldTickCallback> EVENT = EventFactory.arrayBacked(WorldTickCallback.class,
(listeners) -> {
if (EventFactory.isProfilingEnabled()) {
return (world) -> {
world.getProfiler().push("fabricWorldTick");
for (WorldTickCallback event : listeners) {
world.getProfiler().push(event.getClass().getName());
event.tick(world);
world.getProfiler().pop();
}
world.getProfiler().pop();
};
} else {
return (world) -> {
for (WorldTickCallback event : listeners) {
event.tick(world);
}
};
}
}
);
void tick(World world);
}

View file

@ -28,7 +28,7 @@ import net.minecraft.world.World;
*/
public interface BreakInteractable {
/**
* @return True if the block accepted the interaction and it should no longer be processed.
* @return True if the block accepted the player and it should no longer be processed.
*/
boolean onBreakInteract(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, Direction direction);
}

View file

@ -1,54 +0,0 @@
/*
* 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.client.texture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.Identifier;
import java.util.Map;
import java.util.function.Consumer;
/**
* Helper class for registering Sprites during loading.
*/
public class SpriteRegistry {
private final Map<Identifier, Sprite> spriteMap;
private final Consumer<Identifier> defaultSpriteRegister;
public SpriteRegistry(Map<Identifier, Sprite> spriteMap, Consumer<Identifier> defaultSpriteRegister) {
this.spriteMap = spriteMap;
this.defaultSpriteRegister = defaultSpriteRegister;
}
/**
* Register a sprite to be loaded using the default implementation.
*
* @param id The sprite identifier.
*/
public void register(Identifier id) {
this.defaultSpriteRegister.accept(id);
}
/**
* Register a custom sprite to be added and loaded.
*
* @param sprite The sprite to be added.
*/
public void register(Sprite sprite) {
this.spriteMap.put(sprite.getId(), sprite);
}
}

View file

@ -1,38 +0,0 @@
/*
* 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.events;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import java.util.function.BiConsumer;
/**
* This is a class for events emitted when a Block.Settings/Item.Settings is
* turned into a Block or Item. You can use these to extend these builders with
* your own methods and transparently add the resulting information to a Map.
*/
public final class ObjectBuilderEvent {
public static final HandlerRegistry<BiConsumer<Block.Settings, Block>> BLOCK = new HandlerArray<>(BiConsumer.class);
public static final HandlerRegistry<BiConsumer<Item.Settings, Item>> ITEM = new HandlerArray<>(BiConsumer.class);
private ObjectBuilderEvent() {
}
}

View file

@ -16,19 +16,9 @@
package net.fabricmc.fabric.events;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
/**
* This is a class for INTERACTION EVENTS (think left-clicking/right-clicking). For block placement/break
* events, look elsewhere - this just handles the interaction!
* events, look elsewhere - this just handles the player!
*
* These hook in BEFORE the spectator checks, so make sure to check for the player's game mode as well!
*
@ -43,75 +33,6 @@ import net.minecraft.world.World;
* If you must do that, consider returning an ActionResult.SUCCESS and re-emitting the event in some manner!
* - ATTACK_BLOCK does not let you control the packet sending process yet.
*/
@Deprecated
public final class PlayerInteractionEvent {
@FunctionalInterface
public interface Block {
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction);
}
@FunctionalInterface
public interface Entity {
ActionResult interact(PlayerEntity player, World world, Hand hand, net.minecraft.entity.Entity entity);
}
// TODO: Use class_3965
@FunctionalInterface
public interface BlockPositioned {
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction, float hitX, float hitY, float hitZ);
}
@FunctionalInterface
public interface EntityPositioned {
ActionResult interact(PlayerEntity player, World world, Hand hand, net.minecraft.entity.Entity entity, Vec3d hitPosition);
}
@FunctionalInterface
public interface Item {
ActionResult interact(PlayerEntity player, World world, Hand hand);
}
/**
* Event emitted when a player "attacks" a block.
*/
public static final HandlerRegistry<Block> ATTACK_BLOCK = new HandlerArray<>(Block.class);
/**
* Event emitted when a player "attacks" an entity.
*/
public static final HandlerRegistry<Entity> ATTACK_ENTITY = new HandlerArray<>(Entity.class);
// TODO: For completeness' sake, but requires us to add a custom packet. Is it worth the complexity?
/* public static final HandlerRegistry<Item> ATTACK_ITEM = new HandlerList<>(); */
/**
* Event emitted when a player interacts with a block.
*/
public static final HandlerRegistry<BlockPositioned> INTERACT_BLOCK = new HandlerArray<>(BlockPositioned.class);
/**
* Event emitted when a player interacts with an entity.
*
* Developer note: Minecraft provides two methods to interact with
* Entities - one takes in a hit position, the other does not. However,
* all vanilla interaction cases seem to use one, then the other - as such,
* only one event is currently provided, but it is accordingly named in
* the case of a second event being necessary.
*/
public static final HandlerRegistry<EntityPositioned> INTERACT_ENTITY_POSITIONED = new HandlerArray<>(EntityPositioned.class);
/**
* Event emitted when a player interacts with an item.
*/
public static final HandlerRegistry<Item> INTERACT_ITEM = new HandlerArray<>(Item.class);
/**
* @deprecated Use {@link #ATTACK_BLOCK ATTACK_BLOCK} instead.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public static final HandlerRegistry<Block> BREAK_BLOCK = ATTACK_BLOCK;
private PlayerInteractionEvent() {
}
}

View file

@ -1,60 +0,0 @@
/*
* 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.events;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.util.HandlerRegistry;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.World;
import java.util.function.Consumer;
/**
* Events emitted during the ticking process for global Minecraft objects.
* You can use them as endpoints to tick your own, related logic "globally".
*/
public final class TickEvent {
public static final HandlerRegistry<Consumer<MinecraftServer>> SERVER = new HandlerArray<>(Consumer.class);
public static final HandlerRegistry<Consumer<World>> WORLD = new HandlerArray<>(Consumer.class);
private TickEvent() {
}
public static <T> void tick(HandlerRegistry<Consumer<T>> registry, T object, Profiler profiler) {
Consumer<T>[] handlers = ((HandlerArray<Consumer<T>>) registry).getBackingArray();
if (handlers.length > 0) {
profiler.push("fabric");
int i = 0;
for (Consumer<T> handler : handlers) {
if ((i++) == 0) {
profiler.push(handler.getClass().getName());
} else {
profiler.swap(handler.getClass().getName());
}
handler.accept(object);
}
if (i > 0) {
profiler.pop();
}
profiler.pop();
}
}
}

View file

@ -17,23 +17,17 @@
package net.fabricmc.fabric.impl;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.block.BreakInteractable;
import net.fabricmc.fabric.events.PlayerInteractionEvent;
import net.minecraft.block.BlockState;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.MixinEnvironment;
import java.util.List;
public class FabricAPIInitializer implements ModInitializer {
@Override
public void onInitialize() {
PlayerInteractionEvent.BREAK_BLOCK.register((player, world, hand, pos, direction) -> {
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
System.out.println("--- DEMO --- PlayerInteractCallback called!");
BlockState state = world.getBlockState(pos);
if (state instanceof BreakInteractable) {
if (((BreakInteractable) state).onBreakInteract(state, world, pos, player, hand, direction)) {

View file

@ -0,0 +1,70 @@
/*
* 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.impl.event;
import net.fabricmc.fabric.api.event.Event;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.function.Function;
class ArrayBackedEvent<T> extends Event<T> {
private final Class<T> type;
private final Function<T[], T> joiner;
private final T dummyInvoker;
private T[] handlers;
ArrayBackedEvent(Class<T> type, T dummyInvoker, Function<T[], T> joiner) {
this.type = type;
this.dummyInvoker = dummyInvoker;
this.joiner = joiner;
update();
}
void update() {
if (handlers == null) {
if (dummyInvoker != null) {
invoker = dummyInvoker;
} else {
//noinspection unchecked
invoker = joiner.apply((T[]) Array.newInstance(type, 0));
}
} else if (handlers.length == 1) {
invoker = handlers[0];
} else {
invoker = joiner.apply(handlers);
}
}
@Override
public void register(T listener) {
if (listener == null) {
throw new NullPointerException("Tried to register a null listener!");
}
if (handlers == null) {
//noinspection unchecked
handlers = (T[]) Array.newInstance(type, 1);
handlers[0] = listener;
} else {
handlers = Arrays.copyOf(handlers, handlers.length + 1);
handlers[handlers.length - 1] = listener;
}
update();
}
}

View file

@ -0,0 +1,104 @@
/*
* 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.impl.event;
import net.fabricmc.fabric.api.event.Event;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public final class EventFactoryImpl {
private static final List<ArrayBackedEvent<?>> ARRAY_BACKED_EVENTS = new ArrayList<>();
private EventFactoryImpl() {
}
public static void invalidate() {
ARRAY_BACKED_EVENTS.forEach(ArrayBackedEvent::update);
}
public static <T> Event<T> arrayBacked(Class<T> type, Function<T[], T> joiner) {
return arrayBacked(type, null /* buildEmptyInvoker(type, joiner) */, joiner);
}
public static <T> Event<T> arrayBacked(Class<T> type, T emptyInvoker, Function<T[], T> joiner) {
ArrayBackedEvent<T> event = new ArrayBackedEvent<>(type, emptyInvoker, joiner);
ARRAY_BACKED_EVENTS.add(event);
return event;
}
// Code originally by sfPlayer1.
// Unfortunately, it's slightly slower than just passing an empty array in the first place.
private static <T> T buildEmptyInvoker(Class<T> handlerClass, Function<T[], T> invokerSetup) {
// find the functional interface method
Method funcIfMethod = null;
for (Method m : handlerClass.getMethods()) {
if ((m.getModifiers() & (Modifier.STRICT | Modifier.PRIVATE)) == 0) {
if (funcIfMethod != null) {
throw new IllegalStateException("Multiple virtual methods in " + handlerClass + "; cannot build empty invoker!");
}
funcIfMethod = m;
}
}
if (funcIfMethod == null) {
throw new IllegalStateException("No virtual methods in " + handlerClass + "; cannot build empty invoker!");
}
Object defValue = null;
try {
// concert to mh, determine its type without the "this" reference
MethodHandle target = MethodHandles.lookup().unreflect(funcIfMethod);
MethodType type = target.type().dropParameterTypes(0, 1);
if (type.returnType() != void.class) {
// determine default return value by invoking invokerSetup.apply(T[0]) with all-jvm-default args (null for refs, false for boolean, etc.)
// explicitCastArguments is being used to cast Object=null to the jvm default value for the correct type
// construct method desc (TLjava/lang/Object;Ljava/lang/Object;...)R where T = invoker ref ("this"), R = invoker ret type and args 1+ are Object for each non-"this" invoker arg
MethodType objTargetType = MethodType.genericMethodType(type.parameterCount()).changeReturnType(type.returnType()).insertParameterTypes(0, target.type().parameterType(0));
// explicit cast to translate to the invoker args from Object to their real type, inferring jvm default values
MethodHandle objTarget = MethodHandles.explicitCastArguments(target, objTargetType);
// build invocation args with 0 = "this", 1+ = null
Object[] args = new Object[target.type().parameterCount()];
//noinspection unchecked
args[0] = invokerSetup.apply((T[]) Array.newInstance(handlerClass, 0));
// retrieve default by invoking invokerSetup.apply(T[0]).targetName(def,def,...)
defValue = objTarget.invokeWithArguments(args);
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
final Object returnValue = defValue;
//noinspection unchecked
return (T) Proxy.newProxyInstance(EventFactoryImpl.class.getClassLoader(), new Class[] { handlerClass },
(proxy, method, args) -> returnValue);
}
}

View file

@ -17,10 +17,9 @@
package net.fabricmc.fabric.mixin.client.texture;
import com.google.common.base.Joiner;
import net.fabricmc.fabric.api.event.client.SpriteRegistrationCallback;
import net.fabricmc.fabric.client.texture.*;
import net.fabricmc.fabric.impl.client.texture.FabricSprite;
import net.fabricmc.fabric.events.client.SpriteEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.minecraft.class_1050;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
@ -83,13 +82,8 @@ public abstract class MixinSpriteAtlasTexture {
@Inject(at = @At("HEAD"), method = "reload")
public void reload(ResourceManager manager, CallbackInfo info) {
//noinspection RedundantCast,ConstantConditions
if ((SpriteAtlasTexture) (Object) this == MinecraftClient.getInstance().getSpriteAtlas()) {
SpriteRegistry registry = new SpriteRegistry(sprites, (id) -> addSpriteToLoad(manager, id));
for (SpriteEvent.Provider provider : ((HandlerArray<SpriteEvent.Provider>) SpriteEvent.PROVIDE).getBackingArray()) {
provider.registerSprites(registry);
}
}
SpriteRegistrationCallback.Registry registry = new SpriteRegistrationCallback.Registry(sprites, (id) -> addSpriteToLoad(manager, id));
SpriteRegistrationCallback.EVENT.invoker().registerSprites((SpriteAtlasTexture) (Object) this, registry);
// TODO: Unoptimized.
Set<DependentSprite> dependentSprites = new HashSet<>();

View file

@ -16,22 +16,17 @@
package net.fabricmc.fabric.mixin.events.objectbuilder;
import net.fabricmc.fabric.events.ObjectBuilderEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.registry.BlockBuildingCallback;
import net.minecraft.block.Block;
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.callback.CallbackInfo;
import java.util.function.BiConsumer;
@Mixin(Block.class)
public class MixinBlock {
@Inject(method = "<init>(Lnet/minecraft/block/Block$Settings;)V", at = @At("RETURN"))
public void init(Block.Settings builder, CallbackInfo info) {
for (BiConsumer<Block.Settings, Block> consumer : ((HandlerArray<BiConsumer<Block.Settings, Block>>) ObjectBuilderEvent.BLOCK).getBackingArray()) {
consumer.accept(builder, (Block) (Object) this);
}
BlockBuildingCallback.EVENT.invoker().building(builder, (Block) (Object) this);
}
}

View file

@ -16,22 +16,17 @@
package net.fabricmc.fabric.mixin.events.objectbuilder;
import net.fabricmc.fabric.events.ObjectBuilderEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.registry.ItemBuildingCallback;
import net.minecraft.item.Item;
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.callback.CallbackInfo;
import java.util.function.BiConsumer;
@Mixin(Item.class)
public class MixinItem {
@Inject(method = "<init>(Lnet/minecraft/item/Item$Settings;)V", at = @At("RETURN"))
public void init(Item.Settings builder, CallbackInfo info) {
for (BiConsumer<Item.Settings, Item> consumer : ((HandlerArray<BiConsumer<Item.Settings, Item>>) ObjectBuilderEvent.ITEM).getBackingArray()) {
consumer.accept(builder, (Item) (Object) this);
}
ItemBuildingCallback.EVENT.invoker().building(builder, (Item) (Object) this);
}
}

View file

@ -16,8 +16,7 @@
package net.fabricmc.fabric.mixin.events.playerinteraction;
import net.fabricmc.fabric.events.PlayerInteractionEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.player.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
@ -55,13 +54,10 @@ public class MixinClientPlayerInteractionManager {
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/world/GameMode;isCreative()Z", ordinal = 0), method = "attackBlock", cancellable = true)
public void attackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> info) {
for (PlayerInteractionEvent.Block handler : ((HandlerArray<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
ActionResult result = handler.interact(client.player, client.world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
info.setReturnValue(result == ActionResult.SUCCESS);
info.cancel();
return;
}
ActionResult result = AttackBlockCallback.EVENT.invoker().interact(client.player, client.world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
info.setReturnValue(result == ActionResult.SUCCESS);
info.cancel();
}
}
@ -71,86 +67,60 @@ public class MixinClientPlayerInteractionManager {
return;
}
for (PlayerInteractionEvent.Block handler : ((HandlerArray<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
ActionResult result = handler.interact(client.player, client.world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
info.setReturnValue(result == ActionResult.SUCCESS);
info.cancel();
return;
}
ActionResult result = AttackBlockCallback.EVENT.invoker().interact(client.player, client.world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
info.setReturnValue(result == ActionResult.SUCCESS);
info.cancel();
}
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getStackInHand(Lnet/minecraft/util/Hand;)Lnet/minecraft/item/ItemStack;", ordinal = 0), method = "interactBlock", cancellable = true)
public void interactBlock(ClientPlayerEntity player, ClientWorld world, Hand hand, BlockHitResult blockHitResult, CallbackInfoReturnable<ActionResult> info) {
PlayerInteractionEvent.BlockPositioned[] backingArray = ((HandlerArray<PlayerInteractionEvent.BlockPositioned>) PlayerInteractionEvent.INTERACT_BLOCK).getBackingArray();
if (backingArray.length > 0) {
Vec3d vec = blockHitResult.getPos();
BlockPos pos = blockHitResult.getBlockPos();
Direction direction = blockHitResult.getSide();
float hitX = (float) (vec.x - pos.getX());
float hitY = (float) (vec.y - pos.getY());
float hitZ = (float) (vec.z - pos.getZ());
for (PlayerInteractionEvent.BlockPositioned handler : backingArray) {
ActionResult result = handler.interact(player, world, hand, pos, direction, hitX, hitY, hitZ);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractBlockServerPacket(hand, blockHitResult));
}
info.setReturnValue(result);
info.cancel();
return;
}
ActionResult result = UseBlockCallback.EVENT.invoker().interact(player, world, hand, blockHitResult);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractBlockServerPacket(hand, blockHitResult));
}
info.setReturnValue(result);
info.cancel();
}
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "interactItem", cancellable = true)
public void interactItem(PlayerEntity player, World world, Hand hand, CallbackInfoReturnable<ActionResult> info) {
for (PlayerInteractionEvent.Item handler : ((HandlerArray<PlayerInteractionEvent.Item>) PlayerInteractionEvent.INTERACT_ITEM).getBackingArray()) {
ActionResult result = handler.interact(player, world, hand);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractItemServerPacket(hand));
}
info.setReturnValue(result);
info.cancel();
return;
ActionResult result = UseItemCallback.EVENT.invoker().interact(player, world, hand);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractItemServerPacket(hand));
}
info.setReturnValue(result);
info.cancel();
return;
}
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "attackEntity", cancellable = true)
public void attackEntity(PlayerEntity player, Entity entity, CallbackInfo info) {
for (PlayerInteractionEvent.Entity handler : ((HandlerArray<PlayerInteractionEvent.Entity>) PlayerInteractionEvent.ATTACK_ENTITY).getBackingArray()) {
ActionResult result = handler.interact(player, player.getEntityWorld(), Hand.MAIN /* TODO */, entity);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity));
}
info.cancel();
return;
ActionResult result = AttackEntityCallback.EVENT.invoker().interact(player, player.getEntityWorld(), Hand.MAIN /* TODO */, entity, null);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity));
}
info.cancel();
}
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "interactEntityAtLocation", cancellable = true)
public void interactEntityAtLocation(PlayerEntity player, Entity entity, EntityHitResult hitResult, Hand hand, CallbackInfoReturnable<ActionResult> info) {
// TODO: Remove double Vec3d creation?
Vec3d hitVec = hitResult.getPos().subtract(entity.x, entity.y, entity.z);
for (PlayerInteractionEvent.EntityPositioned handler : ((HandlerArray<PlayerInteractionEvent.EntityPositioned>) PlayerInteractionEvent.INTERACT_ENTITY_POSITIONED).getBackingArray()) {
ActionResult result = handler.interact(player, player.getEntityWorld(), hand, entity, hitVec);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity, hand, hitVec));
}
info.setReturnValue(result);
info.cancel();
return;
ActionResult result = UseEntityCallback.EVENT.invoker().interact(player, player.getEntityWorld(), hand, entity, hitResult);
if (result != ActionResult.PASS) {
if (result == ActionResult.SUCCESS) {
Vec3d hitVec = hitResult.getPos().subtract(entity.x, entity.y, entity.z);
this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity, hand, hitVec));
}
info.setReturnValue(result);
info.cancel();
return;
}
}
}

View file

@ -16,12 +16,14 @@
package net.fabricmc.fabric.mixin.events.playerinteraction;
import net.fabricmc.fabric.events.PlayerInteractionEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.packet.PlayerInteractEntityServerPacket;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -35,11 +37,14 @@ public class MixinServerPlayNetworkHandler {
@Inject(method = "onPlayerInteractEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;interactAt(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;"), cancellable = true)
public void onPlayerInteractEntity(PlayerInteractEntityServerPacket packet, CallbackInfo info) {
for (PlayerInteractionEvent.EntityPositioned handler : ((HandlerArray<PlayerInteractionEvent.EntityPositioned>) PlayerInteractionEvent.INTERACT_ENTITY_POSITIONED).getBackingArray()) {
ActionResult result = handler.interact(player, player.getEntityWorld(), packet.getHand(), packet.getEntity(player.world), packet.getHitPosition());
World world = player.getEntityWorld();
Entity entity = packet.getEntity(world);
if (entity != null) {
EntityHitResult hitResult = new EntityHitResult(entity, packet.getHitPosition().add(entity.x, entity.y, entity.z));
ActionResult result = UseEntityCallback.EVENT.invoker().interact(player, world, packet.getHand(), entity, hitResult);
if (result != ActionResult.PASS) {
info.cancel();
return;
}
}
}

View file

@ -16,8 +16,7 @@
package net.fabricmc.fabric.mixin.events.playerinteraction;
import net.fabricmc.fabric.events.PlayerInteractionEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
@ -32,13 +31,9 @@ public class MixinServerPlayerEntity {
@Inject(method = "attack", at = @At("HEAD"), cancellable = true)
public void onPlayerInteractEntity(Entity target, CallbackInfo info) {
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
for (PlayerInteractionEvent.Entity handler : ((HandlerArray<PlayerInteractionEvent.Entity>) PlayerInteractionEvent.ATTACK_ENTITY).getBackingArray()) {
ActionResult result = handler.interact(player, player.getEntityWorld(), Hand.MAIN, target);
if (result != ActionResult.PASS) {
info.cancel();
return;
}
ActionResult result = AttackEntityCallback.EVENT.invoker().interact(player, player.getEntityWorld(), Hand.MAIN, target, null);
if (result != ActionResult.PASS) {
info.cancel();
}
}
}

View file

@ -16,8 +16,9 @@
package net.fabricmc.fabric.mixin.events.playerinteraction;
import net.fabricmc.fabric.events.PlayerInteractionEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.minecraft.client.network.packet.BlockUpdateClientPacket;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
@ -29,7 +30,6 @@ import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -47,46 +47,31 @@ public class MixinServerPlayerInteractionManager {
@Inject(at = @At("HEAD"), method = "method_14263", cancellable = true)
public void startBlockBreak(BlockPos pos, Direction direction, CallbackInfo info) {
for (PlayerInteractionEvent.Block handler : ((HandlerArray<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
ActionResult result = handler.interact(player, world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
// The client might have broken the block on its side, so make sure to let it know.
this.player.networkHandler.sendPacket(new BlockUpdateClientPacket(world, pos));
info.cancel();
return;
}
ActionResult result = AttackBlockCallback.EVENT.invoker().interact(player, world, Hand.MAIN, pos, direction);
if (result != ActionResult.PASS) {
// The client might have broken the block on its side, so make sure to let it know.
this.player.networkHandler.sendPacket(new BlockUpdateClientPacket(world, pos));
info.cancel();
}
}
@Inject(at = @At("HEAD"), method = "interactBlock", cancellable = true)
public void interactBlock(PlayerEntity player, World world, ItemStack stack, Hand hand, BlockHitResult blockHitResult, CallbackInfoReturnable<ActionResult> info) {
for (PlayerInteractionEvent.BlockPositioned handler : ((HandlerArray<PlayerInteractionEvent.BlockPositioned>) PlayerInteractionEvent.INTERACT_BLOCK).getBackingArray()) {
Vec3d vec = blockHitResult.getPos();
BlockPos pos = blockHitResult.getBlockPos();
Direction direction = blockHitResult.getSide();
float hitX = (float) (vec.x - pos.getX());
float hitY = (float) (vec.y - pos.getY());
float hitZ = (float) (vec.z - pos.getZ());
ActionResult result = handler.interact(player, world, hand, pos, direction, hitX, hitY, hitZ);
if (result != ActionResult.PASS) {
info.setReturnValue(result);
info.cancel();
return;
}
ActionResult result = UseBlockCallback.EVENT.invoker().interact(player, world, hand, blockHitResult);
if (result != ActionResult.PASS) {
info.setReturnValue(result);
info.cancel();
return;
}
}
@Inject(at = @At("HEAD"), method = "interactItem", cancellable = true)
public void interactItem(PlayerEntity player, World world, ItemStack stack, Hand hand, CallbackInfoReturnable<ActionResult> info) {
for (PlayerInteractionEvent.Item handler : ((HandlerArray<PlayerInteractionEvent.Item>) PlayerInteractionEvent.INTERACT_ITEM).getBackingArray()) {
ActionResult result = handler.interact(player, world, hand);
if (result != ActionResult.PASS) {
info.setReturnValue(result);
info.cancel();
return;
}
ActionResult result = UseItemCallback.EVENT.invoker().interact(player, world, hand);
if (result != ActionResult.PASS) {
info.setReturnValue(result);
info.cancel();
return;
}
}
}

View file

@ -16,29 +16,23 @@
package net.fabricmc.fabric.mixin.events.server;
import net.fabricmc.fabric.events.ServerEvent;
import net.fabricmc.fabric.util.HandlerArray;
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
import net.minecraft.server.MinecraftServer;
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.callback.CallbackInfo;
import java.util.function.Consumer;
@Mixin(MinecraftServer.class)
public class MixinMinecraftServer {
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;method_3791(Lnet/minecraft/server/ServerMetadata;)V", ordinal = 0), method = "run")
public void afterSetupServer(CallbackInfo info) {
for (Consumer<MinecraftServer> handler : ((HandlerArray<Consumer<MinecraftServer>>) ServerEvent.START).getBackingArray()) {
handler.accept((MinecraftServer) (Object) this);
}
ServerStartCallback.EVENT.invoker().onStartServer((MinecraftServer) (Object) this);
}
@Inject(at = @At("HEAD"), method = "shutdown")
public void beforeShutdownServer(CallbackInfo info) {
for (Consumer<MinecraftServer> handler : ((HandlerArray<Consumer<MinecraftServer>>) ServerEvent.STOP).getBackingArray()) {
handler.accept((MinecraftServer) (Object) this);
}
ServerStopCallback.EVENT.invoker().onStopServer((MinecraftServer) (Object) this);
}
}

View file

@ -16,26 +16,21 @@
package net.fabricmc.fabric.mixin.events.tick;
import net.fabricmc.fabric.events.TickEvent;
import net.fabricmc.fabric.events.client.ClientTickEvent;
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.profiler.DisableableProfiler;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.BooleanSupplier;
@Mixin(MinecraftClient.class)
public class MixinMinecraftClient {
@Shadow
private DisableableProfiler profiler;
@Inject(at = @At("RETURN"), method = "tick")
public void tick(CallbackInfo info) {
TickEvent.tick(ClientTickEvent.CLIENT, (MinecraftClient) (Object) this, this.profiler);
ClientTickCallback.EVENT.invoker().tick((MinecraftClient) (Object) this);
}
}

View file

@ -16,7 +16,7 @@
package net.fabricmc.fabric.mixin.events.tick;
import net.fabricmc.fabric.events.TickEvent;
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.profiler.DisableableProfiler;
import org.spongepowered.asm.mixin.Mixin;
@ -29,11 +29,8 @@ import java.util.function.BooleanSupplier;
@Mixin(MinecraftServer.class)
public class MixinMinecraftServer {
@Shadow
private DisableableProfiler profiler;
@Inject(at = @At("RETURN"), method = "tick")
protected void tick(BooleanSupplier var1, CallbackInfo info) {
TickEvent.tick(TickEvent.SERVER, (MinecraftServer) (Object) this, this.profiler);
ServerTickCallback.EVENT.invoker().tick((MinecraftServer) (Object) this);
}
}

View file

@ -16,7 +16,7 @@
package net.fabricmc.fabric.mixin.events.tick;
import net.fabricmc.fabric.events.TickEvent;
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
@ -29,11 +29,8 @@ import java.util.function.BooleanSupplier;
@Mixin(World.class)
public class MixinWorld {
@Shadow
private Profiler profiler;
@Inject(at = @At("RETURN"), method = "tick")
public void tick(BooleanSupplier booleanSupplier, CallbackInfo info) {
TickEvent.tick(TickEvent.WORLD, (World) (Object) this, this.profiler);
WorldTickCallback.EVENT.invoker().tick((World) (Object) this);
}
}

View file

@ -16,8 +16,8 @@
package net.fabricmc.fabric.tools;
import net.fabricmc.fabric.api.event.registry.BlockBuildingCallback;
import net.fabricmc.fabric.block.FabricBlockSettings;
import net.fabricmc.fabric.events.ObjectBuilderEvent;
import net.fabricmc.fabric.util.TriState;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -75,7 +75,7 @@ public final class ToolManager {
}
static {
ObjectBuilderEvent.BLOCK.register(ToolManager::onBlockRegistered);
BlockBuildingCallback.EVENT.register(ToolManager::onBlockRegistered);
}
private static void onBlockRegistered(Block.Settings settings, Block block) {

View file

@ -1,51 +0,0 @@
/*
* 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.util;
import net.fabricmc.fabric.util.HandlerRegistry;
import java.lang.reflect.Array;
public class HandlerArray<T> implements HandlerRegistry<T> {
private final Class tClass;
private T[] array;
@SuppressWarnings("unchecked")
public HandlerArray(Class theClass) {
this.tClass = theClass;
this.array = (T[]) Array.newInstance(tClass, 0);
}
@Override
public void register(T handler) {
for (int i = 0; i < array.length; i++) {
if (array[i] == handler) {
throw new RuntimeException("Handler " + handler + " already registered!");
}
}
//noinspection unchecked
T[] newArray = (T[]) Array.newInstance(tClass, array.length + 1);
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[array.length] = handler;
array = newArray;
}
public T[] getBackingArray() {
return array;
}
}

View file

@ -1,53 +0,0 @@
/*
* 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.util;
import java.lang.reflect.Array;
/**
* @deprecated Use HandlerArray.
*/
@Deprecated
public class HandlerList<T> implements HandlerRegistry<T> {
private final Class tClass;
private T[] array;
@SuppressWarnings("unchecked")
public HandlerList(Class theClass) {
this.tClass = theClass;
this.array = (T[]) Array.newInstance(tClass, 0);
}
@Override
public void register(T handler) {
for (int i = 0; i < array.length; i++) {
if (array[i] == handler) {
throw new RuntimeException("Handler " + handler + " already registered!");
}
}
//noinspection unchecked
T[] newArray = (T[]) Array.newInstance(tClass, array.length + 1);
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[array.length] = handler;
array = newArray;
}
public T[] getBackingArray() {
return array;
}
}

View file

@ -17,6 +17,8 @@
package net.fabricmc.fabric.events;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -25,7 +27,7 @@ public class ServerEventMod implements ModInitializer {
@Override
public void onInitialize() {
ServerEvent.START.register(server -> LOGGER.info("Server starting (" + server + ")"));
ServerEvent.STOP.register(server -> LOGGER.info("Server stopping (" + server + ")"));
ServerStartCallback.EVENT.register(server -> LOGGER.info("Server starting (" + server + ")"));
ServerStopCallback.EVENT.register(server -> LOGGER.info("Server stopping (" + server + ")"));
}
}

View file

@ -18,7 +18,7 @@ package net.fabricmc.fabric.model;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.events.client.ClientTickEvent;
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.*;
@ -114,7 +114,7 @@ public class ModelModClient implements ClientModInitializer {
}
}));
ClientTickEvent.CLIENT.register((client) -> {
ClientTickCallback.EVENT.register((client) -> {
if (client.getBakedModelManager().getModel(new ModelIdentifier("fabric:model#custom"))
== bakedModel && bakedModel != null) {
System.out.println("--- MODEL LOADED! ---");