Refactor and 1.17-pre1 (#96)

* Fix #94

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Add Chunk data save and load events, closes #89 (#92)

* Created Chunk save and load event. Closes #89

* Fixed missing licence

* Update common/src/main/java/me/shedaniel/architectury/event/events/ChunkEvent.java

* Update common/src/main/java/me/shedaniel/architectury/event/events/ChunkEvent.java

* Update common/src/main/java/me/shedaniel/architectury/event/events/ChunkEvent.java

* Supply ServerLevel in ChunkEvent.LOAD, style cleanup

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Add "Data" suffix to Chunk IO Events and mark level as nullable for load

* Update common/src/main/java/me/shedaniel/architectury/event/events/ChunkEvent.java

* Bump to 1.16

Co-authored-by: shedaniel <daniel@shedaniel.me>
Co-authored-by: Max <maxh2709@gmail.com>

* Update pr.yml

* Add NetworkManager hook for Entity spawn packets (#88)

* New utility hook for creating a entity spawn packet. before every mod had to implement this in itself.

* Apply suggestions from code review

Co-authored-by: shedaniel <daniel@shedaniel.me>

* Update common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java

* Update common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java

* Properly implement SpawnEntityPacket & Format style

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Format

Signed-off-by: shedaniel <daniel@shedaniel.me>

* createEntitySpawnPacket -> createAddEntityPacket for mojmap consistency

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Bump version to 1.17

Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: shedaniel <daniel@shedaniel.me>

* Add Javadocs for all events (#91)

* javadoc for ClientChatEvent

* javadoc for ClientPlayerEvent

* javadoc for ClientRawInputEvent

* Added javadoc for ClientScreenInputEvent

* Bit refactoring and removed javadoc @see to the caller methods

* Add javadoc for BlockEvent

* Add javadoc for ChatEvent

* Add javadoc for CommandPerformEvent and CommandRegistrationEvent

* Add javadoc for EntityEvent

* Add javadoc for ExplosionEvent

* Add javadoc for GuiEvent

* Add javadoc for InteractionEvent

* Add javadoc for LightningEvent, RecipeUpdateEvent & TextureStitchEvent

* Add javadoc for LifecycleEvent & ClientLifecycleEvent

* Add javadoc for TooltipEvent

* Add javadoc for TickEvent and partly PlayerEvent

* More javadoc for PlayerEvent

* Finally all event have javadoc

* Update common/src/main/java/me/shedaniel/architectury/event/events/CommandPerformEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/CommandPerformEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/CommandPerformEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/ChatEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/CommandRegistrationEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/client/ClientScreenInputEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/client/ClientScreenInputEvent.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/BlockEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/BlockEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/BlockEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/BlockEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Update common/src/main/java/me/shedaniel/architectury/event/events/PlayerEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Apply suggestions from code review

Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
Co-authored-by: Max <maxh2709@gmail.com>

* Apply suggestions from code review

Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: shedaniel <daniel@shedaniel.me>

* Applied some more reviews

* Applied some more reviews

* Applied suggestions

* Reformat and apply some minor suggestions

* Apply suggestions from review (first batch)

* Remove double return javadoc

* Apply suggestions from code review

Co-authored-by: shedaniel <daniel@shedaniel.me>

* Add "scaled" to mouse coordinates

* Final touches

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Remove invalid tips

Signed-off-by: shedaniel <daniel@shedaniel.me>

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: shedaniel <daniel@shedaniel.me>

* Refactor

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Update common/src/main/java/dev/architectury/event/events/common/InteractionEvent.java

Co-authored-by: Max <maxh2709@gmail.com>

* Apply suggestions from code review

Co-authored-by: Max <maxh2709@gmail.com>

* attack -> hurt

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Update @param for InteractionEvent#FARMLAND_TRAMPLE

Signed-off-by: shedaniel <daniel@shedaniel.me>

* world -> level

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Relocate hooks

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Organize imports

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Registry -> Registrar Please voice out your opinion!!

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Some more renames
itemOptional -> optionalItem
RegistryBuilder -> RegistrarBuilder
RegistryOption -> RegistrarOption
Not forcing RegistryEntry on new registries, vanilla types don't have them

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Java 16-ification

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Optimise imports after the var change

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Un-minimize architectury-common.mixins.json

Signed-off-by: shedaniel <daniel@shedaniel.me>

Co-authored-by: canitzp <12819060+canitzp@users.noreply.github.com>
Co-authored-by: Max <maxh2709@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
This commit is contained in:
shedaniel
2021-05-30 19:08:11 +08:00
committed by GitHub
parent 28867f012d
commit 8b262d07c0
229 changed files with 3529 additions and 2354 deletions

View File

@@ -0,0 +1,45 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.compat.fabric;
import com.google.common.collect.Maps;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import dev.architectury.platform.fabric.PlatformImpl;
import java.util.Map;
public class ModMenuCompatibility implements ModMenuApi {
private static final Map<String, ConfigScreenFactory<?>> FACTORIES = Maps.newHashMap();
@Override
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
validateMap();
return FACTORIES;
}
private void validateMap() {
for (var entry : PlatformImpl.CONFIG_SCREENS.entrySet()) {
if (!FACTORIES.containsKey(entry.getKey())) {
FACTORIES.put(entry.getKey(), entry.getValue()::provide);
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.event.fabric;
import dev.architectury.event.Event;
import dev.architectury.event.EventActor;
import org.jetbrains.annotations.ApiStatus;
import java.util.function.Consumer;
public class EventFactoryImpl {
public static <T> Event<Consumer<T>> attachToForge(Event<Consumer<T>> event) {
return event;
}
@ApiStatus.Internal
public static <T> Event<EventActor<T>> attachToForgeEventActor(Event<EventActor<T>> event) {
return event;
}
@ApiStatus.Internal
public static <T> Event<EventActor<T>> attachToForgeEventActorCancellable(Event<EventActor<T>> event) {
return event;
}
}

View File

@@ -0,0 +1,85 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.event.fabric;
import dev.architectury.event.events.client.ClientGuiEvent;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.event.events.client.ClientTickEvent;
import dev.architectury.event.events.client.ClientTooltipEvent;
import dev.architectury.event.events.common.CommandRegistrationEvent;
import dev.architectury.event.events.common.InteractionEvent;
import dev.architectury.event.events.common.LifecycleEvent;
import dev.architectury.event.events.common.TickEvent;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
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.commands.Commands;
public class EventHandlerImpl {
@Environment(EnvType.CLIENT)
public static void registerClient() {
ClientLifecycleEvents.CLIENT_STARTED.register(instance -> ClientLifecycleEvent.CLIENT_STARTED.invoker().stateChanged(instance));
ClientLifecycleEvents.CLIENT_STOPPING.register(instance -> ClientLifecycleEvent.CLIENT_STOPPING.invoker().stateChanged(instance));
ClientTickEvents.START_CLIENT_TICK.register(instance -> ClientTickEvent.CLIENT_PRE.invoker().tick(instance));
ClientTickEvents.END_CLIENT_TICK.register(instance -> ClientTickEvent.CLIENT_POST.invoker().tick(instance));
ClientTickEvents.START_WORLD_TICK.register(instance -> ClientTickEvent.CLIENT_LEVEL_PRE.invoker().tick(instance));
ClientTickEvents.END_WORLD_TICK.register(instance -> ClientTickEvent.CLIENT_LEVEL_POST.invoker().tick(instance));
ItemTooltipCallback.EVENT.register((itemStack, tooltipFlag, list) -> ClientTooltipEvent.ITEM.invoker().append(itemStack, list, tooltipFlag));
HudRenderCallback.EVENT.register((matrices, tickDelta) -> ClientGuiEvent.RENDER_HUD.invoker().renderHud(matrices, tickDelta));
}
public static void registerCommon() {
ServerLifecycleEvents.SERVER_STARTING.register(instance -> LifecycleEvent.SERVER_BEFORE_START.invoker().stateChanged(instance));
ServerLifecycleEvents.SERVER_STARTED.register(instance -> LifecycleEvent.SERVER_STARTED.invoker().stateChanged(instance));
ServerLifecycleEvents.SERVER_STOPPING.register(instance -> LifecycleEvent.SERVER_STOPPING.invoker().stateChanged(instance));
ServerLifecycleEvents.SERVER_STOPPED.register(instance -> LifecycleEvent.SERVER_STOPPED.invoker().stateChanged(instance));
ServerTickEvents.START_SERVER_TICK.register(instance -> TickEvent.SERVER_PRE.invoker().tick(instance));
ServerTickEvents.END_SERVER_TICK.register(instance -> TickEvent.SERVER_POST.invoker().tick(instance));
ServerTickEvents.START_WORLD_TICK.register(instance -> TickEvent.SERVER_LEVEL_PRE.invoker().tick(instance));
ServerTickEvents.END_WORLD_TICK.register(instance -> TickEvent.SERVER_LEVEL_POST.invoker().tick(instance));
ServerWorldEvents.LOAD.register((server, world) -> LifecycleEvent.SERVER_LEVEL_LOAD.invoker().act(world));
ServerWorldEvents.UNLOAD.register((server, world) -> LifecycleEvent.SERVER_LEVEL_UNLOAD.invoker().act(world));
CommandRegistrationCallback.EVENT.register((commandDispatcher, b) -> CommandRegistrationEvent.EVENT.invoker().register(commandDispatcher, b ? Commands.CommandSelection.DEDICATED : Commands.CommandSelection.INTEGRATED));
UseItemCallback.EVENT.register((player, world, hand) -> InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(player, hand).asMinecraft());
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(player, hand, hitResult.getBlockPos(), hitResult.getDirection()).asMinecraft());
AttackBlockCallback.EVENT.register((player, world, hand, pos, face) -> InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(player, hand, pos, face).asMinecraft());
}
@Environment(EnvType.SERVER)
public static void registerServer() {
}
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.block.fabric;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Objects;
public class BlockEntityHooksImpl {
/*
* Copyright (c) 2016, 2017, 2018, 2019 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.
*/
public static void syncData(BlockEntity entity) {
if (entity instanceof BlockEntityClientSerializable) {
((BlockEntityClientSerializable) entity).sync();
} else {
var world = Objects.requireNonNull(entity.getLevel());
if (!(world instanceof ServerLevel)) {
throw new IllegalStateException("Cannot call sync() on the logical client! Did you check world.isClient first?");
} else {
((ServerLevel) world).getChunkSource().blockChanged(entity.getBlockPos());
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.client.screen.fabric;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Widget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import java.util.List;
@Environment(EnvType.CLIENT)
public class ScreenHooksImpl {
public static List<NarratableEntry> getNarratables(Screen screen) {
return screen.narratables;
}
public static List<Widget> getRenderables(Screen screen) {
return screen.renderables;
}
public static <T extends AbstractWidget & Widget & NarratableEntry> T addRenderableWidget(Screen screen, T widget) {
return screen.addRenderableWidget(widget);
}
public static <T extends Widget> T addRenderableOnly(Screen screen, T listener) {
return screen.addRenderableOnly(listener);
}
public static <T extends GuiEventListener & NarratableEntry> T addWidget(Screen screen, T listener) {
return screen.addWidget(listener);
}
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.fabric;
import net.minecraft.world.item.DyeColor;
public class DyeColorHooksImpl {
public static int getColorValue(DyeColor color) {
var colors = color.getTextureDiffuseColors();
return ((int) (colors[0] * 255.0F + 0.5D) & 255) << 16 | ((int) (colors[1] * 255.0F + 0.5D) & 255) << 8 | (int) (colors[2] * 255.0F + 0.5D);
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.fabric;
import com.google.common.collect.ImmutableSet;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.RepositorySource;
import java.util.ArrayList;
import java.util.List;
public class PackRepositoryHooksImpl {
public static void addSource(PackRepository repository, RepositorySource source) {
List<RepositorySource> set = new ArrayList<>(repository.sources);
set.add(source);
repository.sources = ImmutableSet.copyOf(set);
}
}

View File

@@ -0,0 +1,26 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.fabric;
import net.minecraft.server.level.ServerLevel;
public interface PersistentEntitySectionManagerHooks {
void architectury_attachLevel(ServerLevel level);
}

View File

@@ -0,0 +1,191 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.fluid.fabric;
import dev.architectury.fluid.FluidStack;
import dev.architectury.platform.Platform;
import dev.architectury.utils.Env;
import dev.architectury.utils.NbtType;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class FluidStackHooksImpl {
public static Component getName(FluidStack stack) {
if (Platform.getEnvironment() == Env.CLIENT) {
return getNameClient(stack);
}
return new TranslatableComponent(getTranslationKey(stack));
}
@Environment(EnvType.CLIENT)
private static Component getNameClient(FluidStack stack) {
return stack.getFluid().defaultFluidState().createLegacyBlock().getBlock().getName();
}
public static String getTranslationKey(FluidStack stack) {
var id = Registry.FLUID.getKey(stack.getFluid());
return "block." + id.getNamespace() + "." + id.getPath();
}
public static FluidStack read(FriendlyByteBuf buf) {
var fluid = Objects.requireNonNull(Registry.FLUID.get(buf.readResourceLocation()));
var amount = buf.readVarLong();
var tag = buf.readNbt();
if (fluid == Fluids.EMPTY) return FluidStack.empty();
return FluidStack.create(fluid, amount, tag);
}
public static void write(FluidStack stack, FriendlyByteBuf buf) {
buf.writeResourceLocation(Registry.FLUID.getKey(stack.getFluid()));
buf.writeVarLong(stack.getAmount());
buf.writeNbt(stack.getTag());
}
public static FluidStack read(CompoundTag tag) {
if (tag == null || !tag.contains("id", NbtType.STRING)) {
return FluidStack.empty();
}
var fluid = Registry.FLUID.get(new ResourceLocation(tag.getString("id")));
if (fluid == null || fluid == Fluids.EMPTY) {
return FluidStack.empty();
}
var amount = tag.getLong("amount");
var stack = FluidStack.create(fluid, amount);
if (tag.contains("tag", NbtType.COMPOUND)) {
stack.setTag(tag.getCompound("tag"));
}
return stack;
}
public static CompoundTag write(FluidStack stack, CompoundTag tag) {
tag.putString("id", Registry.FLUID.getKey(stack.getFluid()).toString());
tag.putLong("amount", stack.getAmount());
if (stack.hasTag()) {
tag.put("tag", stack.getTag());
}
return tag;
}
public static long bucketAmount() {
return 81000;
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
if (state.getType() == Fluids.EMPTY) return null;
var sprites = FluidRenderHandlerRegistry.INSTANCE.get(state.getType()).getFluidSprites(level, pos, state);
if (sprites == null) return null;
return sprites[0];
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@NotNull FluidStack stack) {
if (stack.getFluid() == Fluids.EMPTY) return null;
var sprites = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid()).getFluidSprites(null, null, stack.getFluid().defaultFluidState());
if (sprites == null) return null;
return sprites[0];
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getStillTexture(@NotNull Fluid fluid) {
if (fluid == Fluids.EMPTY) return null;
var sprites = FluidRenderHandlerRegistry.INSTANCE.get(fluid).getFluidSprites(null, null, fluid.defaultFluidState());
if (sprites == null) return null;
return sprites[0];
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
if (state.getType() == Fluids.EMPTY) return null;
var handler = FluidRenderHandlerRegistry.INSTANCE.get(state.getType());
if (handler == null) return null;
var sprites = handler.getFluidSprites(level, pos, state);
if (sprites == null) return null;
return sprites[1];
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@NotNull FluidStack stack) {
if (stack.getFluid() == Fluids.EMPTY) return null;
var handler = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid());
if (handler == null) return null;
var sprites = handler.getFluidSprites(null, null, stack.getFluid().defaultFluidState());
if (sprites == null) return null;
return sprites[1];
}
@Environment(EnvType.CLIENT)
@Nullable
public static TextureAtlasSprite getFlowingTexture(@NotNull Fluid fluid) {
if (fluid == Fluids.EMPTY) return null;
var sprites = FluidRenderHandlerRegistry.INSTANCE.get(fluid).getFluidSprites(null, null, fluid.defaultFluidState());
if (sprites == null) return null;
return sprites[1];
}
@Environment(EnvType.CLIENT)
public static int getColor(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) {
if (state.getType() == Fluids.EMPTY) return -1;
var handler = FluidRenderHandlerRegistry.INSTANCE.get(state.getType());
if (handler == null) return -1;
return handler.getFluidColor(level, pos, state);
}
@Environment(EnvType.CLIENT)
public static int getColor(@NotNull FluidStack stack) {
if (stack.getFluid() == Fluids.EMPTY) return -1;
var handler = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid());
if (handler == null) return -1;
return handler.getFluidColor(null, null, stack.getFluid().defaultFluidState());
}
@Environment(EnvType.CLIENT)
public static int getColor(@NotNull Fluid fluid) {
if (fluid == Fluids.EMPTY) return -1;
var handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid);
if (handler == null) return -1;
return handler.getFluidColor(null, null, fluid.defaultFluidState());
}
}

View File

@@ -0,0 +1,64 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.level.entity.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.core.SectionPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.EntityInLevelCallback;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import org.jetbrains.annotations.Nullable;
public class EntityHooksImpl {
public static String getEncodeId(Entity entity) {
return entity.getEncodeId();
}
@Nullable
public static Entity fromCollision(CollisionContext ctx) {
return ctx instanceof EntityCollisionContext ? ((EntityCollisionContext) ctx).getEntity().orElse(null) : null;
}
public static EntityInLevelCallback wrapEntityInLevelCallback(Entity entity, EntityInLevelCallback callback) {
if (callback == EntityInLevelCallback.NULL) return callback;
if (callback == null) return callback;
return new EntityInLevelCallback() {
private long lastSectionKey = SectionPos.asLong(entity.blockPosition());
@Override
public void onMove() {
callback.onMove();
var currentSectionKey = SectionPos.asLong(entity.blockPosition());
if (currentSectionKey != lastSectionKey) {
EntityEvent.ENTER_SECTION.invoker().enterSection(entity, SectionPos.x(lastSectionKey), SectionPos.y(lastSectionKey),
SectionPos.z(lastSectionKey), SectionPos.x(currentSectionKey), SectionPos.y(currentSectionKey),
SectionPos.z(currentSectionKey));
lastSectionKey = currentSectionKey;
}
}
@Override
public void onRemove(Entity.RemovalReason removalReason) {
callback.onRemove(removalReason);
}
};
}
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.level.entity.fabric;
import dev.architectury.utils.value.IntValue;
import net.minecraft.world.entity.item.ItemEntity;
public class ItemEntityHooksImpl {
public static IntValue lifespan(ItemEntity entity) {
return new IntValue() {
@Override
public void accept(int value) {
}
@Override
public int getAsInt() {
return 6000;
}
};
}
}

View File

@@ -0,0 +1,32 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.level.entity.fabric;
import net.minecraft.world.entity.player.Player;
public class PlayerHooksImpl {
public static boolean isFake(Player player) {
return false;
}
public static void closeContainer(Player player) {
player.closeContainer();
}
}

View File

@@ -0,0 +1,52 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.level.fabric;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.phys.Vec3;
public class ExplosionHooksImpl {
public static Vec3 getPosition(Explosion explosion) {
return ((ExplosionExtensions) explosion).architectury_getPosition();
}
public static Entity getSource(Explosion explosion) {
return ((ExplosionExtensions) explosion).architectury_getSource();
}
public static float getRadius(Explosion explosion) {
return ((ExplosionExtensions) explosion).architectury_getRadius();
}
public static void setRadius(Explosion explosion, float radius) {
((ExplosionExtensions) explosion).architectury_setRadius(radius);
}
public interface ExplosionExtensions {
Vec3 architectury_getPosition();
Entity architectury_getSource();
float architectury_getRadius();
void architectury_setRadius(float v);
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.hooks.tags.fabric;
import net.fabricmc.fabric.api.tag.TagRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagCollection;
import java.util.function.Supplier;
public class TagHooksImpl {
public static <T> Tag.Named<T> optional(ResourceLocation id, Supplier<TagCollection<T>> collection) {
return TagRegistry.create(id, collection);
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.impl.fabric;
import dev.architectury.event.events.common.ChatEvent;
import net.minecraft.network.chat.Component;
public class ChatComponentImpl implements ChatEvent.ChatComponent {
private Component raw;
private Component filtered;
public ChatComponentImpl(Component raw, Component filtered) {
this.raw = raw;
this.filtered = filtered;
}
@Override
public Component getRaw() {
return raw;
}
@Override
public Component getFiltered() {
return filtered;
}
@Override
public void setRaw(Component raw) {
this.raw = raw;
}
@Override
public void setFiltered(Component filtered) {
this.filtered = filtered;
}
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.impl.fabric;
import dev.architectury.event.events.client.ClientScreenInputEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.TextComponent;
public interface ScreenInputDelegate {
Screen architectury_delegateInputs();
class DelegateScreen extends Screen {
private Screen parent;
public DelegateScreen(Screen parent) {
super(TextComponent.EMPTY);
this.parent = parent;
}
@Override
public boolean mouseDragged(double d, double e, int i, double f, double g) {
if (ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), parent, d, e, i, f, g).isPresent())
return true;
if (parent.mouseDragged(d, e, i, f, g))
return true;
return ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), parent, d, e, i, f, g).isPresent();
}
@Override
public boolean charTyped(char c, int i) {
if (ClientScreenInputEvent.CHAR_TYPED_PRE.invoker().charTyped(Minecraft.getInstance(), parent, c, i).isPresent())
return true;
if (parent.charTyped(c, i))
return true;
return ClientScreenInputEvent.CHAR_TYPED_POST.invoker().charTyped(Minecraft.getInstance(), parent, c, i).isPresent();
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.init.fabric;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.networking.fabric.SpawnEntityPacket;
import net.minecraft.client.Minecraft;
public class ArchitecturyClient {
public static void init() {
ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(Minecraft.getInstance());
SpawnEntityPacket.register();
}
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.ExplosionEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.ExplosionDamageCalculator;
import net.minecraft.world.level.Level;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(value = {Level.class, ServerLevel.class})
public class ExplosionPreInvoker {
@Inject(method = "explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Explosion$BlockInteraction;)Lnet/minecraft/world/level/Explosion;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Explosion;explode()V"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
private void explodePre(Entity entity, DamageSource damageSource, ExplosionDamageCalculator explosionDamageCalculator, double d, double e, double f, float g, boolean bl, Explosion.BlockInteraction blockInteraction, CallbackInfoReturnable<Explosion> cir, Explosion explosion) {
if (ExplosionEvent.PRE.invoker().explode((Level) (Object) this, explosion).isFalse()) {
cir.setReturnValue(explosion);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
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;
@Mixin(value = {LivingEntity.class, Player.class, ServerPlayer.class})
public class LivingDeathInvoker {
@Inject(method = "die", at = @At("HEAD"), cancellable = true)
private void die(DamageSource source, CallbackInfo ci) {
if (EntityEvent.LIVING_DEATH.invoker().die((LivingEntity) (Object) this, source).isFalse()) {
ci.cancel();
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(BaseSpawner.class)
public abstract class MixinBaseSpawner {
@Redirect(
method = "serverTick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Mob;checkSpawnRules(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/world/entity/MobSpawnType;)Z",
ordinal = 0
)
)
private boolean checkSpawnerSpawn(Mob mob, LevelAccessor level, MobSpawnType type) {
var result = EntityEvent.LIVING_CHECK_SPAWN.invoker()
.canSpawn(mob, level, mob.getX(), mob.getY(), mob.getZ(), type, (BaseSpawner) (Object) this);
if (result.value() != null) {
return result.value();
}
return mob.checkSpawnRules(level, type) && mob.checkSpawnObstruction(level);
}
@Redirect(
method = "serverTick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Mob;checkSpawnObstruction(Lnet/minecraft/world/level/LevelReader;)Z",
ordinal = 0
)
)
private boolean skipDoubleObstruction(Mob mob, LevelReader levelReader) {
return true;
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.extensions.BlockEntityExtension;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(BlockEntityExtension.class)
public interface MixinBlockEntityExtension extends BlockEntityClientSerializable {
@Override
default void fromClientTag(CompoundTag tag) {
var entity = (BlockEntity) this;
if (entity.hasLevel()) {
((BlockEntityExtension) this).loadClientData(entity.getBlockState(), tag);
}
}
@Override
default CompoundTag toClientTag(CompoundTag tag) {
return ((BlockEntityExtension) this).saveClientData(tag);
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.BlockEvent;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.context.BlockPlaceContext;
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.CallbackInfoReturnable;
@Mixin(BlockItem.class)
public abstract class MixinBlockItem {
@Inject(method = "place",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/item/context/BlockPlaceContext;getClickedPos()Lnet/minecraft/core/BlockPos;"),
cancellable = true)
private void place(BlockPlaceContext context, CallbackInfoReturnable<InteractionResult> cir) {
var result = BlockEvent.PLACE.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());
if (result.isPresent()) {
cir.setReturnValue(result.isTrue() ? InteractionResult.SUCCESS : InteractionResult.FAIL);
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(BucketItem.class)
public class MixinBucketItem {
@Inject(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/phys/BlockHitResult;getType()Lnet/minecraft/world/phys/HitResult$Type;",
ordinal = 0
),
locals = LocalCapture.CAPTURE_FAILHARD,
cancellable = true
)
public void fillBucket(Level level, Player player, InteractionHand hand, CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir, ItemStack stack, BlockHitResult target) {
var result = PlayerEvent.FILL_BUCKET.invoker().fill(player, level, stack, target);
if (result.interruptsFurtherEvaluation() && result.value() != null) {
cir.setReturnValue(result.asMinecraft());
cir.cancel();
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.animal.Cat;
import net.minecraft.world.entity.npc.CatSpawner;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(CatSpawner.class)
public abstract class MixinCatSpawner {
@Inject(
method = "spawnCat",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/animal/Cat;finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/entity/SpawnGroupData;",
ordinal = 0
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILHARD
)
private void checkCatSpawn(BlockPos pos, ServerLevel level, CallbackInfoReturnable<Integer> cir, Cat entity) {
if (EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(entity, level, pos.getX(), pos.getY(), pos.getZ(), MobSpawnType.NATURAL, null).value() == Boolean.FALSE) {
cir.setReturnValue(0);
cir.cancel();
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.ChunkEvent;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.spongepowered.asm.mixin.Final;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ChunkMap.class)
public class MixinChunkMap {
@Shadow
@Final
ServerLevel level;
@Inject(
method = "save",
at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkMap;write(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)V", ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void save(ChunkAccess chunkAccess, CallbackInfoReturnable<Boolean> cir, ChunkPos pos, ChunkStatus chunkStatus, CompoundTag nbt) {
ChunkEvent.SAVE_DATA.invoker().save(chunkAccess, this.level, nbt);
}
}

View File

@@ -0,0 +1,49 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.ChunkEvent;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.lighting.LevelLightEngine;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ChunkSerializer.class)
public class MixinChunkSerializer {
@Inject(method = "read", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
private static void load(ServerLevel serverLevel, StructureManager structureManager, PoiManager poiManager, ChunkPos chunkPos, CompoundTag compoundTag,
CallbackInfoReturnable<ProtoChunk> cir, ChunkGenerator chunkGenerator, BiomeSource biomeSource, CompoundTag compoundTagLevelData,
ChunkBiomeContainer chunkBiomeContainer, UpgradeData upgradeData, ProtoTickList<?> protoTickList, ProtoTickList<?> protoTickList2,
boolean bl, ListTag listTag, int i, LevelChunkSection[] levelChunkSections, boolean bl2, ChunkSource chunkSource,
LevelLightEngine levelLightEngine, long l, ChunkStatus.ChunkType chunkType, ChunkAccess chunk) {
ChunkEvent.LOAD_DATA.invoker().load(chunk, serverLevel, compoundTag);
}
}

View File

@@ -0,0 +1,49 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import com.google.common.base.Throwables;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.architectury.event.events.common.CommandPerformEvent;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Commands.class)
public class MixinCommands {
@Redirect(method = "performCommand",
at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/CommandDispatcher;execute(Lcom/mojang/brigadier/StringReader;Ljava/lang/Object;)I", remap = false))
private int performCommand(CommandDispatcher<CommandSourceStack> dispatcher, StringReader input, Object source) throws CommandSyntaxException {
var stack = (CommandSourceStack) source;
var parse = dispatcher.parse(input, stack);
var event = new CommandPerformEvent(parse, null);
if (CommandPerformEvent.EVENT.invoker().act(event).isPresent()) {
if (event.getThrowable() != null) {
Throwables.throwIfUnchecked(event.getThrowable());
}
return 1;
}
return dispatcher.execute(event.getResults());
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.LifecycleEvent;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
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.CallbackInfoReturnable;
@Mixin(DedicatedServer.class)
public class MixinDedicatedServer {
@Inject(method = "initServer", at = @At("RETURN"), cancellable = true)
private void initServer(CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) {
LifecycleEvent.SERVER_STARTING.invoker().stateChanged((MinecraftServer) (Object) this);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.hooks.level.entity.fabric.EntityHooksImpl;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.EntityInLevelCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(Entity.class)
public class MixinEntity {
@ModifyVariable(method = "setLevelCallback", argsOnly = true, ordinal = 0, at = @At("HEAD"))
public EntityInLevelCallback modifyLevelCallback_setLevelCallback(EntityInLevelCallback callback) {
return EntityHooksImpl.wrapEntityInLevelCallback((Entity) (Object) this, callback);
}
}

View File

@@ -0,0 +1,92 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.ExplosionEvent;
import dev.architectury.hooks.level.fabric.ExplosionHooksImpl;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.List;
import java.util.Set;
@Mixin(Explosion.class)
public class MixinExplosion implements ExplosionHooksImpl.ExplosionExtensions {
@Shadow
@Final
private Level level;
@Shadow
@Final
private double x;
@Shadow
@Final
private double y;
@Shadow
@Final
private double z;
@Shadow
@Final
@Nullable
private Entity source;
@Shadow
@Final
@Mutable
private float radius;
@Unique
Vec3 position;
@Inject(method = "explode", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/Vec3;<init>(DDD)V", ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD)
private void explodePost(CallbackInfo ci, Set<BlockPos> set, int i, float q, int r, int s, int t, int u, int v, int w, List<Entity> list) {
ExplosionEvent.DETONATE.invoker().explode(level, (Explosion) (Object) this, list);
}
@Override
public Vec3 architectury_getPosition() {
if (position == null) {
return position = new Vec3(x, y, z);
}
return position;
}
@Override
public Entity architectury_getSource() {
return source;
}
@Override
public float architectury_getRadius() {
return radius;
}
@Override
public void architectury_setRadius(float v) {
radius = v;
}
}

View File

@@ -0,0 +1,61 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.InteractionEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.FarmBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.commons.lang3.tuple.Triple;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(FarmBlock.class)
public abstract class MixinFarmBlock {
@Unique
private static ThreadLocal<Triple<Long, Float, Entity>> turnToDirtLocal = new ThreadLocal<>();
@Inject(
method = "fallOn",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/block/FarmBlock;turnToDirt(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V"
)
)
private void fallOn(Level level, BlockState blockState, BlockPos blockPos, Entity entity, float f, CallbackInfo ci) {
turnToDirtLocal.set(Triple.of(blockPos.asLong(), f, entity));
}
@Inject(method = "turnToDirt", at = @At("HEAD"), cancellable = true)
private static void turnToDirt(BlockState state, Level level, BlockPos pos, CallbackInfo ci) {
var triple = turnToDirtLocal.get();
turnToDirtLocal.remove();
if (triple != null && triple.getLeft() == pos.asLong()) {
if (InteractionEvent.FARMLAND_TRAMPLE.invoker().trample(level, pos, state, triple.getMiddle(), triple.getRight()).value() != null) {
ci.cancel();
}
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.FurnaceResultSlot;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
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;
@Mixin(FurnaceResultSlot.class)
public class MixinFurnaceResultSlot {
@Shadow
@Final
private Player player;
@Inject(method = "checkTakeAchievements", at = @At("RETURN"))
private void checkTakeAchievements(ItemStack itemStack, CallbackInfo ci) {
PlayerEvent.SMELT_ITEM.invoker().smelt(player, itemStack);
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.extensions.ItemExtension;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
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;
@Mixin(Inventory.class)
public class MixinInventory {
@Shadow
@Final
public NonNullList<ItemStack> armor;
@Shadow
@Final
public Player player;
@Inject(method = "tick", at = @At("RETURN"))
private void updateItems(CallbackInfo ci) {
for (var stack : armor) {
Item item = stack.getItem();
if (item instanceof ItemExtension extension) {
extension.tickArmor(stack, player);
}
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemEntity.class)
public abstract class MixinItemEntity {
@Shadow
public abstract ItemStack getItem();
@Unique
private ItemStack cache;
@Inject(method = "playerTouch",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getCount()I"), cancellable = true)
private void prePickup(Player player, CallbackInfo ci) {
cache = getItem().copy();
var canPickUp = PlayerEvent.PICKUP_ITEM_PRE.invoker().canPickup(player, (ItemEntity) (Object) this, getItem());
if (canPickUp.isFalse()) {
ci.cancel();
}
}
@Inject(method = "playerTouch",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;take(Lnet/minecraft/world/entity/Entity;I)V"))
private void pickup(Player player, CallbackInfo ci) {
if (cache != null) {
PlayerEvent.PICKUP_ITEM_POST.invoker().pickup(player, (ItemEntity) (Object) this, cache);
}
this.cache = null;
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import dev.architectury.extensions.ItemExtension;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LivingEntity.class)
public class MixinLivingEntity {
@Inject(method = "hurt", at = @At("HEAD"), cancellable = true)
private void hurt(DamageSource damageSource, float f, CallbackInfoReturnable<Boolean> cir) {
if ((Object) this instanceof Player) return;
if (EntityEvent.LIVING_HURT.invoker().hurt((LivingEntity) (Object) this, damageSource, f).isFalse()) {
cir.setReturnValue(false);
}
}
@Inject(method = "getEquipmentSlotForItem", at = @At("HEAD"), cancellable = true)
private static void getEquipmentSlotForItem(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> cir) {
var item = stack.getItem();
if (item instanceof ItemExtension extension) {
var slot = extension.getCustomEquipmentSlot(stack);
if (slot != null) {
cir.setReturnValue(slot);
}
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.NaturalSpawner;
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.Redirect;
@Mixin(NaturalSpawner.class)
public abstract class MixinNaturalSpawner {
@Shadow
private static boolean isValidPositionForMob(ServerLevel serverLevel, Mob mob, double d) {
return false;
}
@Redirect(
method = "spawnCategoryForPosition(Lnet/minecraft/world/entity/MobCategory;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/NaturalSpawner$SpawnPredicate;Lnet/minecraft/world/level/NaturalSpawner$AfterSpawnCallback;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/NaturalSpawner;isValidPositionForMob(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Mob;D)Z",
ordinal = 0
)
)
private static boolean overrideNaturalSpawnCondition(ServerLevel level, Mob entity, double f) {
var result = EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(entity, level, entity.xOld, entity.yOld, entity.zOld, MobSpawnType.NATURAL, null);
if (result.value() != null) {
return result.value();
} else {
return isValidPositionForMob(level, entity, f);
}
}
@Redirect(
method = "spawnMobsForChunkGeneration",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Mob;checkSpawnRules(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/world/entity/MobSpawnType;)Z",
ordinal = 0
)
)
private static boolean overrideChunkGenSpawnCondition(Mob mob, LevelAccessor level, MobSpawnType type) {
var result = EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(mob, level, mob.xOld, mob.yOld, mob.zOld, MobSpawnType.CHUNK_GENERATION, null);
if (result.value() != null) {
return result.value();
} else {
return mob.checkSpawnRules(level, type);
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.monster.PatrollingMonster;
import net.minecraft.world.level.levelgen.PatrolSpawner;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Random;
@Mixin(PatrolSpawner.class)
public abstract class MixinPatrolSpawner {
@Inject(
method = "spawnPatrolMember",
at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/world/level/Level;)Lnet/minecraft/world/entity/Entity;",
ordinal = 0,
shift = At.Shift.BY,
by = 2
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILHARD
)
private void checkPatrolSpawn(ServerLevel level, BlockPos pos, Random r, boolean b, CallbackInfoReturnable<Boolean> cir, PatrollingMonster entity) {
var result = EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(entity, level, pos.getX(), pos.getY(), pos.getZ(), MobSpawnType.PATROL, null);
if (result.value() != null) {
cir.setReturnValue(result.value());
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import dev.architectury.hooks.fabric.PersistentEntitySectionManagerHooks;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.EntityAccess;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.lang.ref.WeakReference;
@Mixin(PersistentEntitySectionManager.class)
public class MixinPersistentEntitySectionManager<T extends EntityAccess> implements PersistentEntitySectionManagerHooks {
@Unique
private WeakReference<ServerLevel> levelRef;
@Override
public void architectury_attachLevel(ServerLevel level) {
levelRef = new WeakReference<>(level);
}
@Inject(method = "addEntity", at = @At(value = "INVOKE",
target = "Lnet/minecraft/core/SectionPos;asLong(Lnet/minecraft/core/BlockPos;)J"),
cancellable = true)
private void addEntity(T entityAccess, boolean bl, CallbackInfoReturnable<Boolean> cir) {
// TODO: Check if other classes implements EntityAccess as well
if (entityAccess instanceof Entity entity && levelRef != null) {
var level = levelRef.get();
levelRef = null;
if (level != null) {
if (EntityEvent.ADD.invoker().add(entity, level).isFalse()) {
cir.setReturnValue(false);
}
}
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.monster.Phantom;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.levelgen.PhantomSpawner;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Iterator;
import java.util.Random;
@Mixin(PhantomSpawner.class)
public abstract class MixinPhantomSpawner {
@Inject(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/monster/Phantom;finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/entity/SpawnGroupData;",
ordinal = 0,
shift = At.Shift.BEFORE
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILSOFT // SOFT, because this will break in 2 seconds
)
private void checkPhantomSpawn(ServerLevel level, boolean bl, boolean bl2, CallbackInfoReturnable<Integer> cir,
Random random, int i, Iterator<ServerPlayer> it, Player player, BlockPos pos, DifficultyInstance diff, BlockPos pos2,
SpawnGroupData sgd, int l, int m, Phantom entity) {
if (EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(entity, level, pos.getX(), pos.getY(), pos.getZ(), MobSpawnType.NATURAL, null).value() == Boolean.FALSE) {
cir.setReturnValue(0);
cir.cancel();
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.InteractionEvent;
import dev.architectury.event.events.common.PlayerEvent;
import dev.architectury.event.events.common.TickEvent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Player.class)
public class MixinPlayer {
@Inject(method = "tick", at = @At("HEAD"))
private void preTick(CallbackInfo ci) {
TickEvent.PLAYER_PRE.invoker().tick((Player) (Object) this);
}
@Inject(method = "tick", at = @At("RETURN"))
private void postTick(CallbackInfo ci) {
TickEvent.PLAYER_POST.invoker().tick((Player) (Object) this);
}
@Inject(method = "drop(Lnet/minecraft/world/item/ItemStack;ZZ)Lnet/minecraft/world/entity/item/ItemEntity;", at = @At("RETURN"), cancellable = true)
private void drop(ItemStack itemStack, boolean bl, boolean bl2, CallbackInfoReturnable<ItemEntity> cir) {
if (cir.getReturnValue() != null && PlayerEvent.DROP_ITEM.invoker().drop((Player) (Object) this, cir.getReturnValue()).isFalse()) {
cir.setReturnValue(null);
}
}
@Inject(method = "interactOn", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;",
ordinal = 0),
cancellable = true)
private void entityInteract(Entity entity, InteractionHand interactionHand, CallbackInfoReturnable<InteractionResult> cir) {
var result = InteractionEvent.INTERACT_ENTITY.invoker().interact((Player) (Object) this, entity, interactionHand);
if (result.isPresent()) {
cir.setReturnValue(result.asMinecraft());
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.advancements.Advancement;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.level.ServerPlayer;
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.CallbackInfoReturnable;
@Mixin(PlayerAdvancements.class)
public class MixinPlayerAdvancements {
@Shadow
private ServerPlayer player;
@Inject(method = "award",
at = @At(value = "INVOKE", target = "Lnet/minecraft/advancements/AdvancementRewards;grant(Lnet/minecraft/server/level/ServerPlayer;)V",
shift = At.Shift.AFTER))
private void award(Advancement advancement, String string, CallbackInfoReturnable<Boolean> cir) {
PlayerEvent.PLAYER_ADVANCEMENT.invoker().award(player, advancement);
}
}

View File

@@ -0,0 +1,48 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.network.Connection;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerList.class)
public class MixinPlayerList {
@Inject(method = "placeNewPlayer", at = @At("RETURN"))
private void placeNewPlayer(Connection connection, ServerPlayer serverPlayer, CallbackInfo ci) {
PlayerEvent.PLAYER_JOIN.invoker().join(serverPlayer);
}
@Inject(method = "remove", at = @At("HEAD"))
private void remove(ServerPlayer serverPlayer, CallbackInfo ci) {
PlayerEvent.PLAYER_QUIT.invoker().quit(serverPlayer);
}
@Inject(method = "respawn", at = @At("RETURN"))
private void respawn(ServerPlayer serverPlayer, boolean bl, CallbackInfoReturnable<ServerPlayer> cir) {
PlayerEvent.PLAYER_RESPAWN.invoker().respawn(cir.getReturnValue(), bl);
}
}

View File

@@ -0,0 +1,50 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.inventory.ResultSlot;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
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;
@Mixin(ResultSlot.class)
public class MixinResultSlot {
@Shadow
@Final
private Player player;
@Shadow
@Final
private CraftingContainer craftSlots;
@Inject(method = "checkTakeAchievements", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/item/ItemStack;onCraftedBy(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;I)V",
shift = At.Shift.AFTER))
private void craft(ItemStack itemStack, CallbackInfo ci) {
PlayerEvent.CRAFT_ITEM.invoker().craft(player, itemStack, craftSlots);
}
}

View File

@@ -0,0 +1,78 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.ChatEvent;
import dev.architectury.impl.fabric.ChatComponentImpl;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.server.network.TextFilter;
import org.spongepowered.asm.mixin.Final;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Objects;
@Mixin(ServerGamePacketListenerImpl.class)
public abstract class MixinServerGamePacketListenerImpl {
@Shadow
public ServerPlayer player;
@Shadow
@Final
private MinecraftServer server;
@Shadow
private int chatSpamTickCount;
@Shadow
public abstract void disconnect(Component component);
@Inject(method = "handleChat(Lnet/minecraft/server/network/TextFilter$FilteredText;)V",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/server/players/PlayerList;broadcastMessage(Lnet/minecraft/network/chat/Component;Ljava/util/function/Function;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V"),
cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
private void handleChat(TextFilter.FilteredText message, CallbackInfo ci, String string, Component component, Component component2) {
var chatComponent = new ChatComponentImpl(component2, component);
var process = ChatEvent.SERVER.invoker().process(this.player, message, chatComponent);
if (process.isEmpty()) return;
if (process.isFalse()) {
ci.cancel();
} else if (!Objects.equals(chatComponent.getRaw(), component2) || !Objects.equals(chatComponent.getFiltered(), component)) {
this.server.getPlayerList().broadcastMessage(chatComponent.getRaw(), (serverPlayer) -> {
return this.player.shouldFilterMessageTo(serverPlayer) ? chatComponent.getFiltered() : chatComponent.getRaw();
}, ChatType.CHAT, this.player.getUUID());
this.chatSpamTickCount += 20;
if (this.chatSpamTickCount > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
this.disconnect(new TranslatableComponent("disconnect.spam"));
}
ci.cancel();
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.LifecycleEvent;
import dev.architectury.hooks.fabric.PersistentEntitySectionManagerHooks;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.ProgressListener;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.spongepowered.asm.mixin.Final;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerLevel.class)
public class MixinServerLevel {
@Shadow
@Final
private PersistentEntitySectionManager<Entity> entityManager;
@Inject(method = "save", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;save(Z)V"))
private void save(ProgressListener progressListener, boolean bl, boolean bl2, CallbackInfo ci) {
LifecycleEvent.SERVER_LEVEL_SAVE.invoker().act((ServerLevel) (Object) this);
}
@Inject(method = "addEntity", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;addNewEntity(Lnet/minecraft/world/level/entity/EntityAccess;)Z"),
cancellable = true)
private void addEntity(Entity entity, CallbackInfoReturnable<Boolean> cir) {
((PersistentEntitySectionManagerHooks) this.entityManager).architectury_attachLevel((ServerLevel) (Object) this);
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.PlayerEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.OptionalInt;
@Mixin(ServerPlayer.class)
public class MixinServerPlayer {
@Inject(method = "restoreFrom", at = @At("RETURN"))
private void restoreFrom(ServerPlayer serverPlayer, boolean bl, CallbackInfo ci) {
PlayerEvent.PLAYER_CLONE.invoker().clone((ServerPlayer) (Object) this, serverPlayer, bl);
}
@Inject(method = "openMenu", at = @At("RETURN"))
private void openMenu(MenuProvider menuProvider, CallbackInfoReturnable<OptionalInt> cir) {
if (cir.getReturnValue().isPresent()) {
PlayerEvent.OPEN_MENU.invoker().open((ServerPlayer) (Object) this, ((ServerPlayer) (Object) this).containerMenu);
}
}
@Inject(method = "openHorseInventory", at = @At("RETURN"))
private void openHorseInventory(AbstractHorse abstractHorse, Container container, CallbackInfo ci) {
PlayerEvent.OPEN_MENU.invoker().open((ServerPlayer) (Object) this, ((ServerPlayer) (Object) this).containerMenu);
}
@Inject(method = "doCloseContainer",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/AbstractContainerMenu;removed(Lnet/minecraft/world/entity/player/Player;)V",
shift = At.Shift.AFTER))
private void doCloseContainer(CallbackInfo ci) {
PlayerEvent.CLOSE_MENU.invoker().close((ServerPlayer) (Object) this, ((ServerPlayer) (Object) this).containerMenu);
}
@Inject(method = "triggerDimensionChangeTriggers", at = @At("HEAD"))
private void changeDimension(ServerLevel serverLevel, CallbackInfo ci) {
PlayerEvent.CHANGE_DIMENSION.invoker().change((ServerPlayer) (Object) this, serverLevel.dimension(), ((ServerPlayer) (Object) this).level.dimension());
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.BlockEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Final;
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.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ServerPlayerGameMode.class)
public class MixinServerPlayerGameMode {
@Shadow
protected ServerLevel level;
@Shadow
@Final
protected ServerPlayer player;
@Inject(method = "destroyBlock", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/level/block/state/BlockState;getBlock()Lnet/minecraft/world/level/block/Block;",
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private void onBreak(BlockPos blockPos, CallbackInfoReturnable<Boolean> cir, BlockState state) {
if (BlockEvent.BREAK.invoker().breakBlock(this.level, blockPos, state, this.player, null).isFalse()) {
cir.setReturnValue(false);
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.player.RemotePlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
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.CallbackInfoReturnable;
@Mixin(value = {LocalPlayer.class, Player.class, RemotePlayer.class})
public class PlayerAttackInvoker {
@Inject(method = "hurt", at = @At("HEAD"), cancellable = true)
private void hurt(DamageSource damageSource, float f, CallbackInfoReturnable<Boolean> cir) {
if (EntityEvent.LIVING_HURT.invoker().hurt((LivingEntity) (Object) this, damageSource, f).isFalse() && (Object) this instanceof Player) {
cir.setReturnValue(false);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.event.events.common.EntityEvent;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
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.Supplier;
@Mixin(ClientLevel.class)
public class MixinClientLevel {
@Inject(method = "<init>", at = @At("RETURN"))
private void construct(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey<Level> resourceKey, DimensionType dimensionType, int i, Supplier<ProfilerFiller> supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
ClientLifecycleEvent.CLIENT_LEVEL_LOAD.invoker().act((ClientLevel) (Object) this);
}
@Inject(method = "addEntity", at = @At("HEAD"), cancellable = true)
private void addEntity(int i, Entity entity, CallbackInfo ci) {
if (EntityEvent.ADD.invoker().add(entity, (ClientLevel) (Object) this).isFalse()) {
ci.cancel();
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientChatEvent;
import dev.architectury.event.events.client.ClientPlayerEvent;
import dev.architectury.event.events.client.ClientRecipeUpdateEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.protocol.game.ClientboundChatPacket;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket;
import net.minecraft.world.item.crafting.RecipeManager;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPacketListener.class)
public class MixinClientPacketListener {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
@Final
private RecipeManager recipeManager;
@Unique
private LocalPlayer tmpPlayer;
@Inject(method = "handleLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;broadcastOptions()V"))
private void handleLogin(ClientboundLoginPacket packet, CallbackInfo ci) {
ClientPlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(minecraft.player);
}
@Inject(method = "handleRespawn", at = @At("HEAD"))
private void handleRespawnPre(ClientboundRespawnPacket packet, CallbackInfo ci) {
this.tmpPlayer = minecraft.player;
}
@Inject(method = "handleRespawn", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/ClientLevel;addPlayer(ILnet/minecraft/client/player/AbstractClientPlayer;)V"))
private void handleRespawn(ClientboundRespawnPacket packet, CallbackInfo ci) {
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(tmpPlayer, minecraft.player);
this.tmpPlayer = null;
}
@Inject(method = "handleChat", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/Gui;handleChat(Lnet/minecraft/network/chat/ChatType;Lnet/minecraft/network/chat/Component;Ljava/util/UUID;)V"),
cancellable = true)
private void handleChat(ClientboundChatPacket packet, CallbackInfo ci) {
var process = ClientChatEvent.RECEIVED.invoker().process(packet.getType(), packet.getMessage(), packet.getSender());
if (process.isEmpty()) return;
if (process.isFalse()) {
ci.cancel();
} else if (process.object() != null && !process.object().equals(packet.getMessage())) {
this.minecraft.gui.handleChat(packet.getType(), packet.getMessage(), packet.getSender());
ci.cancel();
}
}
@Inject(method = "handleUpdateRecipes", at = @At("RETURN"))
private void handleUpdateRecipes(ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket, CallbackInfo ci) {
ClientRecipeUpdateEvent.EVENT.invoker().update(recipeManager);
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientGuiEvent;
import net.minecraft.client.gui.components.DebugScreenOverlay;
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.CallbackInfoReturnable;
import java.util.List;
@Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay {
@Inject(method = "getGameInformation", at = @At("RETURN"))
private void getLeftTexts(CallbackInfoReturnable<List<String>> cir) {
ClientGuiEvent.DEBUG_TEXT_LEFT.invoker().gatherText(cir.getReturnValue());
}
@Inject(method = "getSystemInformation", at = @At("RETURN"))
private void getRightTexts(CallbackInfoReturnable<List<String>> cir) {
ClientGuiEvent.DEBUG_TEXT_RIGHT.invoker().gatherText(cir.getReturnValue());
}
}

View File

@@ -0,0 +1,57 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import com.mojang.blaze3d.shaders.Program;
import net.minecraft.client.renderer.EffectInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Unique
@Mixin(value = EffectInstance.class, priority = 950)
public class MixinEffectInstance {
@Redirect(
method = "<init>",
at = @At(value = "NEW",
target = "(Ljava/lang/String;)Lnet/minecraft/resources/ResourceLocation;",
ordinal = 0)
)
private ResourceLocation mojangPls(String _0, ResourceManager rm, String str) {
return mojangPls(new ResourceLocation(str), ".json");
}
@Redirect(
method = "getOrCreate",
at = @At(value = "NEW",
target = "(Ljava/lang/String;)Lnet/minecraft/resources/ResourceLocation;",
ordinal = 0)
)
private static ResourceLocation mojangPls(String _0, ResourceManager rm, Program.Type type, String str) {
return mojangPls(new ResourceLocation(str), type.getExtension());
}
private static ResourceLocation mojangPls(ResourceLocation rl, String ext) {
return new ResourceLocation(rl.getNamespace(), "shaders/program/" + rl.getPath() + ext);
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.architectury.event.events.client.ClientGuiEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import org.spongepowered.asm.mixin.Final;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public abstract class MixinGameRenderer {
@Shadow
@Final
private Minecraft minecraft;
@Inject(method = "render(FJZ)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V",
ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
public void renderScreenPre(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, PoseStack matrices) {
if (ClientGuiEvent.RENDER_PRE.invoker().render(minecraft.screen, matrices, mouseX, mouseY, minecraft.getDeltaFrameTime()).isFalse()) {
ci.cancel();
}
}
@Inject(method = "render(FJZ)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V",
shift = At.Shift.AFTER, ordinal = 0), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
public void renderScreenPost(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, PoseStack matrices) {
ClientGuiEvent.RENDER_POST.invoker().render(minecraft.screen, matrices, mouseX, mouseY, minecraft.getDeltaFrameTime());
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.common.LifecycleEvent;
import net.minecraft.client.server.IntegratedServer;
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.CallbackInfoReturnable;
@Mixin(IntegratedServer.class)
public class MixinIntegratedServer {
@Inject(method = "initServer", at = @At("RETURN"), cancellable = true)
private void initServer(CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) {
LifecycleEvent.SERVER_STARTING.invoker().stateChanged((MinecraftServer) (Object) this);
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.EventResult;
import dev.architectury.event.events.client.ClientRawInputEvent;
import dev.architectury.event.events.client.ClientScreenInputEvent;
import dev.architectury.impl.fabric.ScreenInputDelegate;
import net.minecraft.client.KeyboardHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.Final;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(KeyboardHandler.class)
public class MixinKeyboardHandler {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
private boolean sendRepeatsToGui;
@ModifyVariable(method = {"method_1458", "lambda$charTyped$5"}, at = @At("HEAD"), ordinal = 0, argsOnly = true)
private static GuiEventListener wrapCharTypedFirst(GuiEventListener screen) {
if (screen instanceof ScreenInputDelegate delegate) {
return delegate.architectury_delegateInputs();
}
return screen;
}
@ModifyVariable(method = {"method_1473", "lambda$charTyped$6"}, at = @At("HEAD"), ordinal = 0, argsOnly = true)
private static GuiEventListener wrapCharTypedSecond(GuiEventListener screen) {
if (screen instanceof ScreenInputDelegate delegate) {
return delegate.architectury_delegateInputs();
}
return screen;
}
@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0), cancellable = true)
public void onKey(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info) {
if (!info.isCancelled()) {
if (int_3 != 1 && (int_3 != 2 || !this.sendRepeatsToGui)) {
if (int_3 == 0) {
var result = ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(minecraft, minecraft.screen, int_1, int_2, int_4);
if (result.isPresent())
info.cancel();
}
} else {
var result = ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(minecraft, minecraft.screen, int_1, int_2, int_4);
if (result.isPresent())
info.cancel();
}
}
}
@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD,
cancellable = true)
public void onKeyAfter(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info, Screen screen, boolean bls[]) {
if (!info.isCancelled() && !bls[0]) {
EventResult result;
if (int_3 != 1 && (int_3 != 2 || !this.sendRepeatsToGui)) {
result = ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(minecraft, screen, int_1, int_2, int_4);
} else {
result = ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(minecraft, screen, int_1, int_2, int_4);
}
if (result.isPresent())
info.cancel();
}
}
@Inject(method = "keyPress", at = @At("RETURN"), cancellable = true)
public void onRawKey(long handle, int key, int scanCode, int action, int modifiers, CallbackInfo info) {
if (handle == this.minecraft.getWindow().getWindow()) {
var result = ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(minecraft, key, scanCode, action, modifiers);
if (result.isPresent())
info.cancel();
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientGuiEvent;
import dev.architectury.event.events.client.ClientPlayerEvent;
import dev.architectury.event.events.common.InteractionEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.HitResult;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Unique
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
@Shadow
@Nullable
public LocalPlayer player;
@Shadow
@Nullable
public HitResult hitResult;
@Shadow
public abstract void setScreen(@Nullable Screen screen);
@Unique
private ThreadLocal<Boolean> setScreenCancelled = new ThreadLocal<>();
@Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/chat/NarratorChatListener;clear()V"))
private void handleLogin(Screen screen, CallbackInfo ci) {
ClientPlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(player);
}
@Inject(method = "startUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 1),
locals = LocalCapture.CAPTURE_FAILHARD)
private void rightClickAir(CallbackInfo ci, InteractionHand[] var1, int var2, int var3, InteractionHand interactionHand, ItemStack itemStack) {
if (itemStack.isEmpty() && (this.hitResult == null || this.hitResult.getType() == HitResult.Type.MISS)) {
InteractionEvent.CLIENT_RIGHT_CLICK_AIR.invoker().click(player, interactionHand);
}
}
@Inject(method = "startAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;resetAttackStrengthTicker()V", ordinal = 0))
private void leftClickAir(CallbackInfo ci) {
InteractionEvent.CLIENT_LEFT_CLICK_AIR.invoker().click(player, InteractionHand.MAIN_HAND);
}
@ModifyVariable(
method = "setScreen",
at = @At(value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
argsOnly = true
)
public Screen modifyScreen(Screen screen) {
var old = screen;
var event = ClientGuiEvent.SET_SCREEN.invoker().modifyScreen(screen);
if (event.isPresent()) {
if (event.isFalse()) {
setScreenCancelled.set(true);
return old;
} else {
screen = event.object();
if (old != null && screen != old) {
old.removed();
}
}
}
setScreenCancelled.set(false);
return screen;
}
@Inject(
method = "setScreen",
at = @At(value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
cancellable = true
)
public void cancelSetScreen(@Nullable Screen screen, CallbackInfo ci) {
if (setScreenCancelled.get()) {
ci.cancel();
setScreenCancelled.set(false);
}
}
}

View File

@@ -0,0 +1,163 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientRawInputEvent;
import dev.architectury.event.events.client.ClientScreenInputEvent;
import dev.architectury.impl.fabric.ScreenInputDelegate;
import net.minecraft.client.Minecraft;
import net.minecraft.client.MouseHandler;
import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.Final;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(MouseHandler.class)
public class MixinMouseHandler {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
private int activeButton;
@Shadow
private double xpos;
@Shadow
private double ypos;
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z",
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) {
if (!info.isCancelled()) {
var result = ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount);
if (result.isPresent())
info.cancel();
}
}
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z",
ordinal = 0, shift = At.Shift.AFTER), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onMouseScrolledPost(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) {
if (!info.isCancelled()) {
var result = ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount);
}
}
@Inject(method = "onScroll",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSpectator()Z",
ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void onRawMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount) {
if (!info.isCancelled()) {
var result = ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(minecraft, amount);
if (result.isPresent())
info.cancel();
}
}
@SuppressWarnings("UnresolvedMixinReference")
@Inject(method = {"lambda$onPress$0", "method_1611"}, at = @At("HEAD"), cancellable = true, remap = false)
private static void onGuiMouseClicked(boolean[] bls, Screen screen, double d, double e, int button, CallbackInfo info) {
var minecraft = Minecraft.getInstance();
if (!info.isCancelled()) {
var result = ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, screen, d, e, button);
if (result.isPresent()) {
bls[0] = true;
info.cancel();
}
}
}
@SuppressWarnings("UnresolvedMixinReference")
@Inject(method = {"lambda$onPress$0", "method_1611"}, at = @At("RETURN"), cancellable = true, remap = false)
private static void onGuiMouseClickedPost(boolean[] bls, Screen screen, double d, double e, int button, CallbackInfo info) {
var minecraft = Minecraft.getInstance();
if (!info.isCancelled() && !bls[0]) {
var result = ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(minecraft, screen, d, e, button);
if (result.isPresent()) {
bls[0] = true;
info.cancel();
}
}
}
@Inject(method = "onPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/Minecraft;getOverlay()Lnet/minecraft/client/gui/screens/Overlay;",
ordinal = 0), cancellable = true)
public void onRawMouseClicked(long handle, int button, int action, int mods, CallbackInfo info) {
if (!info.isCancelled()) {
var result = ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, button, action, mods);
if (result.isPresent())
info.cancel();
}
}
@Inject(method = "onPress", at = @At("RETURN"), cancellable = true)
public void onRawMouseClickedPost(long handle, int button, int action, int mods, CallbackInfo info) {
if (handle == this.minecraft.getWindow().getWindow()) {
var result = ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(minecraft, button, action, mods);
if (result.isPresent())
info.cancel();
}
}
@SuppressWarnings("UnresolvedMixinReference")
@Inject(method = {"lambda$onPress$1", "method_1605"}, at = @At("HEAD"), cancellable = true, remap = false)
private static void onGuiMouseReleased(boolean[] bls, Screen screen, double d, double e, int button, CallbackInfo info) {
var minecraft = Minecraft.getInstance();
if (!info.isCancelled()) {
var result = ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(minecraft, screen, d, e, button);
if (result.isPresent()) {
bls[0] = true;
info.cancel();
}
}
}
@SuppressWarnings("UnresolvedMixinReference")
@Inject(method = {"lambda$onPress$1", "method_1605"}, at = @At("RETURN"), cancellable = true, remap = false)
private static void onGuiMouseReleasedPost(boolean[] bls, Screen screen, double d, double e, int button, CallbackInfo info) {
var minecraft = Minecraft.getInstance();
if (!info.isCancelled() && !bls[0]) {
var result = ClientScreenInputEvent.MOUSE_RELEASED_POST.invoker().mouseReleased(minecraft, screen, d, e, button);
if (result.isPresent()) {
bls[0] = true;
info.cancel();
}
}
}
@SuppressWarnings("UnresolvedMixinReference")
@ModifyVariable(method = {"method_1602", "lambda$onMove$11"}, at = @At("HEAD"), ordinal = 0, argsOnly = true)
private Screen wrapMouseDragged(Screen screen) {
if (screen instanceof ScreenInputDelegate delegate) {
return delegate.architectury_delegateInputs();
}
return screen;
}
}

View File

@@ -0,0 +1,45 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.common.InteractionEvent;
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
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.CallbackInfoReturnable;
@Mixin(MultiPlayerGameMode.class)
public class MixinMultiPlayerGameMode {
@Inject(method = "interact",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V",
shift = At.Shift.AFTER),
cancellable = true)
private void entityInteract(Player player, Entity entity, InteractionHand interactionHand, CallbackInfoReturnable<InteractionResult> cir) {
var result = InteractionEvent.INTERACT_ENTITY.invoker().interact(player, entity, interactionHand);
if (result.isPresent()) {
cir.setReturnValue(result.asMinecraft());
}
}
}

View File

@@ -0,0 +1,143 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.architectury.event.events.client.ClientChatEvent;
import dev.architectury.event.events.client.ClientGuiEvent;
import dev.architectury.event.events.client.ClientTooltipEvent;
import dev.architectury.hooks.client.screen.ScreenAccess;
import dev.architectury.impl.ScreenAccessImpl;
import dev.architectury.impl.TooltipEventColorContextImpl;
import dev.architectury.impl.TooltipEventPositionContextImpl;
import dev.architectury.impl.fabric.ScreenInputDelegate;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.util.FormattedCharSequence;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(Screen.class)
public abstract class MixinScreen implements ScreenInputDelegate {
@Unique
private static ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
@Unique
private static ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
@Unique
private ScreenAccessImpl access;
@Shadow
public abstract List<? extends GuiEventListener> children();
@Unique
private Screen inputDelegate;
@Unique
private ScreenAccess getAccess() {
if (access == null) {
return access = new ScreenAccessImpl((Screen) (Object) this);
}
access.setScreen((Screen) (Object) this); // Preventive set
return access;
}
@Override
public Screen architectury_delegateInputs() {
if (inputDelegate == null) {
inputDelegate = new DelegateScreen((Screen) (Object) this);
}
return inputDelegate;
}
@Inject(method = "init(Lnet/minecraft/client/Minecraft;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;clearWidgets()V", ordinal = 0),
cancellable = true)
private void preInit(Minecraft minecraft, int i, int j, CallbackInfo ci) {
if (ClientGuiEvent.INIT_PRE.invoker().init((Screen) (Object) this, getAccess()).isFalse()) {
ci.cancel();
}
}
@Inject(method = "init(Lnet/minecraft/client/Minecraft;II)V", at = @At(value = "RETURN"))
private void postInit(Minecraft minecraft, int i, int j, CallbackInfo ci) {
ClientGuiEvent.INIT_POST.invoker().init((Screen) (Object) this, getAccess());
}
@ModifyVariable(method = "sendMessage(Ljava/lang/String;Z)V", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private String modifyMessage(String message) {
var process = ClientChatEvent.PROCESS.invoker().process(message);
if (process.isPresent()) {
if (process.isFalse())
return "";
if (process.object() != null)
return process.object();
}
return message;
}
@Inject(method = "renderTooltipInternal", at = @At("HEAD"), cancellable = true)
private void renderTooltip(PoseStack poseStack, List<? extends FormattedCharSequence> list, int x, int y, CallbackInfo ci) {
if (!list.isEmpty()) {
var colorContext = tooltipColorContext.get();
colorContext.reset();
var positionContext = tooltipPositionContext.get();
positionContext.reset(x, y);
if (ClientTooltipEvent.RENDER_VANILLA_PRE.invoker().renderTooltip(poseStack, list, x, y).isFalse()) {
ci.cancel();
} else {
ClientTooltipEvent.RENDER_MODIFY_COLOR.invoker().renderTooltip(poseStack, x, y, colorContext);
ClientTooltipEvent.RENDER_MODIFY_POSITION.invoker().renderTooltip(poseStack, positionContext);
}
}
}
@ModifyVariable(method = "renderTooltipInternal",
at = @At(value = "HEAD"), ordinal = 0)
private int modifyTooltipX(int original) {
return tooltipPositionContext.get().getTooltipX();
}
@ModifyVariable(method = "renderTooltipInternal",
at = @At(value = "HEAD"), ordinal = 1)
private int modifyTooltipY(int original) {
return tooltipPositionContext.get().getTooltipY();
}
@ModifyConstant(method = "renderTooltipInternal", constant = @Constant(intValue = 0xf0100010))
private int modifyTooltipBackgroundColor(int original) {
return tooltipColorContext.get().getBackgroundColor();
}
@ModifyConstant(method = "renderTooltipInternal", constant = @Constant(intValue = 0x505000ff))
private int modifyTooltipOutlineGradientTopColor(int original) {
return tooltipColorContext.get().getOutlineGradientTopColor();
}
@ModifyConstant(method = "renderTooltipInternal", constant = @Constant(intValue = 0x5028007f))
private int modifyTooltipOutlineGradientBottomColor(int original) {
return tooltipColorContext.get().getOutlineGradientBottomColor();
}
}

View File

@@ -0,0 +1,50 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.mixin.fabric.client;
import dev.architectury.event.events.client.ClientTextureStitchEvent;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Set;
import java.util.stream.Stream;
@Mixin(TextureAtlas.class)
public class MixinTextureAtlas {
@Inject(method = "prepareToStitch",
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", ordinal = 0,
shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
private void preStitch(ResourceManager resourceManager, Stream<ResourceLocation> stream, ProfilerFiller profilerFiller, int i, CallbackInfoReturnable<TextureAtlas.Preparations> cir, Set<ResourceLocation> set) {
ClientTextureStitchEvent.PRE.invoker().stitch((TextureAtlas) (Object) this, set::add);
}
@Inject(method = "reload", at = @At("RETURN"))
private void postStitch(TextureAtlas.Preparations preparations, CallbackInfo ci) {
ClientTextureStitchEvent.POST.invoker().stitch((TextureAtlas) (Object) this);
}
}

View File

@@ -0,0 +1,104 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.networking.fabric;
import dev.architectury.networking.NetworkManager;
import dev.architectury.networking.NetworkManager.NetworkReceiver;
import dev.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.fabricmc.fabric.api.network.PacketContext;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
public class NetworkManagerImpl {
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, NetworkReceiver receiver) {
if (side == NetworkManager.Side.C2S) {
registerC2SReceiver(id, receiver);
} else if (side == NetworkManager.Side.S2C) {
registerS2CReceiver(id, receiver);
}
}
private static void registerC2SReceiver(ResourceLocation id, NetworkReceiver receiver) {
ServerSidePacketRegistry.INSTANCE.register(id, (packetContext, buf) -> receiver.receive(buf, to(packetContext)));
}
@Environment(EnvType.CLIENT)
private static void registerS2CReceiver(ResourceLocation id, NetworkReceiver receiver) {
ClientSidePacketRegistry.INSTANCE.register(id, (packetContext, buf) -> receiver.receive(buf, to(packetContext)));
}
private static NetworkManager.PacketContext to(PacketContext context) {
return new NetworkManager.PacketContext() {
@Override
public Player getPlayer() {
return context.getPlayer();
}
@Override
public void queue(Runnable runnable) {
context.getTaskQueue().execute(runnable);
}
@Override
public Env getEnvironment() {
return Env.fromPlatform(context.getPacketEnvironment());
}
};
}
public static Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
if (side == NetworkManager.Side.C2S) {
return toC2SPacket(id, buf);
} else if (side == NetworkManager.Side.S2C) {
return toS2CPacket(id, buf);
}
throw new IllegalArgumentException("Invalid side: " + side);
}
public static boolean canServerReceive(ResourceLocation id) {
return ClientSidePacketRegistry.INSTANCE.canServerReceive(id);
}
public static boolean canPlayerReceive(ServerPlayer player, ResourceLocation id) {
return ServerSidePacketRegistry.INSTANCE.canPlayerReceive(player, id);
}
public static Packet<?> createAddEntityPacket(Entity entity) {
return SpawnEntityPacket.create(entity);
}
@Environment(EnvType.CLIENT)
private static Packet<?> toC2SPacket(ResourceLocation id, FriendlyByteBuf buf) {
return ClientSidePacketRegistry.INSTANCE.toPacket(id, buf);
}
private static Packet<?> toS2CPacket(ResourceLocation id, FriendlyByteBuf buf) {
return ServerSidePacketRegistry.INSTANCE.toPacket(id, buf);
}
}

View File

@@ -0,0 +1,102 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.networking.fabric;
import dev.architectury.networking.NetworkManager;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Registry;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
/**
* @see net.minecraft.network.protocol.game.ClientboundAddEntityPacket
*/
public class SpawnEntityPacket {
private static final ResourceLocation PACKET_ID = new ResourceLocation("architectury", "spawn_entity_packet");
@Environment(EnvType.CLIENT)
public static void register() {
NetworkManager.registerReceiver(NetworkManager.s2c(), PACKET_ID, SpawnEntityPacket::receive);
}
public static Packet<?> create(Entity entity) {
if (entity.level.isClientSide()) {
throw new IllegalStateException("SpawnPacketUtil.create called on the logical client!");
}
var buffer = PacketByteBufs.create();
buffer.writeVarInt(Registry.ENTITY_TYPE.getId(entity.getType()));
buffer.writeUUID(entity.getUUID());
buffer.writeVarInt(entity.getId());
var position = entity.position();
buffer.writeDouble(position.x);
buffer.writeDouble(position.y);
buffer.writeDouble(position.z);
buffer.writeFloat(entity.getXRot());
buffer.writeFloat(entity.getYRot());
buffer.writeFloat(entity.getYHeadRot());
var deltaMovement = entity.getDeltaMovement();
buffer.writeDouble(deltaMovement.x);
buffer.writeDouble(deltaMovement.y);
buffer.writeDouble(deltaMovement.z);
return NetworkManager.toPacket(NetworkManager.s2c(), PACKET_ID, buffer);
}
@Environment(EnvType.CLIENT)
public static void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
var entityTypeId = buf.readVarInt();
var uuid = buf.readUUID();
var id = buf.readVarInt();
var x = buf.readDouble();
var y = buf.readDouble();
var z = buf.readDouble();
var xRot = buf.readFloat();
var yRot = buf.readFloat();
var yHeadRot = buf.readFloat();
var deltaX = buf.readDouble();
var deltaY = buf.readDouble();
var deltaZ = buf.readDouble();
context.queue(() -> {
var entityType = Registry.ENTITY_TYPE.byId(entityTypeId);
if (entityType == null) {
throw new IllegalStateException("Entity type (" + entityTypeId + ") is unknown, spawning at (" + x + ", " + y + ", " + z + ")");
}
if (Minecraft.getInstance().level == null) {
throw new IllegalStateException("Client world is null!");
}
var entity = entityType.create(Minecraft.getInstance().level);
if (entity == null) {
throw new IllegalStateException("Created entity is null!");
}
entity.setUUID(uuid);
entity.setId(id);
entity.setPacketCoordinates(x, y, z);
entity.absMoveTo(x, y, z, xRot, yRot);
entity.setYHeadRot(yHeadRot);
entity.setYBodyRot(yHeadRot);
Minecraft.getInstance().level.putNonPlayerEntity(id, entity);
entity.lerpMotion(deltaX, deltaY, deltaZ);
});
}
}

View File

@@ -0,0 +1,159 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.platform.fabric;
import dev.architectury.platform.Mod;
import dev.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.fabricmc.loader.api.metadata.Person;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class PlatformImpl {
public static final Map<String, Mod.ConfigurationScreenProvider> CONFIG_SCREENS = new ConcurrentHashMap<>();
private static final Map<String, Mod> mods = new ConcurrentHashMap<>();
public static Path getGameFolder() {
return FabricLoader.getInstance().getGameDir();
}
public static Path getConfigFolder() {
return FabricLoader.getInstance().getConfigDir();
}
public static Path getModsFolder() {
return getGameFolder().resolve("mods");
}
public static Env getEnvironment() {
return Env.fromPlatform(getEnv());
}
public static EnvType getEnv() {
return FabricLoader.getInstance().getEnvironmentType();
}
public static boolean isModLoaded(String id) {
return FabricLoader.getInstance().isModLoaded(id);
}
public static Mod getMod(String id) {
return mods.computeIfAbsent(id, ModImpl::new);
}
public static Collection<Mod> getMods() {
for (var mod : FabricLoader.getInstance().getAllMods()) {
getMod(mod.getMetadata().getId());
}
return mods.values();
}
public static Collection<String> getModIds() {
return FabricLoader.getInstance().getAllMods().stream().map(ModContainer::getMetadata).map(ModMetadata::getId).collect(Collectors.toList());
}
public static boolean isDevelopmentEnvironment() {
return FabricLoader.getInstance().isDevelopmentEnvironment();
}
private static class ModImpl implements Mod {
private final ModContainer container;
private final ModMetadata metadata;
public ModImpl(String id) {
this.container = FabricLoader.getInstance().getModContainer(id).get();
this.metadata = this.container.getMetadata();
}
@Override
public @NotNull String getModId() {
return metadata.getId();
}
@Override
public @NotNull String getVersion() {
return metadata.getVersion().getFriendlyString();
}
@Override
public @NotNull String getName() {
return metadata.getName();
}
@Override
public @NotNull String getDescription() {
return metadata.getDescription();
}
@Override
public @NotNull Optional<String> getLogoFile(int preferredSize) {
return metadata.getIconPath(preferredSize);
}
@Override
public @NotNull Path getFilePath() {
return container.getRootPath();
}
@Override
public @NotNull Collection<String> getAuthors() {
return metadata.getAuthors().stream()
.map(Person::getName)
.collect(Collectors.toList());
}
@Override
public @Nullable Collection<String> getLicense() {
return metadata.getLicense();
}
@Override
public @NotNull Optional<String> getHomepage() {
return metadata.getContact().get("homepage");
}
@Override
public @NotNull Optional<String> getSources() {
return metadata.getContact().get("issues");
}
@Override
public @NotNull Optional<String> getIssueTracker() {
return metadata.getContact().get("sources");
}
@Override
public void registerConfigurationScreen(ConfigurationScreenProvider provider) {
if (CONFIG_SCREENS.containsKey(getModId()))
throw new IllegalStateException("Can not register configuration screen for mod '" + getModId() + "' because it was already registered!");
CONFIG_SCREENS.put(getModId(), provider);
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.plugin.fabric;
import net.fabricmc.loader.api.FabricLoader;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.List;
import java.util.Set;
public class ArchitecturyMixinPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
// noop
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if ("me.shedaniel.architectury.mixin.fabric.client.MixinEffectInstance".equals(mixinClassName)) {
return !FabricLoader.getInstance().isModLoaded("satin");
}
return true;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
// noop
}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
// noop
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
// noop
}
}

View File

@@ -0,0 +1,81 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.block.fabric;
import dev.architectury.registry.block.BlockProperties;
import dev.architectury.registry.block.ToolType;
import net.fabricmc.fabric.impl.object.builder.BlockSettingsInternals;
import net.fabricmc.fabric.impl.object.builder.FabricBlockInternals;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.MaterialColor;
import java.util.function.Function;
public class BlockPropertiesImpl {
public static BlockProperties of(Material material, MaterialColor color) {
return new Impl(material, (state) -> color);
}
public static BlockProperties of(Material material, Function<BlockState, MaterialColor> color) {
return new Impl(material, color);
}
public static BlockProperties copy(BlockBehaviour old) {
return copy(old.properties);
}
public static BlockProperties copy(BlockBehaviour.Properties old) {
var properties = of(old.material, old.materialColor);
properties.material = old.material;
properties.destroyTime = old.destroyTime;
properties.explosionResistance = old.explosionResistance;
properties.hasCollision = old.hasCollision;
properties.isRandomlyTicking = old.isRandomlyTicking;
properties.lightEmission = old.lightEmission;
properties.materialColor = old.materialColor;
properties.soundType = old.soundType;
properties.friction = old.friction;
properties.speedFactor = old.speedFactor;
properties.dynamicShape = old.dynamicShape;
properties.canOcclude = old.canOcclude;
properties.isAir = old.isAir;
properties.requiresCorrectToolForDrops = old.requiresCorrectToolForDrops;
var otherInternals = (BlockSettingsInternals) old;
var extraData = otherInternals.getExtraData();
if (extraData != null) {
((BlockSettingsInternals) properties).setExtraData(extraData);
}
return properties;
}
private static final class Impl extends BlockProperties {
public Impl(Material material, Function<BlockState, MaterialColor> function) {
super(material, function);
}
@Override
public BlockProperties tool(ToolType type, int level) {
FabricBlockInternals.computeExtraData(this).addMiningLevel(type.fabricTag.get(), level);
return this;
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.block.fabric;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.tags.Tag;
import net.minecraft.world.item.Item;
public class ToolTypeImpl {
public static Tag<Item> pickaxeTag() {
return FabricToolTags.PICKAXES;
}
public static Tag<Item> axeTag() {
return FabricToolTags.AXES;
}
public static Tag<Item> hoeTag() {
return FabricToolTags.HOES;
}
public static Tag<Item> shovelTag() {
return FabricToolTags.SHOVELS;
}
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.client.keymappings.fabric;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.KeyMapping;
public class KeyMappingRegistryImpl {
public static void register(KeyMapping mapping) {
KeyBindingHelper.registerKeyBinding(mapping);
}
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.client.rendering.fabric;
import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
public class BlockEntityRendererRegistryImpl {
public static <T extends BlockEntity> void register(BlockEntityType<T> type, BlockEntityRendererProvider<? super T> provider) {
BlockEntityRendererRegistry.INSTANCE.register(type, provider);
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.client.rendering.fabric;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.minecraft.client.color.block.BlockColor;
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;
public class ColorHandlerRegistryImpl {
@SafeVarargs
public static void registerItemColors(ItemColor itemColor, Supplier<ItemLike>... items) {
Objects.requireNonNull(itemColor, "color is null!");
ColorProviderRegistry.ITEM.register(itemColor, unpackItems(items));
}
@SafeVarargs
public static void registerBlockColors(BlockColor blockColor, Supplier<Block>... blocks) {
Objects.requireNonNull(blockColor, "color is null!");
ColorProviderRegistry.BLOCK.register(blockColor, unpackBlocks(blocks));
}
private static ItemLike[] unpackItems(Supplier<ItemLike>[] items) {
var array = new ItemLike[items.length];
for (var i = 0; i < items.length; i++) {
array[i] = Objects.requireNonNull(items[i].get());
}
return array;
}
private static Block[] unpackBlocks(Supplier<Block>[] blocks) {
var array = new Block[blocks.length];
for (var i = 0; i < blocks.length; i++) {
array[i] = Objects.requireNonNull(blocks[i].get());
}
return array;
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.client.rendering.fabric;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.Fluid;
public class RenderTypeRegistryImpl {
public static void register(RenderType type, Block... blocks) {
BlockRenderLayerMap.INSTANCE.putBlocks(type, blocks);
}
public static void register(RenderType type, Fluid... fluids) {
BlockRenderLayerMap.INSTANCE.putFluids(type, fluids);
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.fabric;
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import java.util.function.Supplier;
public class CreativeTabRegistryImpl {
public static CreativeModeTab create(ResourceLocation name, Supplier<ItemStack> icon) {
return FabricItemGroupBuilder.build(name, icon);
}
}

View File

@@ -0,0 +1,60 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.fabric;
import com.google.common.primitives.Longs;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import org.apache.commons.lang3.StringUtils;
import java.security.SecureRandom;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
public class ReloadListenerRegistryImpl {
private static final SecureRandom RANDOM = new SecureRandom();
public static void register(PackType type, PreparableReloadListener listener) {
var bytes = new byte[8];
RANDOM.nextBytes(bytes);
var id = new ResourceLocation("architectury:reload_" + StringUtils.leftPad(Math.abs(Longs.fromByteArray(bytes)) + "", 19, '0'));
ResourceManagerHelper.get(type).registerReloadListener(new IdentifiableResourceReloadListener() {
@Override
public ResourceLocation getFabricId() {
return id;
}
@Override
public String getName() {
return listener.getName();
}
@Override
public CompletableFuture<Void> reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller profilerFiller, ProfilerFiller profilerFiller2, Executor executor, Executor executor2) {
return listener.reload(preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2);
}
});
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.fuel.fabric;
import net.fabricmc.fabric.api.registry.FuelRegistry;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
public class FuelRegistryImpl {
public static void register(int time, ItemLike... items) {
for (var item : items) {
if (time >= 0) {
FuelRegistry.INSTANCE.add(item, time);
} else {
FuelRegistry.INSTANCE.remove(item);
}
}
}
public static int get(ItemStack stack) {
var time = FuelRegistry.INSTANCE.get(stack.getItem());
return time == null ? 0 : time;
}
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.advancement.fabric;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.advancements.CriterionTrigger;
public class CriteriaTriggersRegistryImpl {
public static <T extends CriterionTrigger<?>> T register(T trigger) {
return CriteriaTriggers.register(trigger);
}
}

View File

@@ -0,0 +1,370 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.biome.fabric;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import dev.architectury.hooks.level.biome.*;
import dev.architectury.registry.level.biome.BiomeModifications.BiomeContext;
import net.fabricmc.fabric.api.biome.v1.BiomeModification;
import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext;
import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext.GenerationSettingsContext;
import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext.SpawnSettingsContext;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.fabricmc.fabric.api.biome.v1.ModificationPhase;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.Music;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.biome.*;
import net.minecraft.world.level.biome.Biome.BiomeCategory;
import net.minecraft.world.level.biome.Biome.Precipitation;
import net.minecraft.world.level.biome.Biome.TemperatureModifier;
import net.minecraft.world.level.biome.BiomeSpecialEffects.GrassColorModifier;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public class BiomeModificationsImpl {
private static final ResourceLocation FABRIC_MODIFICATION = new ResourceLocation("architectury", "fabric_modification");
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> ADDITIONS = Lists.newArrayList();
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> POST_PROCESSING = Lists.newArrayList();
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REMOVALS = Lists.newArrayList();
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REPLACEMENTS = Lists.newArrayList();
public static void addProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
ADDITIONS.add(Pair.of(predicate, modifier));
}
public static void postProcessProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
ADDITIONS.add(Pair.of(predicate, modifier));
}
public static void removeProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
ADDITIONS.add(Pair.of(predicate, modifier));
}
public static void replaceProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
ADDITIONS.add(Pair.of(predicate, modifier));
}
static {
var modification = net.fabricmc.fabric.api.biome.v1.BiomeModifications.create(FABRIC_MODIFICATION);
registerModification(modification, ModificationPhase.ADDITIONS, ADDITIONS);
registerModification(modification, ModificationPhase.POST_PROCESSING, POST_PROCESSING);
registerModification(modification, ModificationPhase.REMOVALS, REMOVALS);
registerModification(modification, ModificationPhase.REPLACEMENTS, REPLACEMENTS);
}
private static void registerModification(BiomeModification modification, ModificationPhase phase, List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> list) {
modification.add(phase, Predicates.alwaysTrue(), (biomeSelectionContext, biomeModificationContext) -> {
var biomeContext = wrapSelectionContext(biomeSelectionContext);
var mutableBiome = wrapMutableBiome(biomeSelectionContext.getBiome(), biomeModificationContext);
for (var pair : list) {
if (pair.getLeft().test(biomeContext)) {
pair.getRight().accept(biomeContext, mutableBiome);
}
}
});
}
private static BiomeContext wrapSelectionContext(BiomeSelectionContext context) {
return new BiomeContext() {
BiomeProperties properties = BiomeHooks.getBiomeProperties(context.getBiome());
@Override
@NotNull
public ResourceLocation getKey() {
return context.getBiomeKey().location();
}
@Override
@NotNull
public BiomeProperties getProperties() {
return properties;
}
};
}
private static BiomeProperties.Mutable wrapMutableBiome(Biome biome, BiomeModificationContext context) {
return new BiomeHooks.MutableBiomeWrapped(
biome,
wrapWeather(biome, context.getWeather()),
wrapEffects(biome, context.getEffects()),
new MutableGenerationProperties(biome, context.getGenerationSettings()),
new MutableSpawnProperties(biome, context.getSpawnSettings())
) {
@Override
@NotNull
public BiomeProperties.Mutable setCategory(@NotNull BiomeCategory category) {
context.setCategory(category);
return this;
}
@Override
@NotNull
public BiomeProperties.Mutable setDepth(float depth) {
context.setDepth(depth);
return this;
}
@Override
@NotNull
public BiomeProperties.Mutable setScale(float scale) {
context.setScale(scale);
return this;
}
};
}
private static class MutableGenerationProperties extends BiomeHooks.GenerationSettingsWrapped implements GenerationProperties.Mutable {
protected final GenerationSettingsContext context;
public MutableGenerationProperties(Biome biome, GenerationSettingsContext context) {
super(biome);
this.context = context;
}
@Override
public Mutable setSurfaceBuilder(ConfiguredSurfaceBuilder<?> builder) {
this.context.setBuiltInSurfaceBuilder(builder);
return this;
}
@Override
public Mutable addFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
this.context.addBuiltInFeature(decoration, feature);
return this;
}
@Override
public Mutable addCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
context.addBuiltInCarver(carving, feature);
return this;
}
@Override
public Mutable addStructure(ConfiguredStructureFeature<?, ?> feature) {
context.addBuiltInStructure(feature);
return this;
}
@Override
public Mutable removeFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
context.removeBuiltInFeature(decoration, feature);
return this;
}
@Override
public Mutable removeCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
context.removeBuiltInCarver(carving, feature);
return this;
}
@Override
public Mutable removeStructure(ConfiguredStructureFeature<?, ?> feature) {
context.removeBuiltInStructure(feature);
return this;
}
}
private static class MutableSpawnProperties extends BiomeHooks.SpawnSettingsWrapped implements SpawnProperties.Mutable {
protected final SpawnSettingsContext context;
public MutableSpawnProperties(Biome biome, SpawnSettingsContext context) {
super(biome);
this.context = context;
}
@Override
public @NotNull Mutable setCreatureProbability(float probability) {
context.setCreatureSpawnProbability(probability);
return this;
}
@Override
public Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data) {
context.addSpawn(category, data);
return this;
}
@Override
public boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate) {
return context.removeSpawns(predicate);
}
@Override
public Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost) {
context.setSpawnCost(entityType, cost.getCharge(), cost.getEnergyBudget());
return this;
}
@Override
public Mutable setSpawnCost(EntityType<?> entityType, double mass, double gravityLimit) {
context.setSpawnCost(entityType, mass, gravityLimit);
return this;
}
@Override
public Mutable clearSpawnCost(EntityType<?> entityType) {
context.clearSpawnCost(entityType);
return this;
}
@Override
public @NotNull Mutable setPlayerSpawnFriendly(boolean friendly) {
context.setPlayerSpawnFriendly(friendly);
return this;
}
}
private static ClimateProperties.Mutable wrapWeather(Biome biome, BiomeModificationContext.WeatherContext context) {
return new BiomeHooks.ClimateWrapped(biome) {
@Override
@NotNull
public ClimateProperties.Mutable setPrecipitation(@NotNull Precipitation precipitation) {
context.setPrecipitation(precipitation);
return this;
}
@Override
@NotNull
public ClimateProperties.Mutable setTemperature(float temperature) {
context.setTemperature(temperature);
return this;
}
@Override
@NotNull
public ClimateProperties.Mutable setTemperatureModifier(@NotNull TemperatureModifier temperatureModifier) {
context.setTemperatureModifier(temperatureModifier);
return this;
}
@Override
@NotNull
public ClimateProperties.Mutable setDownfall(float downfall) {
context.setDownfall(downfall);
return this;
}
};
}
private static EffectsProperties.Mutable wrapEffects(Biome biome, BiomeModificationContext.EffectsContext context) {
return new BiomeHooks.EffectsWrapped(biome) {
@Override
@NotNull
public EffectsProperties.Mutable setFogColor(int color) {
context.setFogColor(color);
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setWaterColor(int color) {
context.setWaterColor(color);
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setWaterFogColor(int color) {
context.setWaterFogColor(color);
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setSkyColor(int color) {
context.setSkyColor(color);
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setFoliageColorOverride(@Nullable Integer colorOverride) {
context.setFoliageColor(Optional.ofNullable(colorOverride));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setGrassColorOverride(@Nullable Integer colorOverride) {
context.setGrassColor(Optional.ofNullable(colorOverride));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setGrassColorModifier(@NotNull GrassColorModifier modifier) {
context.setGrassColorModifier(modifier);
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setAmbientParticle(@Nullable AmbientParticleSettings settings) {
context.setParticleConfig(Optional.ofNullable(settings));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setAmbientLoopSound(@Nullable SoundEvent sound) {
context.setAmbientSound(Optional.ofNullable(sound));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setAmbientMoodSound(@Nullable AmbientMoodSettings settings) {
context.setMoodSound(Optional.ofNullable(settings));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setAmbientAdditionsSound(@Nullable AmbientAdditionsSettings settings) {
context.setAdditionsSound(Optional.ofNullable(settings));
return this;
}
@Override
@NotNull
public EffectsProperties.Mutable setBackgroundMusic(@Nullable Music music) {
context.setMusic(Optional.ofNullable(music));
return this;
}
};
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.entity.fabric;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import java.util.function.Supplier;
public class EntityAttributeRegistryImpl {
public static void register(Supplier<EntityType<? extends LivingEntity>> type, Supplier<AttributeSupplier.Builder> attribute) {
FabricDefaultAttributeRegistry.register(type.get(), attribute.get());
}
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.entity.fabric;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
public class EntityRendererRegistryImpl {
public static <T extends Entity> void register(EntityType<? extends T> type, EntityRendererProvider<T> provider) {
EntityRendererRegistry.INSTANCE.register(type, provider);
}
}

View File

@@ -0,0 +1,36 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.entity.trade.fabric;
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerTrades;
import java.util.Collections;
public class TradeRegistryImpl {
public static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
TradeOfferHelper.registerVillagerOffers(profession, level, allTradesList -> Collections.addAll(allTradesList, trades));
}
public static void registerTradeForWanderingTrader(boolean rare, VillagerTrades.ItemListing... trades) {
TradeOfferHelper.registerWanderingTraderOffers(rare ? 2 : 1, allTradesList -> Collections.addAll(allTradesList, trades));
}
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.fabric;
import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameRules;
import java.util.function.BiConsumer;
public class GameRuleFactoryImpl {
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
return GameRuleFactory.createBooleanRule(defaultValue);
}
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changedCallback) {
return GameRuleFactory.createBooleanRule(defaultValue, changedCallback);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue) {
return GameRuleFactory.createIntRule(defaultValue);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changedCallback) {
return GameRuleFactory.createIntRule(defaultValue, changedCallback);
}
}

View File

@@ -0,0 +1,29 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.level.fabric;
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
import net.minecraft.world.level.GameRules;
public class GameRuleRegistryImpl {
public static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
return GameRuleRegistry.register(name, category, type);
}
}

View File

@@ -0,0 +1,75 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.menu.fabric;
import dev.architectury.registry.menu.ExtendedMenuProvider;
import dev.architectury.registry.menu.MenuRegistry.ExtendedMenuTypeFactory;
import dev.architectury.registry.menu.MenuRegistry.ScreenFactory;
import dev.architectury.registry.menu.MenuRegistry.SimpleMenuTypeFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.fabricmc.fabric.impl.screenhandler.ExtendedScreenHandlerType;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
import org.jetbrains.annotations.Nullable;
public class MenuRegistryImpl {
public static void openExtendedMenu(ServerPlayer player, ExtendedMenuProvider provider) {
player.openMenu(new ExtendedScreenHandlerFactory() {
@Override
public void writeScreenOpeningData(ServerPlayer player, FriendlyByteBuf buf) {
provider.saveExtraData(buf);
}
@Override
public Component getDisplayName() {
return provider.getDisplayName();
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {
return provider.createMenu(i, inventory, player);
}
});
}
public static <T extends AbstractContainerMenu> MenuType<T> of(SimpleMenuTypeFactory<T> factory) {
return new MenuType<>(factory::create);
}
public static <T extends AbstractContainerMenu> MenuType<T> ofExtended(ExtendedMenuTypeFactory<T> factory) {
return new ExtendedScreenHandlerType<>(factory::create);
}
@Environment(EnvType.CLIENT)
public static <H extends AbstractContainerMenu, S extends Screen & MenuAccess<H>> void registerScreenFactory(MenuType<? extends H> type, ScreenFactory<H, S> factory) {
ScreenRegistry.register(type, factory::create);
}
}

View File

@@ -0,0 +1,218 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.registry.registries.fabric;
import com.google.common.base.Objects;
import com.google.common.base.Suppliers;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarBuilder;
import dev.architectury.registry.registries.Registries;
import dev.architectury.registry.registries.RegistrySupplier;
import dev.architectury.registry.registries.options.RegistrarOption;
import dev.architectury.registry.registries.options.StandardRegistrarOption;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
public class RegistriesImpl {
public static Registries.RegistryProvider _get(String modId) {
return RegistryProviderImpl.INSTANCE;
}
public static <T> ResourceLocation getId(T object, ResourceKey<Registry<T>> fallback) {
if (fallback == null)
return null;
return RegistryProviderImpl.INSTANCE.get(fallback).getId(object);
}
public static <T> ResourceLocation getId(T object, Registry<T> fallback) {
if (fallback == null)
return null;
return RegistryProviderImpl.INSTANCE.get(fallback).getId(object);
}
public enum RegistryProviderImpl implements Registries.RegistryProvider {
INSTANCE;
@Override
public <T> Registrar<T> get(ResourceKey<Registry<T>> key) {
return new RegistrarImpl<>((Registry<T>) Registry.REGISTRY.get(key.location()));
}
@Override
public <T> Registrar<T> get(Registry<T> registry) {
return new RegistrarImpl<>(registry);
}
@Override
@NotNull
public <T> RegistrarBuilder<T> builder(Class<T> type, ResourceLocation registryId) {
return new RegistrarBuilderWrapper<>(FabricRegistryBuilder.createSimple(type, registryId));
}
}
public static class RegistrarBuilderWrapper<T> implements RegistrarBuilder<T> {
@NotNull
private FabricRegistryBuilder<T, MappedRegistry<T>> builder;
public RegistrarBuilderWrapper(@NotNull FabricRegistryBuilder<T, MappedRegistry<T>> builder) {
this.builder = builder;
}
@Override
public @NotNull Registrar<T> build() {
return RegistryProviderImpl.INSTANCE.get(builder.buildAndRegister());
}
@Override
public @NotNull RegistrarBuilder<T> option(@NotNull RegistrarOption option) {
if (option == StandardRegistrarOption.SAVE_TO_DISC) {
this.builder.attribute(RegistryAttribute.PERSISTED);
} else if (option == StandardRegistrarOption.SYNC_TO_CLIENTS) {
this.builder.attribute(RegistryAttribute.SYNCED);
}
return this;
}
}
public static class RegistrarImpl<T> implements Registrar<T> {
private Registry<T> delegate;
public RegistrarImpl(Registry<T> delegate) {
this.delegate = delegate;
}
@Override
public @NotNull RegistrySupplier<T> delegate(ResourceLocation id) {
Supplier<T> value = Suppliers.memoize(() -> get(id));
return new RegistrySupplier<>() {
@Override
public @NotNull ResourceLocation getRegistryId() {
return delegate.key().location();
}
@Override
public @NotNull ResourceLocation getId() {
return id;
}
@Override
public boolean isPresent() {
return contains(id);
}
@Override
public T get() {
return value.get();
}
@Override
public int hashCode() {
return Objects.hashCode(getRegistryId(), getId());
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof RegistrySupplier<?> other)) return false;
return other.getRegistryId().equals(getRegistryId()) && other.getId().equals(getId());
}
@Override
public String toString() {
return getRegistryId().toString() + "@" + id.toString();
}
};
}
@Override
public @NotNull <E extends T> RegistrySupplier<E> register(ResourceLocation id, Supplier<E> supplier) {
Registry.register(delegate, id, supplier.get());
return (RegistrySupplier<E>) delegate(id);
}
@Override
public @Nullable ResourceLocation getId(T obj) {
return delegate.getKey(obj);
}
@Override
public int getRawId(T obj) {
return delegate.getId(obj);
}
@Override
public Optional<ResourceKey<T>> getKey(T obj) {
return delegate.getResourceKey(obj);
}
@Override
public @Nullable T get(ResourceLocation id) {
return delegate.get(id);
}
@Override
public T byRawId(int rawId) {
return delegate.byId(rawId);
}
@Override
public boolean contains(ResourceLocation id) {
return delegate.keySet().contains(id);
}
@Override
public boolean containsValue(T obj) {
return delegate.getResourceKey(obj).isPresent();
}
@Override
public Set<ResourceLocation> getIds() {
return delegate.keySet();
}
@Override
public Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
return delegate.entrySet();
}
@Override
public ResourceKey<? extends Registry<T>> key() {
return delegate.key();
}
@NotNull
@Override
public Iterator<T> iterator() {
return delegate.iterator();
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 architectury
*
* 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 dev.architectury.utils.fabric;
import dev.architectury.event.EventHandler;
import dev.architectury.event.events.common.LifecycleEvent;
import dev.architectury.platform.Platform;
import dev.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
public class GameInstanceImpl {
private static MinecraftServer server = null;
public static MinecraftServer getServer() {
MinecraftServer server = null;
if (GameInstanceImpl.server != null) server = GameInstanceImpl.server;
if (Platform.getEnvironment() == Env.CLIENT) {
server = getServerFromClient();
}
return server;
}
public static void init() {
EventHandler.init();
LifecycleEvent.SERVER_BEFORE_START.register(server -> GameInstanceImpl.server = server);
LifecycleEvent.SERVER_STOPPED.register(server -> GameInstanceImpl.server = null);
}
@Environment(EnvType.CLIENT)
private static MinecraftServer getServerFromClient() {
return Minecraft.getInstance().getSingleplayerServer();
}
}