Merge remote-tracking branch 'architectury/1.16' into 1.17

# Conflicts:
#	fabric/src/main/resources/architectury.mixins.json
#	gradle.properties
#	settings.gradle
This commit is contained in:
shedaniel
2021-02-11 21:35:32 +08:00
111 changed files with 2971 additions and 404 deletions

View File

@@ -0,0 +1,29 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.core;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
/**
* The equivalent of {@link RecipeSerializer} to use in common that has forge registry entries extended.
*/
public abstract class AbstractRecipeSerializer<T extends Recipe<?>> extends RegistryEntry<RecipeSerializer<?>> implements RecipeSerializer<T> {
}

View File

@@ -17,12 +17,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test;
package me.shedaniel.architectury.core;
public interface MessageSink {
void accept(String message);
default void accept(String message, Object... args) {
accept(String.format(message, args));
}
/**
* An entry in registries, will extend {@code ForgeRegistryEntry} on forge.
*/
public class RegistryEntry<T> {
}

View File

@@ -58,6 +58,12 @@ public final class EventFactory {
return new EventImpl<>(function);
}
@SafeVarargs
public static <T> Event<T> createLoop(T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return createLoop((Class<T>) typeGetter.getClass().getComponentType());
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<T> createLoop(Class<T> clazz) {
return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
@@ -71,6 +77,12 @@ public final class EventFactory {
}));
}
@SafeVarargs
public static <T> Event<T> createInteractionResult(T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return createInteractionResult((Class<T>) typeGetter.getClass().getComponentType());
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<T> createInteractionResult(Class<T> clazz) {
return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
@@ -87,6 +99,12 @@ public final class EventFactory {
}));
}
@SafeVarargs
public static <T> Event<T> createInteractionResultHolder(T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return createInteractionResultHolder((Class<T>) typeGetter.getClass().getComponentType());
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<T> createInteractionResultHolder(Class<T> clazz) {
return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
@@ -103,6 +121,12 @@ public final class EventFactory {
}));
}
@SafeVarargs
public static <T> Event<Consumer<T>> createConsumerLoop(T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return createConsumerLoop((Class<T>) typeGetter.getClass().getComponentType());
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<Consumer<T>> createConsumerLoop(Class<T> clazz) {
Event<Consumer<T>> event = of(listeners -> (Consumer<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Consumer.class}, new AbstractInvocationHandler() {
@@ -124,6 +148,12 @@ public final class EventFactory {
return event;
}
@SafeVarargs
public static <T> Event<Actor<T>> createActorLoop(T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return createActorLoop((Class<T>) typeGetter.getClass().getComponentType());
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<Actor<T>> createActorLoop(Class<T> clazz) {
Event<Actor<T>> event = of(listeners -> (Actor<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Actor.class}, new AbstractInvocationHandler() {

View File

@@ -30,7 +30,7 @@ public interface ChatEvent {
/**
* Invoked when server receives a message, equivalent to forge's {@code ServerChatEvent}.
*/
Event<Server> SERVER = EventFactory.createInteractionResultHolder(Server.class);
Event<Server> SERVER = EventFactory.createInteractionResultHolder();
interface Server {
@NotNull

View File

@@ -31,7 +31,7 @@ public class CommandPerformEvent {
/**
* Invoked after server parses a command but before server executes it, equivalent to forge's {@code CommandEvent}.
*/
public static final Event<Actor<CommandPerformEvent>> EVENT = EventFactory.createActorLoop(CommandPerformEvent.class);
public static final Event<Actor<CommandPerformEvent>> EVENT = EventFactory.createActorLoop();
@NotNull
private ParseResults<CommandSourceStack> results;

View File

@@ -29,7 +29,7 @@ public interface CommandRegistrationEvent {
/**
* Invoked after server registers its commands, equivalent to forge's {@code RegisterCommandsEvent} and fabric's {@code CommandRegistrationCallback}.
*/
Event<CommandRegistrationEvent> EVENT = EventFactory.createLoop(CommandRegistrationEvent.class);
Event<CommandRegistrationEvent> EVENT = EventFactory.createLoop();
void register(CommandDispatcher<CommandSourceStack> dispatcher, Commands.CommandSelection selection);
}

View File

@@ -34,16 +34,16 @@ public interface EntityEvent {
/**
* Invoked before LivingEntity#die, equivalent to forge's {@code LivingDeathEvent}.
*/
Event<LivingDeath> LIVING_DEATH = EventFactory.createInteractionResult(LivingDeath.class);
Event<LivingDeath> LIVING_DEATH = EventFactory.createInteractionResult();
/**
* Invoked before LivingEntity#hurt, equivalent to forge's {@code LivingAttackEvent}.
*/
Event<LivingAttack> LIVING_ATTACK = EventFactory.createInteractionResult(LivingAttack.class);
Event<LivingAttack> LIVING_ATTACK = EventFactory.createInteractionResult();
/**
* Invoked before entity is added to a world, equivalent to forge's {@code EntityJoinWorldEvent}.
*/
Event<Add> ADD = EventFactory.createInteractionResult(Add.class);
Event<PlaceBlock> PLACE_BLOCK = EventFactory.createInteractionResult(PlaceBlock.class);
Event<Add> ADD = EventFactory.createInteractionResult();
Event<PlaceBlock> PLACE_BLOCK = EventFactory.createInteractionResult();
interface LivingDeath {
InteractionResult die(LivingEntity entity, DamageSource source);

View File

@@ -29,8 +29,8 @@ import net.minecraft.world.level.Level;
import java.util.List;
public interface ExplosionEvent {
Event<Pre> PRE = EventFactory.createInteractionResult(Pre.class);
Event<Detonate> DETONATE = EventFactory.createInteractionResult(Detonate.class);
Event<Pre> PRE = EventFactory.createInteractionResult();
Event<Detonate> DETONATE = EventFactory.createInteractionResult();
interface Pre {
InteractionResult explode(Level world, Explosion explosion);

View File

@@ -28,6 +28,7 @@ import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import java.util.List;
@@ -36,19 +37,24 @@ public interface GuiEvent {
/**
* Invoked after in-game hud is rendered, equivalent to forge's {@code RenderGameOverlayEvent.Post@ElementType#ALL} and fabric's {@code HudRenderCallback}.
*/
Event<RenderHud> RENDER_HUD = EventFactory.createLoop(RenderHud.class);
Event<DebugText> DEBUG_TEXT_LEFT = EventFactory.createLoop(DebugText.class);
Event<DebugText> DEBUG_TEXT_RIGHT = EventFactory.createLoop(DebugText.class);
Event<RenderHud> RENDER_HUD = EventFactory.createLoop();
Event<DebugText> DEBUG_TEXT_LEFT = EventFactory.createLoop();
Event<DebugText> DEBUG_TEXT_RIGHT = EventFactory.createLoop();
/**
* Invoked during Screen#init after previous widgets are cleared, equivalent to forge's {@code GuiScreenEvent.InitGuiEvent.Pre}.
*/
Event<ScreenInitPre> INIT_PRE = EventFactory.createInteractionResult(ScreenInitPre.class);
Event<ScreenInitPre> INIT_PRE = EventFactory.createInteractionResult();
/**
* Invoked after Screen#init, equivalent to forge's {@code GuiScreenEvent.InitGuiEvent.Post}.
*/
Event<ScreenInitPost> INIT_POST = EventFactory.createLoop(ScreenInitPost.class);
Event<ScreenRenderPre> RENDER_PRE = EventFactory.createInteractionResult(ScreenRenderPre.class);
Event<ScreenRenderPost> RENDER_POST = EventFactory.createInteractionResult(ScreenRenderPost.class);
Event<ScreenInitPost> INIT_POST = EventFactory.createLoop();
Event<ScreenRenderPre> RENDER_PRE = EventFactory.createInteractionResult();
Event<ScreenRenderPost> RENDER_POST = EventFactory.createInteractionResult();
/**
* Invoked during Minecraft#setScreen, equivalent to forge's {@code GuiOpenEvent}.
*/
Event<SetScreen> SET_SCREEN = EventFactory.createInteractionResultHolder();
@Environment(EnvType.CLIENT)
interface RenderHud {
@@ -79,4 +85,9 @@ public interface GuiEvent {
interface ScreenRenderPost {
void render(Screen screen, PoseStack matrices, int mouseX, int mouseY, float delta);
}
@Environment(EnvType.CLIENT)
interface SetScreen {
InteractionResultHolder<Screen> modifyScreen(Screen screen);
}
}

View File

@@ -32,12 +32,12 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
public interface InteractionEvent {
Event<LeftClickBlock> LEFT_CLICK_BLOCK = EventFactory.createInteractionResult(LeftClickBlock.class);
Event<RightClickBlock> RIGHT_CLICK_BLOCK = EventFactory.createInteractionResult(RightClickBlock.class);
Event<RightClickItem> RIGHT_CLICK_ITEM = EventFactory.createInteractionResultHolder(RightClickItem.class);
Event<ClientLeftClickAir> CLIENT_LEFT_CLICK_AIR = EventFactory.createLoop(ClientLeftClickAir.class);
Event<ClientRightClickAir> CLIENT_RIGHT_CLICK_AIR = EventFactory.createLoop(ClientRightClickAir.class);
Event<InteractEntity> INTERACT_ENTITY = EventFactory.createInteractionResult(InteractEntity.class);
Event<LeftClickBlock> LEFT_CLICK_BLOCK = EventFactory.createInteractionResult();
Event<RightClickBlock> RIGHT_CLICK_BLOCK = EventFactory.createInteractionResult();
Event<RightClickItem> RIGHT_CLICK_ITEM = EventFactory.createInteractionResultHolder();
Event<ClientLeftClickAir> CLIENT_LEFT_CLICK_AIR = EventFactory.createLoop();
Event<ClientRightClickAir> CLIENT_RIGHT_CLICK_AIR = EventFactory.createLoop();
Event<InteractEntity> INTERACT_ENTITY = EventFactory.createInteractionResult();
interface RightClickBlock {
InteractionResult click(Player player, InteractionHand hand, BlockPos pos, Direction face);

View File

@@ -29,35 +29,35 @@ public interface LifecycleEvent {
/**
* Invoked when server is starting, equivalent to forge's {@code FMLServerAboutToStartEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STARTING}.
*/
Event<ServerState> SERVER_BEFORE_START = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_BEFORE_START = EventFactory.createLoop();
/**
* Invoked when server is starting, equivalent to forge's {@code FMLServerStartingEvent}.
*/
Event<ServerState> SERVER_STARTING = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STARTING = EventFactory.createLoop();
/**
* Invoked when server has started, equivalent to forge's {@code FMLServerStartedEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STARTED}.
*/
Event<ServerState> SERVER_STARTED = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STARTED = EventFactory.createLoop();
/**
* Invoked when server is stopping, equivalent to forge's {@code FMLServerStoppingEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STOPPING}.
*/
Event<ServerState> SERVER_STOPPING = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STOPPING = EventFactory.createLoop();
/**
* Invoked when server has stopped, equivalent to forge's {@code FMLServerStoppedEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STOPPED}.
*/
Event<ServerState> SERVER_STOPPED = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STOPPED = EventFactory.createLoop();
/**
* Invoked after a world is loaded only on server, equivalent to forge's {@code WorldEvent.Load} and fabric's {@code ServerWorldEvents#LOAD}.
*/
Event<ServerWorldState> SERVER_WORLD_LOAD = EventFactory.createLoop(ServerWorldState.class);
Event<ServerWorldState> SERVER_WORLD_LOAD = EventFactory.createLoop();
/**
* Invoked after a world is unloaded, equivalent to forge's {@code WorldEvent.Unload} and fabric's {@code ServerWorldEvents#UNLOAD}.
*/
Event<ServerWorldState> SERVER_WORLD_UNLOAD = EventFactory.createLoop(ServerWorldState.class);
Event<ServerWorldState> SERVER_WORLD_UNLOAD = EventFactory.createLoop();
/**
* Invoked during a world is saved, equivalent to forge's {@code WorldEvent.Save}.
*/
Event<ServerWorldState> SERVER_WORLD_SAVE = EventFactory.createLoop(ServerWorldState.class);
Event<ServerWorldState> SERVER_WORLD_SAVE = EventFactory.createLoop();
interface InstanceState<T> {
void stateChanged(T instance);

View File

@@ -24,6 +24,7 @@ import me.shedaniel.architectury.event.EventFactory;
import me.shedaniel.architectury.utils.IntValue;
import net.minecraft.advancements.Advancement;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.InteractionResult;
@@ -36,19 +37,20 @@ import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public interface PlayerEvent {
Event<PlayerJoin> PLAYER_JOIN = EventFactory.createLoop(PlayerJoin.class);
Event<PlayerQuit> PLAYER_QUIT = EventFactory.createLoop(PlayerQuit.class);
Event<PlayerRespawn> PLAYER_RESPAWN = EventFactory.createLoop(PlayerRespawn.class);
Event<PlayerAdvancement> PLAYER_ADVANCEMENT = EventFactory.createLoop(PlayerAdvancement.class);
Event<PlayerClone> PLAYER_CLONE = EventFactory.createLoop(PlayerClone.class);
Event<CraftItem> CRAFT_ITEM = EventFactory.createLoop(CraftItem.class);
Event<SmeltItem> SMELT_ITEM = EventFactory.createLoop(SmeltItem.class);
Event<PickupItemPredicate> PICKUP_ITEM_PRE = EventFactory.createInteractionResult(PickupItemPredicate.class);
Event<PickupItem> PICKUP_ITEM_POST = EventFactory.createLoop(PickupItem.class);
Event<DropItem> DROP_ITEM = EventFactory.createLoop(DropItem.class);
Event<OpenMenu> OPEN_MENU = EventFactory.createLoop(OpenMenu.class);
Event<CloseMenu> CLOSE_MENU = EventFactory.createLoop(CloseMenu.class);
Event<BreakBlock> BREAK_BLOCK = EventFactory.createInteractionResult(BreakBlock.class);
Event<PlayerJoin> PLAYER_JOIN = EventFactory.createLoop();
Event<PlayerQuit> PLAYER_QUIT = EventFactory.createLoop();
Event<PlayerRespawn> PLAYER_RESPAWN = EventFactory.createLoop();
Event<PlayerAdvancement> PLAYER_ADVANCEMENT = EventFactory.createLoop();
Event<PlayerClone> PLAYER_CLONE = EventFactory.createLoop();
Event<CraftItem> CRAFT_ITEM = EventFactory.createLoop();
Event<SmeltItem> SMELT_ITEM = EventFactory.createLoop();
Event<PickupItemPredicate> PICKUP_ITEM_PRE = EventFactory.createInteractionResult();
Event<PickupItem> PICKUP_ITEM_POST = EventFactory.createLoop();
Event<ChangeDimension> CHANGE_DIMENSION = EventFactory.createLoop();
Event<DropItem> DROP_ITEM = EventFactory.createLoop();
Event<OpenMenu> OPEN_MENU = EventFactory.createLoop();
Event<CloseMenu> CLOSE_MENU = EventFactory.createLoop();
Event<BreakBlock> BREAK_BLOCK = EventFactory.createInteractionResult();
interface PlayerJoin {
void join(ServerPlayer player);
@@ -86,6 +88,10 @@ public interface PlayerEvent {
void pickup(Player player, ItemEntity entity, ItemStack stack);
}
interface ChangeDimension {
void change(ServerPlayer player, ResourceKey<Level> oldLevel, ResourceKey<Level> newLevel);
}
interface DropItem {
InteractionResult drop(Player player, ItemEntity entity);
}

View File

@@ -27,7 +27,7 @@ import net.minecraft.world.item.crafting.RecipeManager;
@Environment(EnvType.CLIENT)
public interface RecipeUpdateEvent {
Event<RecipeUpdateEvent> EVENT = EventFactory.createLoop(RecipeUpdateEvent.class);
Event<RecipeUpdateEvent> EVENT = EventFactory.createLoop();
void update(RecipeManager recipeManager);
}

View File

@@ -30,8 +30,8 @@ import java.util.function.Consumer;
@Environment(EnvType.CLIENT)
public interface TextureStitchEvent {
Event<Pre> PRE = EventFactory.createLoop(Pre.class);
Event<Post> POST = EventFactory.createLoop(Post.class);
Event<Pre> PRE = EventFactory.createLoop();
Event<Post> POST = EventFactory.createLoop();
@Environment(EnvType.CLIENT)
interface Pre {

View File

@@ -26,12 +26,12 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
public interface TickEvent<T> {
Event<Server> SERVER_PRE = EventFactory.createLoop(Server.class);
Event<Server> SERVER_POST = EventFactory.createLoop(Server.class);
Event<ServerWorld> SERVER_WORLD_PRE = EventFactory.createLoop(ServerWorld.class);
Event<ServerWorld> SERVER_WORLD_POST = EventFactory.createLoop(ServerWorld.class);
Event<Player> PLAYER_PRE = EventFactory.createLoop(Player.class);
Event<Player> PLAYER_POST = EventFactory.createLoop(Player.class);
Event<Server> SERVER_PRE = EventFactory.createLoop();
Event<Server> SERVER_POST = EventFactory.createLoop();
Event<ServerWorld> SERVER_WORLD_PRE = EventFactory.createLoop();
Event<ServerWorld> SERVER_WORLD_POST = EventFactory.createLoop();
Event<Player> PLAYER_PRE = EventFactory.createLoop();
Event<Player> PLAYER_POST = EventFactory.createLoop();
void tick(T instance);

View File

@@ -35,17 +35,17 @@ import java.util.List;
@Environment(EnvType.CLIENT)
public interface TooltipEvent {
Event<Item> ITEM = EventFactory.createLoop(Item.class);
Event<Item> ITEM = EventFactory.createLoop();
/**
* Render vanilla events are not invoked on the forge side.
*/
Event<RenderVanilla> RENDER_VANILLA_PRE = EventFactory.createInteractionResult(RenderVanilla.class);
Event<RenderVanilla> RENDER_VANILLA_PRE = EventFactory.createInteractionResult();
/**
* Render forge events are only invoked on the forge side.
*/
Event<RenderForge> RENDER_FORGE_PRE = EventFactory.createInteractionResult(RenderForge.class);
Event<RenderModifyPosition> RENDER_MODIFY_POSITION = EventFactory.createInteractionResult(RenderModifyPosition.class);
Event<RenderModifyColor> RENDER_MODIFY_COLOR = EventFactory.createInteractionResult(RenderModifyColor.class);
Event<RenderForge> RENDER_FORGE_PRE = EventFactory.createInteractionResult();
Event<RenderModifyPosition> RENDER_MODIFY_POSITION = EventFactory.createInteractionResult();
Event<RenderModifyColor> RENDER_MODIFY_COLOR = EventFactory.createInteractionResult();
@Environment(EnvType.CLIENT)
interface Item {

View File

@@ -36,11 +36,11 @@ public interface ClientChatEvent {
/**
* Invoked when client tries to send a message, equivalent to forge's {@code ClientChatEvent}.
*/
Event<Client> CLIENT = EventFactory.createInteractionResultHolder(Client.class);
Event<Client> CLIENT = EventFactory.createInteractionResultHolder();
/**
* Invoked when client receives a message, equivalent to forge's {@code ClientChatReceivedEvent}.
*/
Event<ClientReceived> CLIENT_RECEIVED = EventFactory.createInteractionResultHolder(ClientReceived.class);
Event<ClientReceived> CLIENT_RECEIVED = EventFactory.createInteractionResultHolder();
@Environment(EnvType.CLIENT)
interface Client {

View File

@@ -32,17 +32,17 @@ public interface ClientLifecycleEvent {
/**
* Invoked when client has been initialised, not available in forge.
*/
@Deprecated Event<ClientState> CLIENT_STARTED = EventFactory.createLoop(ClientState.class);
@Deprecated Event<ClientState> CLIENT_STARTED = EventFactory.createLoop();
/**
* Invoked when client is initialising, not available in forge.
*/
@Deprecated Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop(ClientState.class);
@Deprecated Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop();
/**
* Invoked after a world is loaded only on client, equivalent to forge's {@code WorldEvent.Load}.
*/
Event<ClientWorldState> CLIENT_WORLD_LOAD = EventFactory.createLoop(ClientWorldState.class);
Event<ClientWorldState> CLIENT_WORLD_LOAD = EventFactory.createLoop();
Event<ClientState> CLIENT_SETUP = EventFactory.createLoop();
@Deprecated
@Environment(EnvType.CLIENT)
interface ClientState extends LifecycleEvent.InstanceState<Minecraft> {}

View File

@@ -24,12 +24,13 @@ import me.shedaniel.architectury.event.EventFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.player.LocalPlayer;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public interface ClientPlayerEvent {
Event<ClientPlayerJoin> CLIENT_PLAYER_JOIN = EventFactory.createLoop(ClientPlayerJoin.class);
Event<ClientPlayerQuit> CLIENT_PLAYER_QUIT = EventFactory.createLoop(ClientPlayerQuit.class);
Event<ClientPlayerRespawn> CLIENT_PLAYER_RESPAWN = EventFactory.createLoop(ClientPlayerRespawn.class);
Event<ClientPlayerJoin> CLIENT_PLAYER_JOIN = EventFactory.createLoop();
Event<ClientPlayerQuit> CLIENT_PLAYER_QUIT = EventFactory.createLoop();
Event<ClientPlayerRespawn> CLIENT_PLAYER_RESPAWN = EventFactory.createLoop();
@Environment(EnvType.CLIENT)
interface ClientPlayerJoin {
@@ -38,7 +39,7 @@ public interface ClientPlayerEvent {
@Environment(EnvType.CLIENT)
interface ClientPlayerQuit {
void quit(LocalPlayer player);
void quit(@Nullable LocalPlayer player);
}
@Environment(EnvType.CLIENT)

View File

@@ -0,0 +1,59 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.event.events.client;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.world.InteractionResult;
@Environment(EnvType.CLIENT)
public interface ClientRawInputEvent {
/**
* Invoked after the mouse has scrolled, but doesn't have a screen opened, and in a world, equivalent to forge's {@code InputEvent.MouseScrollEvent}.
*/
Event<MouseScrolled> MOUSE_SCROLLED = EventFactory.createInteractionResult();
/**
* Invoked after the mouse has clicked, before the screen intercepts, equivalent to forge's {@code InputEvent.RawMouseEvent}.
*/
Event<MouseClicked> MOUSE_CLICKED_PRE = EventFactory.createInteractionResult();
/**
* Invoked after the mouse has clicked, after the screen intercepts, equivalent to forge's {@code InputEvent.MouseInputEvent}.
*/
Event<MouseClicked> MOUSE_CLICKED_POST = EventFactory.createInteractionResult();
/**
* Invoked after a key was pressed, after the screen intercepts, equivalent to forge's {@code InputEvent.KeyInputEvent}.
*/
Event<KeyPressed> KEY_PRESSED = EventFactory.createInteractionResult();
interface KeyPressed {
InteractionResult keyPressed(Minecraft client, int keyCode, int scanCode, int action, int modifiers);
}
interface MouseScrolled {
InteractionResult mouseScrolled(Minecraft client, double amount);
}
interface MouseClicked {
InteractionResult mouseClicked(Minecraft client, int button, int action, int mods);
}
}

View File

@@ -29,20 +29,20 @@ import net.minecraft.world.InteractionResult;
@Environment(EnvType.CLIENT)
public interface ClientScreenInputEvent {
Event<MouseScrolled> MOUSE_SCROLLED_PRE = EventFactory.createInteractionResult(MouseScrolled.class);
Event<MouseScrolled> MOUSE_SCROLLED_POST = EventFactory.createInteractionResult(MouseScrolled.class);
Event<MouseClicked> MOUSE_CLICKED_PRE = EventFactory.createInteractionResult(MouseClicked.class);
Event<MouseClicked> MOUSE_CLICKED_POST = EventFactory.createInteractionResult(MouseClicked.class);
Event<MouseReleased> MOUSE_RELEASED_PRE = EventFactory.createInteractionResult(MouseReleased.class);
Event<MouseReleased> MOUSE_RELEASED_POST = EventFactory.createInteractionResult(MouseReleased.class);
Event<MouseDragged> MOUSE_DRAGGED_PRE = EventFactory.createInteractionResult(MouseDragged.class);
Event<MouseDragged> MOUSE_DRAGGED_POST = EventFactory.createInteractionResult(MouseDragged.class);
Event<KeyTyped> CHAR_TYPED_PRE = EventFactory.createInteractionResult(KeyTyped.class);
Event<KeyTyped> CHAR_TYPED_POST = EventFactory.createInteractionResult(KeyTyped.class);
Event<KeyPressed> KEY_PRESSED_PRE = EventFactory.createInteractionResult(KeyPressed.class);
Event<KeyPressed> KEY_PRESSED_POST = EventFactory.createInteractionResult(KeyPressed.class);
Event<KeyReleased> KEY_RELEASED_PRE = EventFactory.createInteractionResult(KeyReleased.class);
Event<KeyReleased> KEY_RELEASED_POST = EventFactory.createInteractionResult(KeyReleased.class);
Event<MouseScrolled> MOUSE_SCROLLED_PRE = EventFactory.createInteractionResult();
Event<MouseScrolled> MOUSE_SCROLLED_POST = EventFactory.createInteractionResult();
Event<MouseClicked> MOUSE_CLICKED_PRE = EventFactory.createInteractionResult();
Event<MouseClicked> MOUSE_CLICKED_POST = EventFactory.createInteractionResult();
Event<MouseReleased> MOUSE_RELEASED_PRE = EventFactory.createInteractionResult();
Event<MouseReleased> MOUSE_RELEASED_POST = EventFactory.createInteractionResult();
Event<MouseDragged> MOUSE_DRAGGED_PRE = EventFactory.createInteractionResult();
Event<MouseDragged> MOUSE_DRAGGED_POST = EventFactory.createInteractionResult();
Event<KeyTyped> CHAR_TYPED_PRE = EventFactory.createInteractionResult();
Event<KeyTyped> CHAR_TYPED_POST = EventFactory.createInteractionResult();
Event<KeyPressed> KEY_PRESSED_PRE = EventFactory.createInteractionResult();
Event<KeyPressed> KEY_PRESSED_POST = EventFactory.createInteractionResult();
Event<KeyReleased> KEY_RELEASED_PRE = EventFactory.createInteractionResult();
Event<KeyReleased> KEY_RELEASED_POST = EventFactory.createInteractionResult();
interface KeyPressed {
InteractionResult keyPressed(Minecraft client, Screen screen, int keyCode, int scanCode, int modifiers);

View File

@@ -28,10 +28,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
@Environment(EnvType.CLIENT)
public interface ClientTickEvent<T> {
Event<Client> CLIENT_PRE = EventFactory.createLoop(Client.class);
Event<Client> CLIENT_POST = EventFactory.createLoop(Client.class);
Event<ClientWorld> CLIENT_WORLD_PRE = EventFactory.createLoop(ClientWorld.class);
Event<ClientWorld> CLIENT_WORLD_POST = EventFactory.createLoop(ClientWorld.class);
Event<Client> CLIENT_PRE = EventFactory.createLoop();
Event<Client> CLIENT_POST = EventFactory.createLoop();
Event<ClientWorld> CLIENT_WORLD_PRE = EventFactory.createLoop();
Event<ClientWorld> CLIENT_WORLD_POST = EventFactory.createLoop();
void tick(T instance);

View File

@@ -0,0 +1,54 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.extensions;
import me.shedaniel.architectury.hooks.BlockEntityHooks;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Extensions to {@link net.minecraft.world.level.block.entity.BlockEntity}, implement this on to your class.
*/
public interface BlockEntityExtension {
/**
* Handles data sent by {@link BlockEntityExtension#saveClientData(CompoundTag)} on the server.
*/
@Environment(EnvType.CLIENT)
void loadClientData(@NotNull BlockState pos, @NotNull CompoundTag tag);
/**
* Writes data to sync to the client.
*/
@NotNull
CompoundTag saveClientData(@NotNull CompoundTag tag);
/**
* Sync data to the clients by {@link BlockEntityExtension#saveClientData(CompoundTag)} and {@link BlockEntityExtension#loadClientData(BlockState, CompoundTag)}.
*/
@ApiStatus.NonExtendable
default void syncData() {
BlockEntityHooks.syncData((BlockEntity) this);
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.ExpectPlatform;
import net.minecraft.world.level.block.entity.BlockEntity;
public class BlockEntityHooks {
private BlockEntityHooks() {}
/**
* Sync data to the clients.
*/
@ExpectPlatform
public static void syncData(BlockEntity entity) {
throw new AssertionError();
}
}

View File

@@ -20,11 +20,8 @@
package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.entity.Entity;
@Environment(EnvType.CLIENT)
public final class EntityHooks {
private EntityHooks() {}

View File

@@ -20,14 +20,11 @@
package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public final class ExplosionHooks {
private ExplosionHooks() {}

View File

@@ -22,9 +22,18 @@ package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.fluid.FluidStack;
import me.shedaniel.architectury.utils.Fraction;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FluidStackHooks {
private FluidStackHooks() {}
@@ -80,4 +89,64 @@ public class FluidStackHooks {
public static Fraction bucketAmount() {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@NotNull FluidStack stack) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@NotNull Fluid fluid) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@NotNull FluidStack stack) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@NotNull Fluid fluid) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
public static int getColor(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
public static int getColor(@NotNull FluidStack stack) {
throw new AssertionError();
}
@ExpectPlatform
@Environment(EnvType.CLIENT)
public static int getColor(@NotNull Fluid fluid) {
throw new AssertionError();
}
}

View File

@@ -21,11 +21,8 @@ package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.utils.IntValue;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.entity.item.ItemEntity;
@Environment(EnvType.CLIENT)
public final class ItemEntityHooks {
private ItemEntityHooks() {}
@@ -38,4 +35,4 @@ public final class ItemEntityHooks {
public static IntValue lifespan(ItemEntity entity) {
throw new AssertionError();
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.hooks;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
public final class ItemStackHooks {
private ItemStackHooks() {}
public static ItemStack copyWithCount(ItemStack stack, int count) {
ItemStack copy = stack.copy();
copy.setCount(count);
return copy;
}
public static void giveItem(ServerPlayer player, ItemStack stack) {
boolean bl = player.inventory.add(stack);
if (bl && stack.isEmpty()) {
stack.setCount(1);
ItemEntity entity = player.drop(stack, false);
if (entity != null) {
entity.makeFakeItem();
}
player.level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, 0.2F, ((player.getRandom().nextFloat() - player.getRandom().nextFloat()) * 0.7F + 1.0F) * 2.0F);
player.inventoryMenu.broadcastChanges();
} else {
ItemEntity entity = player.drop(stack, false);
if (entity != null) {
entity.setNoPickUpDelay();
entity.setOwner(player.getUUID());
}
}
}
}

View File

@@ -17,16 +17,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test;
package me.shedaniel.architectury.hooks;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.level.storage.LevelResource;
public class ConsoleMessageSink implements MessageSink {
protected final Logger logger = LogManager.getLogger("Architectury Test");
public class LevelResourceHooks {
private LevelResourceHooks() {}
@Override
public void accept(String message) {
logger.info(message);
public static LevelResource create(String id) {
return new LevelResource(id);
}
}

View File

@@ -20,11 +20,8 @@
package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.entity.player.Player;
@Environment(EnvType.CLIENT)
public final class PlayerHooks {
private PlayerHooks() {}

View File

@@ -19,11 +19,9 @@
package me.shedaniel.architectury.networking;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import me.shedaniel.architectury.networking.NetworkManager.PacketContext;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
@@ -34,8 +32,9 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
@@ -47,8 +46,7 @@ import java.util.function.Supplier;
*/
public final class NetworkChannel {
private final ResourceLocation id;
private final IntSet takenIds = new IntOpenHashSet();
private final Table<NetworkManager.Side, Class<?>, Pair<ResourceLocation, BiConsumer<?, FriendlyByteBuf>>> encoders = HashBasedTable.create();
private final Map<Class<?>, MessageInfo<?>> encoders = Maps.newHashMap();
private NetworkChannel(ResourceLocation id) {
this.id = id;
@@ -58,57 +56,68 @@ public final class NetworkChannel {
return new NetworkChannel(id);
}
@Deprecated
public <T> void register(NetworkManager.Side side, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(Optional.ofNullable(side), type, encoder, decoder, messageConsumer);
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
public <T> void register(Optional<NetworkManager.Side> side, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
for (int i = 0; true; i++) {
if (!takenIds.contains(i)) {
register(side, i, type, encoder, decoder, messageConsumer);
break;
}
register(type, encoder, decoder, messageConsumer);
}
public <T> void register(Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
String s = StringUtils.leftPad(String.valueOf(hashCodeString(type.toString())), 10, '0');
if (s.length() > 10) s = s.substring(0, 10);
MessageInfo<T> info = new MessageInfo<>(new ResourceLocation(id + "_" + s), encoder, decoder, messageConsumer);
encoders.put(type, info);
NetworkManager.NetworkReceiver receiver = (buf, context) -> {
info.messageConsumer.accept(info.decoder.apply(buf), () -> context);
};
NetworkManager.registerReceiver(NetworkManager.clientToServer(), info.packetId, receiver);
if (Platform.getEnvironment() == Env.CLIENT) {
NetworkManager.registerReceiver(NetworkManager.serverToClient(), info.packetId, receiver);
}
}
public static long hashCodeString(String str) {
long h = 0;
int length = str.length();
for (int i = 0; i < length; i++) {
h = 31 * h + str.charAt(i);
}
return h;
}
@Deprecated
public <T> void register(int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
public <T> void register(NetworkManager.Side side, int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(Optional.ofNullable(side), id, type, encoder, decoder, messageConsumer);
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
public <T> void register(Optional<NetworkManager.Side> side, int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
takenIds.add(id);
ResourceLocation messageId = new ResourceLocation(this.id.getNamespace(), this.id.getPath() + "_" + id);
if (!side.isPresent() || side.get() == NetworkManager.s2c()) {
if (Platform.getEnvironment() == Env.CLIENT) {
NetworkManager.registerReceiver(NetworkManager.s2c(), messageId, (buf, context) -> {
messageConsumer.accept(decoder.apply(buf), () -> context);
});
}
encoders.put(NetworkManager.s2c(), type, Pair.of(messageId, encoder));
}
if (!side.isPresent() || side.get() == NetworkManager.c2s()) {
NetworkManager.registerReceiver(NetworkManager.c2s(), messageId, (buf, context) -> {
messageConsumer.accept(decoder.apply(buf), () -> context);
});
encoders.put(NetworkManager.c2s(), type, Pair.of(messageId, encoder));
}
register(type, encoder, decoder, messageConsumer);
}
private <T> Pair<ResourceLocation, FriendlyByteBuf> encode(NetworkManager.Side side, T message) {
Pair<ResourceLocation, BiConsumer<?, FriendlyByteBuf>> pair = Objects.requireNonNull(encoders.get(side, message.getClass()));
private <T> Pair<MessageInfo<T>, FriendlyByteBuf> encode(T message) {
MessageInfo<T> messageInfo = (MessageInfo<T>) Objects.requireNonNull(encoders.get(message.getClass()));
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
((BiConsumer<T, FriendlyByteBuf>) pair.getRight()).accept(message, buf);
return Pair.of(pair.getLeft(), buf);
messageInfo.encoder.accept(message, buf);
return new Pair<>(messageInfo, buf);
}
public <T> Packet<?> toPacket(NetworkManager.Side side, T message) {
Pair<ResourceLocation, FriendlyByteBuf> encoded = encode(side, message);
return NetworkManager.toPacket(side, encoded.getLeft(), encoded.getRight());
Pair<MessageInfo<T>, FriendlyByteBuf> encoded = encode(message);
return NetworkManager.toPacket(side, encoded.getFirst().packetId, encoded.getSecond());
}
public <T> void sendToPlayer(ServerPlayer player, T message) {
Pair<ResourceLocation, FriendlyByteBuf> encoded = encode(NetworkManager.s2c(), message);
NetworkManager.sendToPlayer(player, encoded.getLeft(), encoded.getRight());
player.connection.send(toPacket(NetworkManager.s2c(), message));
}
public <T> void sendToPlayers(Iterable<ServerPlayer> players, T message) {
@@ -125,10 +134,24 @@ public final class NetworkChannel {
@Environment(EnvType.CLIENT)
public <T> boolean canServerReceive(Class<T> type) {
return NetworkManager.canServerReceive(encoders.get(NetworkManager.c2s(), type).getLeft());
return NetworkManager.canServerReceive(encoders.get(type).packetId);
}
public <T> boolean canPlayerReceive(ServerPlayer player, Class<T> type) {
return NetworkManager.canPlayerReceive(player, encoders.get(NetworkManager.s2c(), type).getLeft());
return NetworkManager.canPlayerReceive(player, encoders.get(type).packetId);
}
private static final class MessageInfo<T> {
private final ResourceLocation packetId;
private final BiConsumer<T, FriendlyByteBuf> encoder;
private final Function<FriendlyByteBuf, T> decoder;
private final BiConsumer<T, Supplier<PacketContext>> messageConsumer;
public MessageInfo(ResourceLocation packetId, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
this.packetId = packetId;
this.encoder = encoder;
this.decoder = decoder;
this.messageConsumer = messageConsumer;
}
}
}

View File

@@ -27,17 +27,40 @@ import net.minecraft.client.color.item.ItemColor;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import java.util.Objects;
import java.util.function.Supplier;
@Environment(EnvType.CLIENT)
public final class ColorHandlers {
private ColorHandlers() {}
@ExpectPlatform
public static void registerItemColors(ItemColor color, ItemLike... items) {
Supplier<ItemLike>[] array = new Supplier[items.length];
for (int i = 0; i < items.length; i++) {
ItemLike item = Objects.requireNonNull(items[i], "items[i] is null!");
array[i] = () -> item;
}
registerItemColors(color, array);
}
public static void registerBlockColors(BlockColor color, Block... blocks) {
Supplier<Block>[] array = new Supplier[blocks.length];
for (int i = 0; i < blocks.length; i++) {
Block block = Objects.requireNonNull(blocks[i], "blocks[i] is null!");
array[i] = () -> block;
}
registerBlockColors(color, array);
}
@SafeVarargs
@ExpectPlatform
public static void registerItemColors(ItemColor color, Supplier<ItemLike>... items) {
throw new AssertionError();
}
@SafeVarargs
@ExpectPlatform
public static void registerBlockColors(BlockColor color, Block... blocks) {
public static void registerBlockColors(BlockColor color, Supplier<Block>... blocks) {
throw new AssertionError();
}
}

View File

@@ -70,7 +70,7 @@ public class DeferredRegister<T> {
return create(registries::get, key);
}
public RegistrySupplier<T> register(String id, Supplier<T> supplier) {
public <R extends T> RegistrySupplier<R> register(String id, Supplier<? extends R> supplier) {
if (modId == null) {
throw new NullPointerException("You must create the deferred register with a mod id to register entries without the namespace!");
}
@@ -78,14 +78,14 @@ public class DeferredRegister<T> {
return register(new ResourceLocation(modId, id), supplier);
}
public RegistrySupplier<T> register(ResourceLocation id, Supplier<T> supplier) {
Entry<T> entry = new Entry<>(id, supplier);
public <R extends T> RegistrySupplier<R> register(ResourceLocation id, Supplier<? extends R> supplier) {
Entry<T> entry = new Entry<>(id, (Supplier<T>) supplier);
this.entries.add(entry);
if (registered) {
Registry<T> registry = registriesSupplier.get().get(key);
entry.value = registry.registerSupplied(entry.id, entry.supplier);
}
return entry;
return (RegistrySupplier<R>) entry;
}
public void register() {

View File

@@ -0,0 +1,79 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameRules;
import java.util.function.BiConsumer;
/**
* A utility class for creating game rule types.
*/
public final class GameRuleFactory {
private GameRuleFactory() {}
/**
* Creates a boolean rule type.
*
* @param defaultValue the rule's default value
* @return the created type
*/
@ExpectPlatform
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
throw new AssertionError();
}
/**
* Creates a boolean rule type.
*
* @param defaultValue the rule's default value
* @param changedCallback a callback that is called when the rule's value is changed
* @return the created type
*/
@ExpectPlatform
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changedCallback) {
throw new AssertionError();
}
/**
* Creates an integer rule type.
*
* @param defaultValue the rule's default value
* @return the created type
*/
@ExpectPlatform
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue) {
throw new AssertionError();
}
/**
* Creates an integer rule type.
*
* @param defaultValue the rule's default value
* @param changedCallback a callback that is called when the rule's value is changed
* @return the created type
*/
@ExpectPlatform
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changedCallback) {
throw new AssertionError();
}
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.level.GameRules;
/**
* A registry for registering game rules.
*/
public final class GameRuleRegistry {
private GameRuleRegistry() {}
/**
* Registers a game rule.
*
* @param name the rule's name
* @param category the rule category
* @param type the type of the rule
* @param <T> the type of the rule value
* @return a key for the registered rule
*/
@ExpectPlatform
public static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
throw new AssertionError();
}
}

View File

@@ -20,9 +20,12 @@
package me.shedaniel.architectury.registry;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.core.RegistryEntry;
import me.shedaniel.architectury.registry.registries.RegistryBuilder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
@@ -36,6 +39,7 @@ public final class Registries {
private final RegistryProvider provider;
private final String modId;
@NotNull
public static Registries get(String modId) {
return REGISTRIES.computeIfAbsent(modId, Registries::new);
}
@@ -45,15 +49,24 @@ public final class Registries {
this.modId = modId;
}
@NotNull
public <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key) {
return this.provider.get(key);
}
@NotNull
@Deprecated
public <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
return this.provider.get(registry);
}
@NotNull
@SafeVarargs
public final <T extends RegistryEntry<T>> RegistryBuilder<T> builder(ResourceLocation registryId, T... typeGetter) {
if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
return this.provider.builder((Class<T>) typeGetter.getClass().getComponentType(), registryId);
}
/**
* Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null
* Fabric: Use registry
@@ -79,8 +92,8 @@ public final class Registries {
* Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null
* Fabric: null
*/
@Deprecated
@Nullable
@Deprecated
public static <T> ResourceLocation getRegistryName(T object) {
return getId(object, (ResourceKey<net.minecraft.core.Registry<T>>) null);
}
@@ -90,6 +103,7 @@ public final class Registries {
throw new AssertionError();
}
@NotNull
public String getModId() {
return modId;
}
@@ -100,5 +114,7 @@ public final class Registries {
@Deprecated
<T> Registry<T> get(net.minecraft.core.Registry<T> registry);
<T extends RegistryEntry<T>> RegistryBuilder<T> builder(Class<T> type, ResourceLocation registryId);
}
}

View File

@@ -49,11 +49,16 @@ public interface Registry<T> extends Iterable<T> {
@Nullable
ResourceLocation getId(T obj);
int getRawId(T obj);
Optional<ResourceKey<T>> getKey(T obj);
@Nullable
T get(ResourceLocation id);
@Nullable
T byRawId(int rawId);
boolean contains(ResourceLocation id);
boolean containsValue(T obj);

View File

@@ -29,12 +29,21 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
public interface RegistrySupplier<T> extends Supplier<T> {
/**
* @return the identifier of the registry
*/
@NotNull
ResourceLocation getRegistryId();
/**
* @return the identifier of the entry
*/
@NotNull
ResourceLocation getId();
/**
* @return whether the entry has been registered
*/
boolean isPresent();
@Nullable

View File

@@ -39,6 +39,5 @@ public final class RenderTypes {
public static void register(RenderType type, Fluid... fluids) {
throw new AssertionError();
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.registries;
import me.shedaniel.architectury.core.RegistryEntry;
import me.shedaniel.architectury.registry.Registry;
import org.jetbrains.annotations.NotNull;
public interface RegistryBuilder<T extends RegistryEntry<T>> {
@NotNull
Registry<T> build();
@NotNull
RegistryBuilder<T> option(@NotNull RegistryOption option);
@NotNull
default RegistryBuilder<T> saveToDisc() {
return option(StandardRegistryOption.SAVE_TO_DISC);
}
@NotNull
default RegistryBuilder<T> syncToClients() {
return option(StandardRegistryOption.SYNC_TO_CLIENTS);
}
}

View File

@@ -0,0 +1,23 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.registries;
public interface RegistryOption {
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.registry.registries;
public enum StandardRegistryOption implements RegistryOption {
/**
* Denote that the registry should save to disc and persist. Defaulted false.
*/
SAVE_TO_DISC,
/**
* Denote that the registry should sync its contents to clients. Defaulted false.
*/
SYNC_TO_CLIENTS,
}

View File

@@ -38,4 +38,5 @@ mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientMoodSet
accessible field net/minecraft/world/level/biome/BiomeSpecialEffects ambientAdditionsSettings Ljava/util/Optional;
mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientAdditionsSettings Ljava/util/Optional;
accessible field net/minecraft/world/level/biome/BiomeSpecialEffects backgroundMusic Ljava/util/Optional;
mutable field net/minecraft/world/level/biome/BiomeSpecialEffects backgroundMusic Ljava/util/Optional;
mutable field net/minecraft/world/level/biome/BiomeSpecialEffects backgroundMusic Ljava/util/Optional;
accessible method net/minecraft/world/level/storage/LevelResource <init> (Ljava/lang/String;)V

View File

@@ -1,260 +0,0 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test;
import com.mojang.blaze3d.platform.InputConstants;
import me.shedaniel.architectury.event.events.*;
import me.shedaniel.architectury.event.events.client.ClientChatEvent;
import me.shedaniel.architectury.event.events.client.ClientScreenInputEvent;
import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent;
import me.shedaniel.architectury.event.events.client.ClientPlayerEvent;
import me.shedaniel.architectury.hooks.ExplosionHooks;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.test.client.ClientOverlayMessageSink;
import me.shedaniel.architectury.utils.Env;
import me.shedaniel.architectury.utils.EnvExecutor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.core.Position;
import net.minecraft.core.Vec3i;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import java.util.Optional;
public class TestMod {
public static final MessageSink SINK = EnvExecutor.getEnvSpecific(() -> ClientOverlayMessageSink::new, () -> ConsoleMessageSink::new);
public static void initialize() {
debugEvents();
if (Platform.getEnvironment() == Env.CLIENT)
debugEventsClient();
}
public static void debugEvents() {
ChatEvent.SERVER.register((player, message, component) -> {
SINK.accept("Server chat received: " + message);
return InteractionResultHolder.pass(component);
});
CommandPerformEvent.EVENT.register(event -> {
SINK.accept("Server command performed: " + event.getResults().getReader().getString());
return InteractionResult.PASS;
});
CommandRegistrationEvent.EVENT.register((dispatcher, selection) -> {
SINK.accept("Server commands registers");
});
EntityEvent.LIVING_DEATH.register((entity, source) -> {
if (entity instanceof Player) {
SINK.accept(entity.getScoreboardName() + " died to " + source.getMsgId() + logSide(entity.level));
}
return InteractionResult.PASS;
});
EntityEvent.LIVING_ATTACK.register((entity, source, amount) -> {
if (source.getDirectEntity() instanceof Player) {
SINK.accept(source.getDirectEntity().getScoreboardName() + " deals %.2f damage" + logSide(entity.level), amount);
}
return InteractionResult.PASS;
});
EntityEvent.ADD.register((entity, level) -> {
if (entity instanceof Player) {
SINK.accept(entity.getScoreboardName() + " was added to " + level.dimension().location().toString() + logSide(level));
}
return InteractionResult.PASS;
});
EntityEvent.PLACE_BLOCK.register((world, pos, state, placer) -> {
SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world));
return InteractionResult.PASS;
});
ExplosionEvent.DETONATE.register((world, explosion, affectedEntities) -> {
SINK.accept(world.dimension().location() + " explodes at " + toShortString(ExplosionHooks.getPosition(explosion)) + logSide(world));
});
InteractionEvent.LEFT_CLICK_BLOCK.register((player, hand, pos, face) -> {
SINK.accept(player.getScoreboardName() + " left clicks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
InteractionEvent.RIGHT_CLICK_BLOCK.register((player, hand, pos, face) -> {
SINK.accept(player.getScoreboardName() + " right clicks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
InteractionEvent.RIGHT_CLICK_ITEM.register((player, hand) -> {
SINK.accept(player.getScoreboardName() + " uses " + (hand == InteractionHand.MAIN_HAND ? "main hand" : "off hand") + logSide(player.level));
return InteractionResultHolder.pass(player.getItemInHand(hand));
});
InteractionEvent.INTERACT_ENTITY.register((player, entity, hand) -> {
SINK.accept(player.getScoreboardName() + " interacts with " + entity.getScoreboardName() + " using " + (hand == InteractionHand.MAIN_HAND ? "main hand" : "off hand") + logSide(player.level));
return InteractionResult.PASS;
});
LifecycleEvent.SERVER_BEFORE_START.register(instance -> {
SINK.accept("Server ready to start");
});
LifecycleEvent.SERVER_STARTING.register(instance -> {
SINK.accept("Server starting");
});
LifecycleEvent.SERVER_STARTED.register(instance -> {
SINK.accept("Server started");
});
LifecycleEvent.SERVER_STOPPING.register(instance -> {
SINK.accept("Server stopping");
});
LifecycleEvent.SERVER_STOPPED.register(instance -> {
SINK.accept("Server stopped");
});
LifecycleEvent.SERVER_WORLD_LOAD.register(instance -> {
SINK.accept("Server world loaded: " + instance.dimension().location());
});
LifecycleEvent.SERVER_WORLD_UNLOAD.register(instance -> {
SINK.accept("Server world unloaded: " + instance.dimension().location());
});
LifecycleEvent.SERVER_WORLD_SAVE.register(instance -> {
SINK.accept("Server world saved: " + instance.dimension().location());
});
PlayerEvent.PLAYER_JOIN.register(player -> {
SINK.accept(player.getScoreboardName() + " joined" + logSide(player.level));
});
PlayerEvent.PLAYER_QUIT.register(player -> {
SINK.accept(player.getScoreboardName() + " quit" + logSide(player.level));
});
PlayerEvent.PLAYER_RESPAWN.register((player, conqueredEnd) -> {
if (!conqueredEnd) {
SINK.accept(player.getScoreboardName() + " respawns " + logSide(player.level));
}
});
PlayerEvent.PLAYER_CLONE.register((oldPlayer, newPlayer, wonGame) -> {
SINK.accept("Player cloned: " + newPlayer.getScoreboardName() + logSide(newPlayer.level));
});
PlayerEvent.PLAYER_ADVANCEMENT.register((player, advancement) -> {
SINK.accept(player.getScoreboardName() + " was awarded with %s" + logSide(player.level), advancement.getChatComponent().getString());
});
PlayerEvent.CRAFT_ITEM.register((player, constructed, inventory) -> {
SINK.accept(player.getScoreboardName() + " crafts " + new TranslatableComponent(constructed.getDescriptionId()).getString() + logSide(player.level));
});
PlayerEvent.SMELT_ITEM.register((player, smelted) -> {
SINK.accept(player.getScoreboardName() + " smelts " + new TranslatableComponent(smelted.getDescriptionId()).getString() + logSide(player.level));
});
PlayerEvent.PICKUP_ITEM_POST.register((player, entity, stack) -> {
SINK.accept(player.getScoreboardName() + " picks up " + new TranslatableComponent(stack.getDescriptionId()).getString() + logSide(player.level));
});
PlayerEvent.DROP_ITEM.register((player, entity) -> {
SINK.accept(player.getScoreboardName() + " drops " + new TranslatableComponent(entity.getItem().getDescriptionId()).getString() + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.BREAK_BLOCK.register((world, pos, state, player, xp) -> {
SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.OPEN_MENU.register((player, menu) -> {
SINK.accept(player.getScoreboardName() + " opens " + toSimpleName(menu) + logSide(player.level));
});
PlayerEvent.CLOSE_MENU.register((player, menu) -> {
SINK.accept(player.getScoreboardName() + " closes " + toSimpleName(menu) + logSide(player.level));
});
}
public static String toShortString(Vec3i pos) {
return pos.getX() + ", " + pos.getY() + ", " + pos.getZ();
}
public static String toShortString(Position pos) {
return pos.x() + ", " + pos.y() + ", " + pos.z();
}
public static String logSide(Level level) {
if (level.isClientSide())
return " (client)";
return " (server)";
}
@Environment(EnvType.CLIENT)
public static void debugEventsClient() {
ClientChatEvent.CLIENT.register(message -> {
SINK.accept("Client chat sent: " + message);
return InteractionResultHolder.pass(message);
});
ClientChatEvent.CLIENT_RECEIVED.register((type, message, sender) -> {
SINK.accept("Client chat received: " + message.getString());
return InteractionResultHolder.pass(message);
});
ClientLifecycleEvent.CLIENT_WORLD_LOAD.register(world -> {
SINK.accept("Client world loaded: " + world.dimension().location().toString());
});
ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(player -> {
SINK.accept(player.getScoreboardName() + " joined (client)");
});
ClientPlayerEvent.CLIENT_PLAYER_QUIT.register(player -> {
SINK.accept(player.getScoreboardName() + " quit (client)");
});
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.register((oldPlayer, newPlayer) -> {
SINK.accept(newPlayer.getScoreboardName() + " respawned (client)");
});
GuiEvent.INIT_PRE.register((screen, widgets, children) -> {
SINK.accept(toSimpleName(screen) + " initializes");
return InteractionResult.PASS;
});
InteractionEvent.CLIENT_LEFT_CLICK_AIR.register((player, hand) -> {
SINK.accept(player.getScoreboardName() + " left clicks air" + logSide(player.level));
});
InteractionEvent.CLIENT_RIGHT_CLICK_AIR.register((player, hand) -> {
SINK.accept(player.getScoreboardName() + " right clicks air" + logSide(player.level));
});
RecipeUpdateEvent.EVENT.register(recipeManager -> {
SINK.accept("Client recipes received");
});
TextureStitchEvent.POST.register(atlas -> {
SINK.accept("Client texture stitched: " + atlas.location());
});
ClientScreenInputEvent.MOUSE_SCROLLED_PRE.register((client, screen, mouseX, mouseY, amount) -> {
SINK.accept("Screen Mouse amount: %.2f distance", amount);
return InteractionResult.PASS;
});
ClientScreenInputEvent.MOUSE_CLICKED_PRE.register((client, screen, mouseX, mouseY, button) -> {
SINK.accept("Screen Mouse clicked: " + button);
return InteractionResult.PASS;
});
ClientScreenInputEvent.MOUSE_RELEASED_PRE.register((client, screen, mouseX, mouseY, button) -> {
SINK.accept("Screen Mouse released: " + button);
return InteractionResult.PASS;
});
ClientScreenInputEvent.MOUSE_DRAGGED_PRE.register((client, screen, mouseX1, mouseY1, button, mouseX2, mouseY2) -> {
SINK.accept("Screen Mouse dragged: %d (%d,%d) by (%d,%d)", button, (int) mouseX1, (int) mouseY1, (int) mouseX2, (int) mouseY2);
return InteractionResult.PASS;
});
ClientScreenInputEvent.CHAR_TYPED_PRE.register((client, screen, character, keyCode) -> {
SINK.accept("Screen Char typed: " + character);
return InteractionResult.PASS;
});
ClientScreenInputEvent.KEY_PRESSED_PRE.register((client, screen, keyCode, scanCode, modifiers) -> {
SINK.accept("Screen Key pressed: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString());
return InteractionResult.PASS;
});
ClientScreenInputEvent.KEY_RELEASED_PRE.register((client, screen, keyCode, scanCode, modifiers) -> {
SINK.accept("Screen Key released: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString());
return InteractionResult.PASS;
});
}
private static String toSimpleName(Object o) {
return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode());
}
}

View File

@@ -1,101 +0,0 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test.client;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import me.shedaniel.architectury.event.events.GuiEvent;
import me.shedaniel.architectury.test.ConsoleMessageSink;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.util.Mth;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@Environment(EnvType.CLIENT)
public class ClientOverlayMessageSink extends ConsoleMessageSink {
private final List<Message> messages = Collections.synchronizedList(Lists.newArrayList());
public ClientOverlayMessageSink() {
GuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> render(matrices, delta));
GuiEvent.RENDER_HUD.register((matrices, tickDelta) -> {
if (Minecraft.getInstance().screen == null && !Minecraft.getInstance().options.renderDebug) {
render(matrices, tickDelta);
}
});
}
@Override
public void accept(String message) {
super.accept(message);
messages.add(0, new Message(new TextComponent(message), Util.getMillis()));
}
public void render(PoseStack matrices, float delta) {
Minecraft minecraft = Minecraft.getInstance();
long currentMills = Util.getMillis();
int lineHeight = minecraft.font.lineHeight;
synchronized (messages) {
Iterator<Message> messageIterator = messages.iterator();
int y = 1;
RenderSystem.enableBlend();
while (messageIterator.hasNext()) {
Message message = messageIterator.next();
int timeExisted = (int) (currentMills - message.created);
if (timeExisted >= 5000) {
messageIterator.remove();
} else {
if (y - 1 < minecraft.getWindow().getGuiScaledHeight()) {
int textWidth = minecraft.font.width(message.text);
int alpha = (int) Mth.clamp((5000 - timeExisted) / 5000f * 400f + 8, 0, 255);
GuiComponent.fill(matrices, 0, y - 1, 2 + textWidth + 1, y + lineHeight - 1, 0x505050 + ((alpha * 144 / 255) << 24));
minecraft.font.draw(matrices, message.text, 1, y, 0xE0E0E0 + (alpha << 24));
}
y += lineHeight;
}
}
}
RenderSystem.disableAlphaTest();
RenderSystem.disableBlend();
}
private static class Message {
private final Component text;
private final long created;
public Message(Component text, long created) {
this.text = text;
this.created = created;
}
}
}

View File

@@ -1,17 +0,0 @@
{
"schemaVersion": 1,
"id": "architectury-test",
"version": "${version}",
"name": "Architectury Test",
"description": "A intermediary api aimed to ease developing multiplatform mods.",
"authors": [
"shedaniel"
],
"license": "LGPL-3",
"environment": "*",
"entrypoints": {
"main": [
"me.shedaniel.architectury.test.TestMod::initialize"
]
}
}