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

# Conflicts:
#	fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinBlockEntityExtension.java
#	fabric/src/main/resources/architectury.mixins.json
#	gradle.properties
This commit is contained in:
shedaniel
2021-04-09 21:54:50 +08:00
60 changed files with 1100 additions and 370 deletions

View File

@@ -1,21 +1,26 @@
# Architectury
# Architectury API
Talk to us on [Discord](https://discord.gg/C2RdJDpRBP)!
An intermediary api aimed to ease developing multiplatform mods.
### What is Architectury
Architectury is an api to abstract calls to fabric api and forge api as both loader has different implementations of what can be perceived as the same thing.
### What is Architectury API
Architectury API is an api to abstract calls to fabric api and forge api as both loader has different implementations of what can be perceived as the same thing.
Architectury updates regularly, with new hooks and features. Currently contains over **60** events hooks, networking abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation (Only works on static methods).
Architectury API updates regularly, with new hooks and features. Currently contains over **90** events hooks, networking abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation (Only works on static methods).
### Do I really need this API?
Architectury API is only one part of the architectury ecosystem, **Architectury Plugin** is the gradle plugin enabling all this multiplatform actions.
Architectury API is optional for projects built on architectury, you may create your architectury project with just Architectury Plugin.
### Advantages of Architectury
- Open sourced
- Less boilerplate for your multiplatform mod
### Getting started with making multiplatform mods
Gradle Plugin: https://github.com/architectury/architect-plugin
Gradle Plugin: https://github.com/architectury/architectury-plugin
Example Mod: https://github.com/architectury/architect-example-mod
Example Mod: https://github.com/architectury/architectury-example-mod
### Credits
This library bundles typetools, which you can find its license [here](https://github.com/jhalterman/typetools/blob/master/LICENSE.txt "")

View File

@@ -1,6 +1,6 @@
plugins {
id "architectury-plugin" version "2.0.65"
id "forgified-fabric-loom" version "0.6.54" apply false
id "architectury-plugin" version "3.0.97"
id "forgified-fabric-loom" version "0.6.78" apply false
id "org.cadixdev.licenser" version "0.5.0"
id "com.matthewprenger.cursegradle" version "1.4.0" apply false
id "maven-publish"

View File

@@ -20,26 +20,16 @@ task sourcesJar(type: Jar, dependsOn: classes) {
from sourceSets.main.allSource
}
task javadocs(type: Javadoc) {
source = sourceSets.main.allJava
}
task javadocsJar(type: Jar, dependsOn: javadocs) {
archiveClassifier.set("javadocs")
javadocs.failOnError false
from javadocs.destinationDir
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.archivesBaseName
artifact(file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}.jar")) {
builtBy build
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
artifact javadocsJar
}
}

View File

@@ -19,6 +19,8 @@
package me.shedaniel.architectury;
import org.jetbrains.annotations.ApiStatus;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -30,5 +32,6 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public @interface ExpectPlatform {
}
}

View File

@@ -89,7 +89,7 @@ public final class EventFactory {
@Override
protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
for (T listener : listeners) {
InteractionResult result = (InteractionResult) method.invoke(listener, args);
InteractionResult result = (InteractionResult) Objects.requireNonNull(method.invoke(listener, args));
if (result != InteractionResult.PASS) {
return result;
}

View File

@@ -20,6 +20,9 @@
package me.shedaniel.architectury.event;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.event.events.BlockEvent;
import me.shedaniel.architectury.event.events.EntityEvent;
import me.shedaniel.architectury.event.events.PlayerEvent;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
import net.fabricmc.api.EnvType;
@@ -38,6 +41,8 @@ public final class EventHandler {
registerCommon();
if (Platform.getEnvironment() == Env.SERVER)
registerServer();
registerDelegates();
}
@ExpectPlatform
@@ -56,4 +61,10 @@ public final class EventHandler {
private static void registerServer() {
throw new AssertionError();
}
@SuppressWarnings("deprecation")
private static void registerDelegates() {
BlockEvent.PLACE.register((EntityEvent.PLACE_BLOCK.invoker()::placeBlock));
BlockEvent.BREAK.register((PlayerEvent.BREAK_BLOCK.invoker()::breakBlock));
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import me.shedaniel.architectury.utils.IntValue;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public interface BlockEvent {
// Block interaction events
/**
* Called when a player breaks a block.
*/
Event<Break> BREAK = EventFactory.createInteractionResult();
/**
* Called when a block is placed in the world by an entity.
*/
Event<Place> PLACE = EventFactory.createInteractionResult();
/**
* Called when a falling block (sand, anvil, etc.) is about to land.
* Use fallState#getBlock to get the type of block for more granular control.
*/
Event<FallingLand> FALLING_LAND = EventFactory.createLoop();
interface Break {
InteractionResult breakBlock(Level world, BlockPos pos, BlockState state, ServerPlayer player, @Nullable IntValue xp);
}
interface Place {
InteractionResult placeBlock(Level world, BlockPos pos, BlockState state, @Nullable Entity placer);
}
interface FallingLand {
void onLand(Level level, BlockPos pos, BlockState fallState, BlockState landOn, FallingBlockEntity entity);
}
}

View File

@@ -28,6 +28,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface EntityEvent {
@@ -43,6 +44,12 @@ public interface EntityEvent {
* Invoked before entity is added to a world, equivalent to forge's {@code EntityJoinWorldEvent}.
*/
Event<Add> ADD = EventFactory.createInteractionResult();
/**
* @deprecated use {@link BlockEvent#PLACE}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
Event<PlaceBlock> PLACE_BLOCK = EventFactory.createInteractionResult();
interface LivingDeath {

View File

@@ -30,7 +30,7 @@ import java.util.List;
public interface ExplosionEvent {
Event<Pre> PRE = EventFactory.createInteractionResult();
Event<Detonate> DETONATE = EventFactory.createInteractionResult();
Event<Detonate> DETONATE = EventFactory.createLoop();
interface Pre {
InteractionResult explode(Level world, Explosion explosion);

View File

@@ -49,7 +49,7 @@ public interface GuiEvent {
*/
Event<ScreenInitPost> INIT_POST = EventFactory.createLoop();
Event<ScreenRenderPre> RENDER_PRE = EventFactory.createInteractionResult();
Event<ScreenRenderPost> RENDER_POST = EventFactory.createInteractionResult();
Event<ScreenRenderPost> RENDER_POST = EventFactory.createLoop();
/**
* Invoked during Minecraft#setScreen, equivalent to forge's {@code GuiOpenEvent}.

View File

@@ -0,0 +1,45 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import java.util.List;
public interface LightningEvent {
// TODO Pre - Called before a lightning bolt entity is added to the world. (cancellable)
/**
* Invoked after the lightning has gathered a list of entities to strike.
* Remove entities from the list to stop them from being hit.
*/
Event<Strike> STRIKE = EventFactory.createLoop();
// TODO Post - Called before a lightning bolt entity is removed from the world.
interface Strike {
void onStrike(LightningBolt bolt, Level level, Vec3 pos, List<Entity> toStrike);
}
}

View File

@@ -34,6 +34,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface PlayerEvent {
@@ -50,6 +51,12 @@ public interface PlayerEvent {
Event<DropItem> DROP_ITEM = EventFactory.createLoop();
Event<OpenMenu> OPEN_MENU = EventFactory.createLoop();
Event<CloseMenu> CLOSE_MENU = EventFactory.createLoop();
/**
* @deprecated use {@link BlockEvent#BREAK}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
Event<BreakBlock> BREAK_BLOCK = EventFactory.createInteractionResult();
interface PlayerJoin {

View File

@@ -44,8 +44,8 @@ public interface TooltipEvent {
* Render forge events are only invoked on the forge side.
*/
Event<RenderForge> RENDER_FORGE_PRE = EventFactory.createInteractionResult();
Event<RenderModifyPosition> RENDER_MODIFY_POSITION = EventFactory.createInteractionResult();
Event<RenderModifyColor> RENDER_MODIFY_COLOR = EventFactory.createInteractionResult();
Event<RenderModifyPosition> RENDER_MODIFY_POSITION = EventFactory.createLoop();
Event<RenderModifyColor> RENDER_MODIFY_COLOR = EventFactory.createLoop();
@Environment(EnvType.CLIENT)
interface Item {

View File

@@ -21,6 +21,8 @@ package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.jetbrains.annotations.Nullable;
public final class EntityHooks {
private EntityHooks() {}
@@ -29,4 +31,10 @@ public final class EntityHooks {
public static String getEncodeId(Entity entity) {
throw new AssertionError();
}
@Nullable
@ExpectPlatform
public static Entity fromCollision(CollisionContext ctx) {
throw new AssertionError();
}
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.hooks;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.mixin.FluidTagsAccessor;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.*;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.Fluid;
import java.util.function.Supplier;
public final class TagHooks {
private TagHooks() {}
@ExpectPlatform
public static <T> Tag.Named<T> getOptional(ResourceLocation id, Supplier<TagCollection<T>> collection) {
throw new AssertionError();
}
public static Tag.Named<Item> getItemOptional(ResourceLocation id) {
return getOptional(id, ItemTags::getAllTags);
}
public static Tag.Named<Block> getBlockOptional(ResourceLocation id) {
return getOptional(id, BlockTags::getAllTags);
}
public static Tag.Named<Fluid> getFluidOptional(ResourceLocation id) {
return getOptional(id, FluidTagsAccessor.getHelper()::getAllTags);
}
public static Tag.Named<EntityType<?>> getEntityTypeOptional(ResourceLocation id) {
return getOptional(id, EntityTypeTags::getAllTags);
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.mixin;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.AnvilBlock;
import net.minecraft.world.level.block.ConcretePowderBlock;
import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.state.BlockState;
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.LocalCapture;
@Mixin({FallingBlock.class, AnvilBlock.class, ConcretePowderBlock.class})
public abstract class BlockLandingInvoker {
@Inject(method = "onLand", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
public void handleLand(Level level, BlockPos pos, BlockState fallState, BlockState landOn, FallingBlockEntity entity, CallbackInfo ci) {
BlockEvent.FALLING_LAND.invoker().onLand(level, pos, fallState, landOn, entity);
}
}

View File

@@ -0,0 +1,34 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.mixin;
import net.minecraft.tags.FluidTags;
import net.minecraft.tags.StaticTagHelper;
import net.minecraft.world.level.material.Fluid;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(FluidTags.class)
public interface FluidTagsAccessor {
@Accessor("HELPER")
static StaticTagHelper<Fluid> getHelper() {
throw new AssertionError();
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.mixin;
import me.shedaniel.architectury.event.events.LightningEvent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LightningBolt;
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.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.List;
@Mixin(LightningBolt.class)
public abstract class MixinLightningBolt extends Entity {
public MixinLightningBolt(EntityType<?> type, Level level) {
super(type, level);
throw new IllegalStateException();
}
@Inject(method = "tick", at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/level/Level;getEntities(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;)Ljava/util/List;",
ordinal = 0,
shift = At.Shift.BY,
by = 1
), locals = LocalCapture.CAPTURE_FAILHARD)
public void handleLightning(CallbackInfo ci, double d0, List<Entity> list) {
if (this.removed || this.level.isClientSide) {
return;
}
LightningEvent.STRIKE.invoker().onStrike((LightningBolt) (Object) this, this.level, this.position(), list);
}
}

View File

@@ -20,7 +20,6 @@
package me.shedaniel.architectury.networking;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import me.shedaniel.architectury.networking.NetworkManager.PacketContext;
import me.shedaniel.architectury.platform.Platform;
@@ -32,11 +31,13 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.ApiStatus;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -57,26 +58,28 @@ public final class NetworkChannel {
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public <T> void register(NetworkManager.Side side, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public <T> void register(Optional<NetworkManager.Side> side, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
public <T> void register(Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
String s = StringUtils.leftPad(String.valueOf(hashCodeString(type.toString())), 10, '0');
if (s.length() > 10) s = s.substring(0, 10);
MessageInfo<T> info = new MessageInfo<>(new ResourceLocation(id + "_" + s), encoder, decoder, messageConsumer);
// TODO: this is pretty wasteful; add a way to specify custom or numeric ids
String s = UUID.nameUUIDFromBytes(type.getName().getBytes(StandardCharsets.UTF_8)).toString().replace("-", "");
MessageInfo<T> info = new MessageInfo<>(new ResourceLocation(id + "/" + s), encoder, decoder, messageConsumer);
encoders.put(type, info);
NetworkManager.NetworkReceiver receiver = (buf, context) -> {
info.messageConsumer.accept(info.decoder.apply(buf), () -> context);
};
NetworkManager.registerReceiver(NetworkManager.clientToServer(), info.packetId, receiver);
NetworkManager.registerReceiver(NetworkManager.c2s(), info.packetId, receiver);
if (Platform.getEnvironment() == Env.CLIENT) {
NetworkManager.registerReceiver(NetworkManager.serverToClient(), info.packetId, receiver);
NetworkManager.registerReceiver(NetworkManager.s2c(), info.packetId, receiver);
}
}
@@ -90,46 +93,48 @@ public final class NetworkChannel {
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public <T> void register(int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public <T> void register(NetworkManager.Side side, int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
public <T> void register(Optional<NetworkManager.Side> side, int id, Class<T> type, BiConsumer<T, FriendlyByteBuf> encoder, Function<FriendlyByteBuf, T> decoder, BiConsumer<T, Supplier<PacketContext>> messageConsumer) {
register(type, encoder, decoder, messageConsumer);
}
private <T> Pair<MessageInfo<T>, FriendlyByteBuf> encode(T message) {
MessageInfo<T> messageInfo = (MessageInfo<T>) Objects.requireNonNull(encoders.get(message.getClass()));
public <T> Packet<?> toPacket(NetworkManager.Side side, T message) {
MessageInfo<T> messageInfo = (MessageInfo<T>) Objects.requireNonNull(encoders.get(message.getClass()), "Unknown message type! " + message);
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
messageInfo.encoder.accept(message, buf);
return new Pair<>(messageInfo, buf);
}
public <T> Packet<?> toPacket(NetworkManager.Side side, T message) {
Pair<MessageInfo<T>, FriendlyByteBuf> encoded = encode(message);
return NetworkManager.toPacket(side, encoded.getFirst().packetId, encoded.getSecond());
return NetworkManager.toPacket(side, messageInfo.packetId, buf);
}
public <T> void sendToPlayer(ServerPlayer player, T message) {
player.connection.send(toPacket(NetworkManager.s2c(), message));
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(toPacket(NetworkManager.s2c(), message));
}
public <T> void sendToPlayers(Iterable<ServerPlayer> players, T message) {
Packet<?> packet = toPacket(NetworkManager.s2c(), message);
for (ServerPlayer player : players) {
player.connection.send(packet);
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(packet);
}
}
@Environment(EnvType.CLIENT)
public <T> void sendToServer(T message) {
Minecraft.getInstance().getConnection().send(toPacket(NetworkManager.c2s(), message));
if (Minecraft.getInstance().getConnection() != null) {
Minecraft.getInstance().getConnection().send(toPacket(NetworkManager.c2s(), message));
} else {
throw new IllegalStateException("Unable to send packet to the server while not in game!");
}
}
@Environment(EnvType.CLIENT)

View File

@@ -30,6 +30,8 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import java.util.Objects;
public final class NetworkManager {
@ExpectPlatform
public static void registerReceiver(Side side, ResourceLocation id, NetworkReceiver receiver) {
@@ -42,19 +44,23 @@ public final class NetworkManager {
}
public static void sendToPlayer(ServerPlayer player, ResourceLocation id, FriendlyByteBuf buf) {
player.connection.send(toPacket(serverToClient(), id, buf));
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(toPacket(serverToClient(), id, buf));
}
public static void sendToPlayers(Iterable<ServerPlayer> players, ResourceLocation id, FriendlyByteBuf buf) {
Packet<?> packet = toPacket(serverToClient(), id, buf);
for (ServerPlayer player : players) {
player.connection.send(packet);
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(packet);
}
}
@Environment(EnvType.CLIENT)
public static void sendToServer(ResourceLocation id, FriendlyByteBuf buf) {
Minecraft.getInstance().getConnection().send(toPacket(clientToServer(), id, buf));
if (Minecraft.getInstance().getConnection() != null) {
Minecraft.getInstance().getConnection().send(toPacket(clientToServer(), id, buf));
} else {
throw new IllegalStateException("Unable to send packet to the server while not in game!");
}
}
@Environment(EnvType.CLIENT)
@@ -77,7 +83,7 @@ public final class NetworkManager {
Player getPlayer();
void queue(Runnable runnable);
Env getEnvironment();
default EnvType getEnv() {

View File

@@ -0,0 +1,21 @@
package me.shedaniel.architectury.registry.entity;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import java.util.function.Function;
@Environment(EnvType.CLIENT)
public final class EntityRenderers {
private EntityRenderers() {}
@ExpectPlatform
public static <T extends Entity> void register(EntityType<T> type, Function<EntityRenderDispatcher, EntityRenderer<T>> factory) {
throw new AssertionError();
}
}

View File

@@ -0,0 +1,13 @@
{
"required": true,
"package": "me.shedaniel.architectury.mixin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.7.11",
"client": [
],
"mixins": ["BlockLandingInvoker", "FluidTagsAccessor", "MixinLightningBolt"],
"injectors": {
"maxShiftBy": 5,
"defaultRequire": 1
}
}

View File

@@ -1,9 +1,3 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import shadow.org.apache.tools.zip.ZipEntry
import shadow.org.apache.tools.zip.ZipOutputStream
import shadow.org.codehaus.plexus.util.IOUtil
plugins {
id "com.github.johnrengelman.shadow" version "5.0.0"
id "com.matthewprenger.cursegradle"
@@ -14,7 +8,7 @@ loom {
}
configurations {
shadow
shadowCommon
dev
}
@@ -24,6 +18,7 @@ artifacts {
architectury {
platformSetupLoomIde()
fabric()
}
repositories {
@@ -37,15 +32,15 @@ dependencies {
modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modCompileOnly "com.terraformersmc:modmenu:${rootProject.mod_menu_version}"
implementation "net.jodah:typetools:0.6.2"
shadow "net.jodah:typetools:0.6.2"
shadowCommon "net.jodah:typetools:0.6.2"
compileOnly(project(path: ":common")) {
implementation(project(path: ":common")) {
transitive = false
}
runtimeOnly(project(path: ":common", configuration: "transformDevelopmentFabric")) {
developmentFabric(project(path: ":common")) {
transitive = false
}
shadow(project(path: ":common", configuration: "transformProductionFabric")) {
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) {
transitive = false
}
}
@@ -59,7 +54,7 @@ processResources {
shadowJar {
relocate "net.jodah.typetools", "me.shedaniel.architectury.shadowed.impl.net.jodah.typetools"
configurations = [project.configurations.shadow]
configurations = [project.configurations.shadowCommon]
classifier "shadow"
}
@@ -72,9 +67,10 @@ remapJar {
publishing {
publications {
mavenFabric(MavenPublication) {
artifactId = rootProject.archivesBaseName + "-fabric"
artifact(remapJar.archivePath) {
builtBy build
classifier "fabric"
classifier null
}
}
}

View File

@@ -20,9 +20,23 @@
package me.shedaniel.architectury.hooks.fabric;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
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 ((CollisionContextExtension) ctx).getEntity();
}
public interface CollisionContextExtension {
@Nullable
default Entity getEntity() {
return null;
}
}
}

View File

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

View File

@@ -21,23 +21,12 @@ package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.extensions.BlockEntityExtension;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(BlockEntityExtension.class)
public interface MixinBlockEntityExtension extends BlockEntityClientSerializable {
@Shadow(remap = false)
@NotNull
CompoundTag saveClientData(@NotNull CompoundTag tag);
@Shadow(remap = false)
void loadClientData(@NotNull BlockState pos, @NotNull CompoundTag tag);
@Override
default void fromClientTag(CompoundTag tag) {
BlockEntity entity = (BlockEntity) this;
@@ -48,6 +37,6 @@ public interface MixinBlockEntityExtension extends BlockEntityClientSerializable
@Override
default CompoundTag toClientTag(CompoundTag tag) {
return saveClientData(tag);
return ((BlockEntityExtension) this).saveClientData(tag);
}
}

View File

@@ -19,7 +19,7 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.events.EntityEvent;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.context.BlockPlaceContext;
@@ -35,9 +35,9 @@ public abstract class MixinBlockItem {
target = "Lnet/minecraft/world/item/context/BlockPlaceContext;getClickedPos()Lnet/minecraft/core/BlockPos;"),
cancellable = true)
private void place(BlockPlaceContext context, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = EntityEvent.PLACE_BLOCK.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());
InteractionResult result = BlockEvent.PLACE.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());
if (result != InteractionResult.PASS) {
cir.setReturnValue(result);
}
}
}
}

View File

@@ -0,0 +1,9 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.hooks.fabric.EntityHooksImpl;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(CollisionContext.class)
public interface MixinCollisionContext extends EntityHooksImpl.CollisionContextExtension {
}

View File

@@ -0,0 +1,32 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.hooks.fabric.EntityHooksImpl;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import org.jetbrains.annotations.Nullable;
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(EntityCollisionContext.class)
public abstract class MixinEntityCollisionContext implements CollisionContext, EntityHooksImpl.CollisionContextExtension {
@Unique
private Entity entity = null;
@Inject(method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
at = @At("RETURN"))
public void saveEntity(Entity entity, CallbackInfo ci) {
this.entity = entity;
}
@Nullable
@Override
public Entity getEntity() {
return entity;
}
}

View File

@@ -19,7 +19,7 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.events.PlayerEvent;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -44,7 +44,7 @@ public class MixinServerPlayerGameMode {
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private void onBreak(BlockPos blockPos, CallbackInfoReturnable<Boolean> cir, BlockState state) {
if (PlayerEvent.BREAK_BLOCK.invoker().breakBlock(this.level, blockPos, state, this.player, null) == InteractionResult.FAIL) {
if (BlockEvent.BREAK.invoker().breakBlock(this.level, blockPos, state, this.player, null) == InteractionResult.FAIL) {
cir.setReturnValue(false);
}
}

View File

@@ -23,40 +23,35 @@ import me.shedaniel.architectury.event.events.GuiEvent;
import me.shedaniel.architectury.event.events.InteractionEvent;
import me.shedaniel.architectury.event.events.client.ClientPlayerEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.ConnectScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.main.GameConfig;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
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.*;
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;
import java.io.File;
@Unique
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
// @formatter:off
@Shadow @Nullable public LocalPlayer player;
@Shadow @Nullable public HitResult hitResult;
@Shadow public abstract void setScreen(@Nullable Screen screen);
private boolean setScreenCancelled;
private String hostname;
private int port;
// @formatter:on
@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"))
@@ -79,10 +74,11 @@ public abstract class MixinMinecraft {
@ModifyVariable(
method = "setScreen",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V",
shift = At.Shift.BY,
by = 2),
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) {
@@ -90,7 +86,7 @@ public abstract class MixinMinecraft {
InteractionResultHolder<Screen> event = GuiEvent.SET_SCREEN.invoker().modifyScreen(screen);
switch (event.getResult()) {
case FAIL:
setScreenCancelled = true;
setScreenCancelled.set(true);
return old;
case SUCCESS:
screen = event.getObject();
@@ -98,56 +94,24 @@ public abstract class MixinMinecraft {
old.removed();
}
default:
setScreenCancelled = false;
setScreenCancelled.set(false);
return screen;
}
}
@Inject(
method = "setScreen",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V",
shift = At.Shift.BY,
by = 3),
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) {
if (setScreenCancelled.get()) {
ci.cancel();
}
}
@Redirect(
method = "<init>",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V"),
slice = @Slice(
from = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;resizeDisplay()V"),
to = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/LoadingOverlay;registerTextures(Lnet/minecraft/client/Minecraft;)V")
)
)
public void minecraftWhy(Minecraft mc, Screen screen) {
}
@Inject(
method = "<init>",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;resizeDisplay()V"),
locals = LocalCapture.CAPTURE_FAILHARD
)
public void saveLocals(GameConfig gc, CallbackInfo ci, File f, String string2, int j) {
hostname = string2;
port = j;
}
@SuppressWarnings({"UnresolvedMixinReference", "ConstantConditions"})
@Inject(
method = {"method_29338", "lambda$null$1"}, // <init>.lambda$null$1
at = @At("RETURN")
)
public void registerMainScreens(CallbackInfo ci) {
if (hostname != null) {
setScreen(new ConnectScreen(new TitleScreen(), (Minecraft) ((Object) this), hostname, port));
} else {
setScreen(new TitleScreen(true));
setScreenCancelled.set(false);
}
}
}

View File

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

View File

@@ -0,0 +1,15 @@
package me.shedaniel.architectury.registry.entity.fabric;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import java.util.function.Function;
public class EntityRenderersImpl {
public static <T extends Entity> void register(EntityType<T> type, Function<EntityRenderDispatcher, EntityRenderer<T>> factory) {
EntityRendererRegistry.INSTANCE.register(type, (manager, context) -> factory.apply(manager));
}
}

View File

@@ -1,35 +1,37 @@
{
"required": true,
"package": "me.shedaniel.architectury.mixin.fabric",
"plugin": "me.shedaniel.architectury.plugin.fabric.ArchitecturyMixinPlugin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.7.11",
"client": [
"client.MixinClientLevel",
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinEffectInstance",
"client.MixinGameRenderer",
"client.MixinIntegratedServer",
"client.MixinKeyboardHandler",
"client.MixinMinecraft",
"client.MixinMouseHandler",
"client.MixinMultiPlayerGameMode",
"client.MixinScreen",
"client.MixinTextureAtlas"
],
"mixins": [
"ExplosionPreInvoker",
"LivingDeathInvoker",
"MixinBlockEntityExtension",
"MixinBlockItem",
"MixinCommands",
"MixinDedicatedServer",
"MixinExplosion",
"MixinFurnaceResultSlot",
"MixinItemEntity",
"MixinLivingEntity",
"MixinPersistentEntitySectionManager", "MixinPlayer",
"required": true,
"package": "me.shedaniel.architectury.mixin.fabric",
"plugin": "me.shedaniel.architectury.plugin.fabric.ArchitecturyMixinPlugin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.7.11",
"client": [
"client.MixinClientLevel",
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinEffectInstance",
"client.MixinGameRenderer",
"client.MixinIntegratedServer",
"client.MixinKeyboardHandler",
"client.MixinMinecraft",
"client.MixinMouseHandler",
"client.MixinMultiPlayerGameMode",
"client.MixinScreen",
"client.MixinTextureAtlas"
],
"mixins": [
"ExplosionPreInvoker",
"LivingDeathInvoker",
"MixinBlockEntityExtension",
"MixinBlockItem",
"MixinCollisionContext",
"MixinCommands",
"MixinDedicatedServer",
"MixinEntityCollisionContext",
"MixinExplosion",
"MixinFurnaceResultSlot",
"MixinItemEntity",
"MixinLivingEntity",
"MixinPersistentEntitySectionManager", "MixinPlayer",
"MixinPlayerAdvancements",
"MixinPlayerList",
"MixinResultSlot",

View File

@@ -10,6 +10,7 @@
"license": "LGPL-3",
"environment": "*",
"mixins": [
"architectury-common.mixins.json",
"architectury.mixins.json"
],
"entrypoints": {
@@ -30,4 +31,4 @@
"custom": {
"modmenu:api": true
}
}
}

View File

@@ -4,11 +4,11 @@ plugins {
}
loom {
mixinConfig = "architectury.mixins.json"
mixinConfigs = ["architectury.mixins.json", "architectury-common.mixins.json"]
}
configurations {
shadow
shadowCommon
dev
}
@@ -18,6 +18,7 @@ artifacts {
architectury {
platformSetupLoomIde()
forge()
}
dependencies {
@@ -25,15 +26,15 @@ dependencies {
mappings loom.officialMojangMappings()
forge "net.minecraftforge:forge:${rootProject.architectury.minecraft}-${rootProject.forge_version}"
implementation "net.jodah:typetools:0.6.2"
shadow "net.jodah:typetools:0.6.2"
shadowCommon "net.jodah:typetools:0.6.2"
compileOnly(project(path: ":common")) {
implementation(project(path: ":common")) {
transitive = false
}
runtimeOnly(project(path: ":common", configuration: "transformDevelopmentForge")) {
developmentForge(project(path: ":common")) {
transitive = false
}
shadow(project(path: ":common", configuration: "transformProductionForge")) {
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) {
transitive = false
}
}
@@ -50,7 +51,7 @@ shadowJar {
exclude "fabric.mod.json"
exclude "architectury-common.accessWidener"
configurations = [project.configurations.shadow]
configurations = [project.configurations.shadowCommon]
classifier "shadow"
}
@@ -63,9 +64,10 @@ remapJar {
publishing {
publications {
mavenForge(MavenPublication) {
artifactId = rootProject.archivesBaseName + "-forge"
artifact(remapJar.archivePath) {
builtBy build
classifier "forge"
classifier null
}
}
}

View File

@@ -38,6 +38,7 @@ import net.minecraftforge.client.event.*;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
@@ -45,12 +46,12 @@ import java.util.List;
@OnlyIn(Dist.CLIENT)
public class EventHandlerImplClient {
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ItemTooltipEvent event) {
TooltipEvent.ITEM.invoker().append(event.getItemStack(), event.getToolTip(), event.getFlags());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(net.minecraftforge.event.TickEvent.ClientTickEvent event) {
if (event.phase == net.minecraftforge.event.TickEvent.Phase.START)
ClientTickEvent.CLIENT_PRE.invoker().tick(Minecraft.getInstance());
@@ -58,40 +59,40 @@ public class EventHandlerImplClient {
ClientTickEvent.CLIENT_POST.invoker().tick(Minecraft.getInstance());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RenderGameOverlayEvent.Post event) {
if (event.getType() == RenderGameOverlayEvent.ElementType.ALL)
GuiEvent.RENDER_HUD.invoker().renderHud(event.getMatrixStack(), event.getPartialTicks());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ClientPlayerNetworkEvent.LoggedInEvent event) {
ClientPlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(event.getPlayer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ClientPlayerNetworkEvent.LoggedOutEvent event) {
ClientPlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(event.getPlayer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ClientPlayerNetworkEvent.RespawnEvent event) {
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(event.getOldPlayer(), event.getNewPlayer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.InitGuiEvent.Pre event) {
if (GuiEvent.INIT_PRE.invoker().init(event.getGui(), event.getWidgetList(), (List<GuiEventListener>) event.getGui().children()) == InteractionResult.FAIL) {
if (GuiEvent.INIT_PRE.invoker().init(event.getGui(), event.getWidgetList(), (List<GuiEventListener>) event.getGui().children()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.InitGuiEvent.Post event) {
GuiEvent.INIT_POST.invoker().init(event.getGui(), event.getWidgetList(), (List<GuiEventListener>) event.getGui().children());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RenderGameOverlayEvent.Text event) {
if (Minecraft.getInstance().options.renderDebug) {
GuiEvent.DEBUG_TEXT_LEFT.invoker().gatherText(event.getLeft());
@@ -99,7 +100,7 @@ public class EventHandlerImplClient {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(net.minecraftforge.client.event.ClientChatEvent event) {
InteractionResultHolder<String> process = ClientChatEvent.CLIENT.invoker().process(event.getMessage());
if (process.getObject() != null)
@@ -108,7 +109,7 @@ public class EventHandlerImplClient {
event.setCanceled(true);
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ClientChatReceivedEvent event) {
InteractionResultHolder<Component> process = ClientChatEvent.CLIENT_RECEIVED.invoker().process(event.getType(), event.getMessage(), event.getSenderUUID());
if (process.getObject() != null)
@@ -117,15 +118,15 @@ public class EventHandlerImplClient {
event.setCanceled(true);
}
@SubscribeEvent
public static void event(WorldEvent.Save event) {
if (event.getWorld() instanceof ClientLevel) {
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(WorldEvent.Load event) {
if (event.getWorld().isClientSide()) {
ClientLevel world = (ClientLevel) event.getWorld();
ClientLifecycleEvent.CLIENT_WORLD_LOAD.invoker().act(world);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiOpenEvent event) {
InteractionResultHolder<Screen> result = GuiEvent.SET_SCREEN.invoker().modifyScreen(event.getGui());
switch (result.getResult()) {
@@ -137,29 +138,29 @@ public class EventHandlerImplClient {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.DrawScreenEvent.Pre event) {
if (GuiEvent.RENDER_PRE.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()) == InteractionResult.FAIL) {
if (GuiEvent.RENDER_PRE.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.DrawScreenEvent.Post event) {
GuiEvent.RENDER_POST.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.RightClickEmpty event) {
InteractionEvent.CLIENT_RIGHT_CLICK_AIR.invoker().click(event.getPlayer(), event.getHand());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.LeftClickEmpty event) {
InteractionEvent.CLIENT_LEFT_CLICK_AIR.invoker().click(event.getPlayer(), event.getHand());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RecipesUpdatedEvent event) {
RecipeUpdateEvent.EVENT.invoker().update(event.getRecipeManager());
}
@@ -167,7 +168,7 @@ public class EventHandlerImplClient {
private static final ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
private static final ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RenderTooltipEvent.Pre event) {
if (TooltipEvent.RENDER_FORGE_PRE.invoker().renderTooltip(event.getMatrixStack(), event.getLines(), event.getX(), event.getY()) == InteractionResult.FAIL) {
event.setCanceled(true);
@@ -181,7 +182,7 @@ public class EventHandlerImplClient {
event.setY(positionContext.getTooltipY());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RenderTooltipEvent.Color event) {
TooltipEventColorContextImpl colorContext = tooltipColorContext.get();
colorContext.reset();
@@ -194,127 +195,127 @@ public class EventHandlerImplClient {
event.setBorderStart(colorContext.getOutlineGradientTopColor());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseScrollEvent.Pre event) {
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getScrollDelta()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getScrollDelta()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseScrollEvent.Post event) {
ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getScrollDelta());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseClickedEvent.Pre event) {
if (ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseClickedEvent.Post event) {
ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseDragEvent.Pre event) {
if (ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseDragEvent.Post event) {
ClientScreenInputEvent.MOUSE_DRAGGED_POST.invoker().mouseDragged(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseReleasedEvent.Pre event) {
if (ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.MouseReleasedEvent.Post event) {
ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardCharTypedEvent.Pre event) {
if (ClientScreenInputEvent.CHAR_TYPED_PRE.invoker().charTyped(Minecraft.getInstance(), event.getGui(), event.getCodePoint(), event.getModifiers()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.CHAR_TYPED_PRE.invoker().charTyped(Minecraft.getInstance(), event.getGui(), event.getCodePoint(), event.getModifiers()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardCharTypedEvent.Post event) {
ClientScreenInputEvent.CHAR_TYPED_POST.invoker().charTyped(Minecraft.getInstance(), event.getGui(), event.getCodePoint(), event.getModifiers());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardKeyPressedEvent.Pre event) {
if (ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardKeyPressedEvent.Post event) {
ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardKeyReleasedEvent.Pre event) {
if (ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) == InteractionResult.FAIL) {
if (ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(GuiScreenEvent.KeyboardKeyReleasedEvent.Post event) {
ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(InputEvent.MouseScrollEvent event) {
if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDelta()) == InteractionResult.FAIL) {
if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDelta()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(InputEvent.RawMouseEvent event) {
if (ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()) == InteractionResult.FAIL) {
if (ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()) != InteractionResult.PASS) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(InputEvent.MouseInputEvent event) {
ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(InputEvent.KeyInputEvent event) {
ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(Minecraft.getInstance(), event.getKey(), event.getScanCode(), event.getAction(), event.getModifiers());
}
@OnlyIn(Dist.CLIENT)
public static class ModBasedEventHandler {
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(net.minecraftforge.client.event.TextureStitchEvent.Pre event) {
TextureStitchEvent.PRE.invoker().stitch(event.getMap(), event::addSprite);
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(net.minecraftforge.client.event.TextureStitchEvent.Post event) {
TextureStitchEvent.POST.invoker().stitch(event.getMap());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLClientSetupEvent event) {
ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(event.getMinecraftSupplier().get());
}

View File

@@ -44,18 +44,20 @@ import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.*;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.BlockEvent.BreakEvent;
import net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent;
import net.minecraftforge.event.world.ExplosionEvent.Detonate;
import net.minecraftforge.event.world.ExplosionEvent.Start;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.event.server.*;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
public class EventHandlerImplCommon {
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ServerTickEvent event) {
if (event.phase == Phase.START)
TickEvent.SERVER_PRE.invoker().tick(ServerLifecycleHooks.getCurrentServer());
@@ -63,7 +65,7 @@ public class EventHandlerImplCommon {
TickEvent.SERVER_POST.invoker().tick(ServerLifecycleHooks.getCurrentServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(WorldTickEvent event) {
if (event.side == LogicalSide.SERVER) {
if (event.phase == Phase.START)
@@ -73,47 +75,47 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLServerStartingEvent event) {
LifecycleEvent.SERVER_STARTING.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLServerStartedEvent event) {
LifecycleEvent.SERVER_STARTED.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLServerStoppingEvent event) {
LifecycleEvent.SERVER_STOPPING.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLServerStoppedEvent event) {
LifecycleEvent.SERVER_STOPPED.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RegisterCommandsEvent event) {
CommandRegistrationEvent.EVENT.invoker().register(event.getDispatcher(), event.getEnvironment());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerLoggedInEvent event) {
PlayerEvent.PLAYER_JOIN.invoker().join((ServerPlayer) event.getPlayer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerLoggedOutEvent event) {
PlayerEvent.PLAYER_QUIT.invoker().quit((ServerPlayer) event.getPlayer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerRespawnEvent event) {
PlayerEvent.PLAYER_RESPAWN.invoker().respawn((ServerPlayer) event.getPlayer(), event.isEndConquered());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(CommandEvent event) {
CommandPerformEvent performEvent = new CommandPerformEvent(event.getParseResults(), event.getException());
if (CommandPerformEvent.EVENT.invoker().act(performEvent) == InteractionResult.FAIL) {
@@ -123,7 +125,7 @@ public class EventHandlerImplCommon {
event.setException(performEvent.getThrowable());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerTickEvent event) {
if (event.phase == Phase.START) {
TickEvent.PLAYER_PRE.invoker().tick(event.player);
@@ -132,7 +134,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ServerChatEvent event) {
InteractionResultHolder<Component> process = ChatEvent.SERVER.invoker().process(event.getPlayer(), event.getMessage(), event.getComponent());
if (process.getObject() != null)
@@ -141,7 +143,7 @@ public class EventHandlerImplCommon {
event.setCanceled(true);
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(WorldEvent.Load event) {
if (event.getWorld() instanceof ServerLevel) {
ServerLevel world = (ServerLevel) event.getWorld();
@@ -149,7 +151,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(WorldEvent.Unload event) {
if (event.getWorld() instanceof ServerLevel) {
ServerLevel world = (ServerLevel) event.getWorld();
@@ -157,7 +159,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(WorldEvent.Save event) {
if (event.getWorld() instanceof ServerLevel) {
ServerLevel world = (ServerLevel) event.getWorld();
@@ -165,89 +167,89 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(LivingDeathEvent event) {
if (EntityEvent.LIVING_DEATH.invoker().die(event.getEntityLiving(), event.getSource()) == InteractionResult.FAIL) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(AdvancementEvent event) {
if (event.getPlayer() instanceof ServerPlayer) {
PlayerEvent.PLAYER_ADVANCEMENT.invoker().award((ServerPlayer) event.getPlayer(), event.getAdvancement());
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(Clone event) {
if (event.getOriginal() instanceof ServerPlayer && event.getPlayer() instanceof ServerPlayer) {
PlayerEvent.PLAYER_CLONE.invoker().clone((ServerPlayer) event.getOriginal(), (ServerPlayer) event.getPlayer(), !event.isWasDeath());
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(Start event) {
if (ExplosionEvent.PRE.invoker().explode(event.getWorld(), event.getExplosion()) == InteractionResult.FAIL) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(Detonate event) {
ExplosionEvent.DETONATE.invoker().explode(event.getWorld(), event.getExplosion(), event.getAffectedEntities());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(LivingAttackEvent event) {
if (EntityEvent.LIVING_ATTACK.invoker().attack(event.getEntityLiving(), event.getSource(), event.getAmount()) == InteractionResult.FAIL) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(EntityJoinWorldEvent event) {
if (EntityEvent.ADD.invoker().add(event.getEntity(), event.getWorld()) == InteractionResult.FAIL) {
event.setCanceled(true);
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ItemCraftedEvent event) {
PlayerEvent.CRAFT_ITEM.invoker().craft(event.getPlayer(), event.getCrafting(), event.getInventory());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ItemSmeltedEvent event) {
PlayerEvent.SMELT_ITEM.invoker().smelt(event.getPlayer(), event.getSmelting());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(EntityItemPickupEvent event) {
PlayerEvent.PICKUP_ITEM_PRE.invoker().canPickup(event.getPlayer(), event.getItem(), event.getItem().getItem());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ItemPickupEvent event) {
PlayerEvent.PICKUP_ITEM_POST.invoker().pickup(event.getPlayer(), event.getOriginalEntity(), event.getStack());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(ItemTossEvent event) {
PlayerEvent.DROP_ITEM.invoker().drop(event.getPlayer(), event.getEntityItem());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerContainerEvent.Open event) {
PlayerEvent.OPEN_MENU.invoker().open(event.getPlayer(), event.getContainer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerContainerEvent.Close event) {
PlayerEvent.CLOSE_MENU.invoker().close(event.getPlayer(), event.getContainer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.RightClickItem event) {
InteractionResultHolder<ItemStack> result = InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(event.getPlayer(), event.getHand());
if (result.getResult() != InteractionResult.PASS) {
@@ -256,7 +258,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.RightClickBlock event) {
InteractionResult result = InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
if (result != InteractionResult.PASS) {
@@ -267,7 +269,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.EntityInteract event) {
InteractionResult result = InteractionEvent.INTERACT_ENTITY.invoker().interact(event.getPlayer(), event.getTarget(), event.getHand());
if (result != InteractionResult.PASS) {
@@ -276,7 +278,7 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerInteractEvent.LeftClickBlock event) {
InteractionResult result = InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
if (result != InteractionResult.PASS) {
@@ -287,10 +289,10 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
public static void event(BlockEvent.BreakEvent event) {
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(BreakEvent event) {
if (event.getPlayer() instanceof ServerPlayer && event.getWorld() instanceof Level) {
InteractionResult result = PlayerEvent.BREAK_BLOCK.invoker().breakBlock((Level) event.getWorld(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
InteractionResult result = BlockEvent.BREAK.invoker().breakBlock((Level) event.getWorld(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
@Override
public int getAsInt() {
return event.getExpToDrop();
@@ -307,22 +309,22 @@ public class EventHandlerImplCommon {
}
}
@SubscribeEvent
public static void event(BlockEvent.EntityPlaceEvent event) {
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(EntityPlaceEvent event) {
if (event.getWorld() instanceof Level) {
InteractionResult result = EntityEvent.PLACE_BLOCK.invoker().placeBlock((Level) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
InteractionResult result = BlockEvent.PLACE.invoker().placeBlock((Level) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
if (result != InteractionResult.PASS) {
event.setCanceled(true);
}
}
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(FMLServerAboutToStartEvent event) {
LifecycleEvent.SERVER_BEFORE_START.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(PlayerChangedDimensionEvent event) {
if (event.getPlayer() instanceof ServerPlayer) {
PlayerEvent.CHANGE_DIMENSION.invoker().change((ServerPlayer) event.getPlayer(), event.getFrom(), event.getTo());

View File

@@ -20,9 +20,16 @@
package me.shedaniel.architectury.hooks.forge;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
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.getEntity();
}
}

View File

@@ -0,0 +1,79 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.hooks.forge;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagCollection;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
public class TagHooksImpl {
public static <T> Tag.Named<T> getOptional(ResourceLocation id, Supplier<TagCollection<T>> collection) {
return new Tag.Named<T>() {
private volatile Tag<T> backend;
private volatile WeakReference<TagCollection<T>> backendCollection;
@Override
public ResourceLocation getName() {
return id;
}
@Override
public boolean contains(T object) {
return getBackend().contains(object);
}
@Override
public List<T> getValues() {
return getBackend().getValues();
}
private Tag<T> getBackend() {
TagCollection<T> currentCollection = collection.get();
if (backend == null || backendCollection == null || backendCollection.get() != currentCollection) { // If not initialized or was tag changed.
backendCollection = new WeakReference<>(currentCollection);
return backend = currentCollection.getTagOrEmpty(id);
} else {
return backend;
}
}
@Override
public String toString() {
return "OptionalNamedTag[" + getName().toString() + ']';
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof Named && Objects.equals(getName(), ((Named) o).getName());
}
@Override
public int hashCode() {
return getName().hashCode();
}
};
}
}

View File

@@ -0,0 +1,65 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.mixin.forge;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameRules;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.function.BiConsumer;
@Mixin(GameRules.class)
public interface GameRulesAccessor {
/**
* Spliting simple classes because mixin can't handle refmap using the same name
*/
@Mixin(GameRules.BooleanValue.class)
interface BooleanValue {
@Invoker("create")
static GameRules.Type<GameRules.BooleanValue> invokeCreateArchitectury(boolean value, BiConsumer<MinecraftServer, GameRules.BooleanValue> biConsumer) {
throw new AssertionError();
}
}
@Mixin(GameRules.BooleanValue.class)
interface BooleanValueSimple {
@Invoker("create")
static GameRules.Type<GameRules.BooleanValue> invokeCreateArchitectury(boolean value) {
throw new AssertionError();
}
}
@Mixin(GameRules.IntegerValue.class)
interface IntegerValue {
@Invoker("create")
static GameRules.Type<GameRules.IntegerValue> invokeCreateArchitectury(int value, BiConsumer<MinecraftServer, GameRules.IntegerValue> biConsumer) {
throw new AssertionError();
}
}
@Mixin(GameRules.IntegerValue.class)
interface IntegerValueSimple {
@Invoker("create")
static GameRules.Type<GameRules.IntegerValue> invokeCreateArchitectury(int value) {
throw new AssertionError();
}
}
}

View File

@@ -21,19 +21,22 @@ package me.shedaniel.architectury.mixin.forge;
import me.shedaniel.architectury.extensions.BlockEntityExtension;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.extensions.IForgeTileEntity;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(BlockEntityExtension.class)
public interface MixinBlockEntityExtension extends IForgeTileEntity {
@Shadow(remap = false)
void loadClientData(@NotNull BlockState pos, @NotNull CompoundTag tag);
@Override
default void handleUpdateTag(BlockState state, CompoundTag tag) {
loadClientData(state, tag);
((BlockEntityExtension) this).loadClientData(state, tag);
}
@Override
default void onDataPacket(Connection connection, ClientboundBlockEntityDataPacket packet) {
((BlockEntityExtension) this).loadClientData(((BlockEntity) this).getBlockState(), packet.getTag());
}
}

View File

@@ -27,6 +27,7 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.network.NetworkEvent;
import java.util.Set;
@@ -38,7 +39,7 @@ import static me.shedaniel.architectury.networking.forge.NetworkManagerImpl.SYNC
public class ClientNetworkingManager {
public static void initClient() {
NetworkManagerImpl.CHANNEL.addListener(NetworkManagerImpl.createPacketHandler(NetworkEvent.ServerCustomPayloadEvent.class, NetworkManagerImpl.S2C));
MinecraftForge.EVENT_BUS.<ClientPlayerNetworkEvent.LoggedOutEvent>addListener(event -> NetworkManagerImpl.serverReceivables.clear());
MinecraftForge.EVENT_BUS.register(ClientNetworkingManager.class);
NetworkManagerImpl.registerS2CReceiver(SYNC_IDS, (buffer, context) -> {
Set<ResourceLocation> receivables = NetworkManagerImpl.serverReceivables;
@@ -54,4 +55,9 @@ public class ClientNetworkingManager {
public static Player getClientPlayer() {
return Minecraft.getInstance().player;
}
}
@SubscribeEvent
public static void loggedOut(ClientPlayerNetworkEvent.LoggedOutEvent event) {
NetworkManagerImpl.serverReceivables.clear();
}
}

View File

@@ -22,6 +22,7 @@ package me.shedaniel.architectury.networking.forge;
import com.google.common.collect.*;
import io.netty.buffer.Unpooled;
import me.shedaniel.architectury.forge.ArchitecturyForge;
import me.shedaniel.architectury.networking.NetworkManager;
import me.shedaniel.architectury.networking.NetworkManager.NetworkReceiver;
import me.shedaniel.architectury.utils.Env;
@@ -34,8 +35,10 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkRegistry;
@@ -49,6 +52,7 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class NetworkManagerImpl {
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, NetworkReceiver receiver) {
if (side == NetworkManager.Side.C2S) {
@@ -79,9 +83,6 @@ public class NetworkManagerImpl {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient);
MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedInEvent>addListener(event -> NetworkManager.sendToPlayer((ServerPlayer) event.getPlayer(), SYNC_IDS, sendSyncPacket(C2S)));
MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedOutEvent>addListener(event -> clientReceivables.removeAll(event.getPlayer()));
registerC2SReceiver(SYNC_IDS, (buffer, context) -> {
Set<ResourceLocation> receivables = (Set<ResourceLocation>) clientReceivables.get(context.getPlayer());
int size = buffer.readInt();
@@ -157,4 +158,14 @@ public class NetworkManagerImpl {
}
return packetBuffer;
}
@SubscribeEvent
public static void loggedIn(PlayerEvent.PlayerLoggedInEvent event) {
NetworkManager.sendToPlayer((ServerPlayer) event.getPlayer(), SYNC_IDS, sendSyncPacket(C2S));
}
@SubscribeEvent
public static void loggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
clientReceivables.removeAll(event.getPlayer());
}
}

View File

@@ -0,0 +1,15 @@
package me.shedaniel.architectury.registry.entity.forge;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import java.util.function.Function;
public class EntityRenderersImpl {
public static <T extends Entity> void register(EntityType<T> type, Function<EntityRenderDispatcher, EntityRenderer<T>> factory) {
RenderingRegistry.registerEntityRenderingHandler(type, factory::apply);
}
}

View File

@@ -20,6 +20,7 @@
package me.shedaniel.architectury.registry.forge;
import com.google.common.collect.Lists;
import me.shedaniel.architectury.forge.ArchitecturyForge;
import me.shedaniel.architectury.hooks.biome.*;
import me.shedaniel.architectury.mixin.forge.BiomeGenerationSettingsBuilderAccessor;
import me.shedaniel.architectury.mixin.forge.MobSpawnSettingsBuilderAccessor;
@@ -34,10 +35,11 @@ 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 net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder;
import net.minecraftforge.common.world.MobSpawnInfoBuilder;
import net.minecraftforge.event.world.BiomeLoadingEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
@@ -49,6 +51,7 @@ import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.function.Supplier;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class BiomeModificationsImpl {
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> MODIFICATIONS = Lists.newArrayList();
@@ -68,25 +71,6 @@ public class BiomeModificationsImpl {
MODIFICATIONS.add(Pair.of(predicate, modifier));
}
static {
MinecraftForge.EVENT_BUS.<BiomeLoadingEvent>addListener(event -> {
BiomeContext biomeContext = wrapSelectionContext(event);
BiomeProperties.Mutable mutableBiome = new MutableBiomeWrapped(event);
for (Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>> pair : MODIFICATIONS) {
if (pair.getLeft().test(biomeContext)) {
pair.getRight().accept(biomeContext, mutableBiome);
}
}
MutableClimatePropertiesWrapped climateProperties = (MutableClimatePropertiesWrapped) mutableBiome.getClimateProperties();
if (climateProperties.dirty) {
event.setClimate(new Biome.ClimateSettings(climateProperties.precipitation,
climateProperties.temperature,
climateProperties.temperatureModifier,
climateProperties.downfall));
}
});
}
private static BiomeContext wrapSelectionContext(BiomeLoadingEvent event) {
return new BiomeContext() {
BiomeProperties properties = new BiomeWrapped(event);
@@ -446,4 +430,22 @@ public class BiomeModificationsImpl {
return this;
}
}
@SubscribeEvent
public static void onBiomeLoading(BiomeLoadingEvent event) {
BiomeContext biomeContext = wrapSelectionContext(event);
BiomeProperties.Mutable mutableBiome = new MutableBiomeWrapped(event);
for (Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>> pair : MODIFICATIONS) {
if (pair.getLeft().test(biomeContext)) {
pair.getRight().accept(biomeContext, mutableBiome);
}
}
MutableClimatePropertiesWrapped climateProperties = (MutableClimatePropertiesWrapped) mutableBiome.getClimateProperties();
if (climateProperties.dirty) {
event.setClimate(new Biome.ClimateSettings(climateProperties.precipitation,
climateProperties.temperature,
climateProperties.temperatureModifier,
climateProperties.downfall));
}
}
}

View File

@@ -28,6 +28,7 @@ import net.minecraft.client.color.item.ItemColor;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
@@ -40,19 +41,24 @@ public class ColorHandlersImpl {
static {
EventBuses.onRegistered(ArchitecturyForge.MOD_ID, bus -> {
bus.<ColorHandlerEvent.Item>addListener(event -> {
for (Pair<ItemColor, Supplier<ItemLike>[]> pair : ITEM_COLORS) {
event.getItemColors().register(pair.getLeft(), unpackItems(pair.getRight()));
}
});
bus.<ColorHandlerEvent.Block>addListener(event -> {
for (Pair<BlockColor, Supplier<Block>[]> pair : BLOCK_COLORS) {
event.getBlockColors().register(pair.getLeft(), unpackBlocks(pair.getRight()));
}
});
bus.register(ColorHandlersImpl.class);
});
}
@SubscribeEvent
public static void onItemColorEvent(ColorHandlerEvent.Item event) {
for (Pair<ItemColor, Supplier<ItemLike>[]> pair : ITEM_COLORS) {
event.getItemColors().register(pair.getLeft(), unpackItems(pair.getRight()));
}
}
@SubscribeEvent
public static void onBlockColorEvent(ColorHandlerEvent.Block event) {
for (Pair<BlockColor, Supplier<Block>[]> pair : BLOCK_COLORS) {
event.getBlockColors().register(pair.getLeft(), unpackBlocks(pair.getRight()));
}
}
@SafeVarargs
public static void registerItemColors(ItemColor itemColor, Supplier<ItemLike>... items) {
Objects.requireNonNull(itemColor, "color is null!");

View File

@@ -19,6 +19,7 @@
package me.shedaniel.architectury.registry.forge;
import me.shedaniel.architectury.mixin.forge.GameRulesAccessor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameRules;
@@ -26,20 +27,20 @@ import java.util.function.BiConsumer;
public class GameRuleFactoryImpl {
private GameRuleFactoryImpl() {}
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue) {
return GameRules.BooleanValue.create(defaultValue);
return GameRulesAccessor.BooleanValueSimple.invokeCreateArchitectury(defaultValue);
}
public static GameRules.Type<GameRules.BooleanValue> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changedCallback) {
return GameRules.BooleanValue.create(defaultValue, changedCallback);
return GameRulesAccessor.BooleanValue.invokeCreateArchitectury(defaultValue, changedCallback);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue) {
return GameRules.IntegerValue.create(defaultValue);
return GameRulesAccessor.IntegerValueSimple.invokeCreateArchitectury(defaultValue);
}
public static GameRules.Type<GameRules.IntegerValue> createIntRule(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changedCallback) {
return GameRules.IntegerValue.create(defaultValue, changedCallback);
return GameRulesAccessor.IntegerValue.invokeCreateArchitectury(defaultValue, changedCallback);
}
}

View File

@@ -20,38 +20,40 @@
package me.shedaniel.architectury.registry.forge;
import com.google.common.collect.Lists;
import me.shedaniel.architectury.forge.ArchitecturyForge;
import net.minecraft.client.Minecraft;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddReloadListenerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.List;
@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID)
public class ReloadListenersImpl {
private static List<PreparableReloadListener> serverDataReloadListeners = Lists.newArrayList();
static {
MinecraftForge.EVENT_BUS.<AddReloadListenerEvent>addListener(event -> {
for (PreparableReloadListener listener : serverDataReloadListeners) {
event.addListener(listener);
}
});
}
public static void registerReloadListener(PackType type, PreparableReloadListener listener) {
if (type == PackType.SERVER_DATA) {
serverDataReloadListeners.add(listener);
} else if (type == PackType.CLIENT_RESOURCES) {
reloadClientReloadListener(listener);
registerClientReloadListener(listener);
}
}
@OnlyIn(Dist.CLIENT)
private static void reloadClientReloadListener(PreparableReloadListener listener) {
private static void registerClientReloadListener(PreparableReloadListener listener) {
((ReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListener(listener);
}
@SubscribeEvent
public static void addReloadListeners(AddReloadListenerEvent event) {
for (PreparableReloadListener listener : serverDataReloadListeners) {
event.addListener(listener);
}
}
}

View File

@@ -33,7 +33,3 @@ public-f net.minecraft.world.biome.BiomeAmbience field_242524_f # foliageColor
public-f net.minecraft.world.biome.BiomeAmbience field_242525_g # grassColor
public-f net.minecraft.world.biome.BiomeAmbience field_242526_h # grassColorModifier
public net.minecraft.world.storage.FolderName <init>(Ljava/lang/String;)V
public net.minecraft.world.GameRules$BooleanValue func_223567_b(ZLjava/util/function/BiConsumer;)Lnet/minecraft/world/GameRules$RuleType; # create
public net.minecraft.world.GameRules$BooleanValue func_223568_b(Z)Lnet/minecraft/world/GameRules$RuleType; # create
public net.minecraft.world.GameRules$IntegerValue func_223564_a(ILjava/util/function/BiConsumer;)Lnet/minecraft/world/GameRules$RuleType; # create
public net.minecraft.world.GameRules$IntegerValue func_223559_b(I)Lnet/minecraft/world/GameRules$RuleType; # create

View File

@@ -8,7 +8,7 @@
],
"mixins": [
"BiomeGenerationSettingsBuilderAccessor", "MixinRegistryEntry", "MixinBlockEntity", "MixinBlockEntityExtension",
"MobSpawnSettingsBuilderAccessor"
"MobSpawnSettingsBuilderAccessor", "GameRulesAccessor", "GameRulesAccessor$BooleanValue", "GameRulesAccessor$BooleanValueSimple", "GameRulesAccessor$IntegerValue", "GameRulesAccessor$IntegerValueSimple"
],
"injectors": {
"defaultRequire": 1

View File

@@ -1,8 +1,8 @@
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
minecraft_version=21w06a
supported_version=21w06a
minecraft_version=21w14a
supported_version=21w14a
cf_type=beta
@@ -11,8 +11,9 @@ archives_base_name_snapshot=architectury-snapshot
base_version=2.0
maven_group=me.shedaniel
fabric_loader_version=0.11.1
fabric_api_version=0.30.2+1.17
mod_menu_version=2.0.0-beta.2
fabric_loader_version=0.11.3
fabric_api_version=0.32.7+1.17
mod_menu_version=2.0.0-beta.3
#forge_version=35.1.36
#forge_version=36
.0.42

View File

@@ -1,8 +1,7 @@
pluginManagement {
repositories {
jcenter()
maven { url "https://maven.fabricmc.net/" }
maven { url "https://dl.bintray.com/shedaniel/cloth" }
maven { url "https://maven.shedaniel.me/" }
maven { url "https://files.minecraftforge.net/maven/" }
gradlePluginPortal()
}

View File

@@ -21,12 +21,13 @@ package me.shedaniel.architectury.test;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.test.debug.ConsoleMessageSink;
import me.shedaniel.architectury.test.events.DebugEvents;
import me.shedaniel.architectury.test.debug.MessageSink;
import me.shedaniel.architectury.test.debug.client.ClientOverlayMessageSink;
import me.shedaniel.architectury.test.events.DebugEvents;
import me.shedaniel.architectury.test.gamerule.TestGameRules;
import me.shedaniel.architectury.test.registry.TestRegistries;
import me.shedaniel.architectury.test.registry.client.TestKeybinds;
import me.shedaniel.architectury.test.tags.TestTags;
import me.shedaniel.architectury.utils.Env;
import me.shedaniel.architectury.utils.EnvExecutor;
@@ -38,6 +39,7 @@ public class TestMod {
DebugEvents.initialize();
TestRegistries.initialize();
TestGameRules.init();
TestTags.initialize();
if (Platform.getEnvironment() == Env.CLIENT)
TestKeybinds.initialize();
}

View File

@@ -27,6 +27,7 @@ import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.screens.ChatScreen;
import net.minecraft.core.Position;
import net.minecraft.core.Vec3i;
import net.minecraft.network.chat.TranslatableComponent;
@@ -49,6 +50,14 @@ public class DebugEvents {
}
public static void debugEvents() {
BlockEvent.BREAK.register((world, pos, state, player, xp) -> {
SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
BlockEvent.PLACE.register((world, pos, state, placer) -> {
SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world));
return InteractionResult.PASS;
});
ChatEvent.SERVER.register((player, message, component) -> {
SINK.accept("Server chat received: " + message);
return InteractionResultHolder.pass(component);
@@ -78,10 +87,6 @@ public class DebugEvents {
}
return InteractionResult.PASS;
});
EntityEvent.PLACE_BLOCK.register((world, pos, state, placer) -> {
SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world));
return InteractionResult.PASS;
});
ExplosionEvent.DETONATE.register((world, explosion, affectedEntities) -> {
SINK.accept(world.dimension().location() + " explodes at " + toShortString(ExplosionHooks.getPosition(explosion)) + logSide(world));
});
@@ -155,10 +160,6 @@ public class DebugEvents {
SINK.accept(player.getScoreboardName() + " drops " + new TranslatableComponent(entity.getItem().getDescriptionId()).getString() + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.BREAK_BLOCK.register((world, pos, state, player, xp) -> {
SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.OPEN_MENU.register((player, menu) -> {
SINK.accept(player.getScoreboardName() + " opens " + toSimpleName(menu) + logSide(player.level));
});
@@ -168,6 +169,9 @@ public class DebugEvents {
PlayerEvent.CHANGE_DIMENSION.register((player, oldLevel, newLevel) -> {
SINK.accept(player.getScoreboardName() + " switched from " + oldLevel.location() + " to " + newLevel.location() + logSide(player.level));
});
LightningEvent.STRIKE.register((bolt, level, pos, toStrike) -> {
SINK.accept(bolt.getScoreboardName() + " struck at " + toShortString(pos) + logSide(level));
});
}
public static String toShortString(Vec3i pos) {
@@ -208,10 +212,6 @@ public class DebugEvents {
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.register((oldPlayer, newPlayer) -> {
SINK.accept(newPlayer.getScoreboardName() + " respawned (client)");
});
GuiEvent.SET_SCREEN.register((screen -> {
SINK.accept("Screen has been changed to " + toSimpleName(screen));
return InteractionResultHolder.pass(screen);
}));
GuiEvent.INIT_PRE.register((screen, widgets, children) -> {
SINK.accept(toSimpleName(screen) + " initializes");
return InteractionResult.PASS;
@@ -268,6 +268,14 @@ public class DebugEvents {
SINK.accept("Raw Key pressed: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString());
return InteractionResult.PASS;
});
GuiEvent.SET_SCREEN.register(screen -> {
if (screen instanceof ChatScreen) {
return InteractionResultHolder.fail(screen);
}
SINK.accept("Screen has been changed to " + toSimpleName(screen));
return InteractionResultHolder.pass(screen);
});
}
private static String toSimpleName(Object o) {

View File

@@ -19,16 +19,24 @@
package me.shedaniel.architectury.test.registry;
import me.shedaniel.architectury.hooks.EntityHooks;
import me.shedaniel.architectury.registry.BlockProperties;
import me.shedaniel.architectury.registry.DeferredRegister;
import me.shedaniel.architectury.registry.RegistrySupplier;
import me.shedaniel.architectury.test.TestMod;
import me.shedaniel.architectury.test.tab.TestCreativeTabs;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import static me.shedaniel.architectury.test.TestMod.SINK;
public class TestRegistries {
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(TestMod.MOD_ID, Registry.ITEM_REGISTRY);
@@ -39,8 +47,19 @@ public class TestRegistries {
public static final RegistrySupplier<Block> TEST_BLOCK = BLOCKS.register("test_block", () ->
new Block(BlockProperties.copy(Blocks.STONE)));
public static final RegistrySupplier<Block> COLLISION_BLOCK = BLOCKS.register("collision_block", () ->
new Block(BlockProperties.copy(Blocks.STONE)) {
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter bg, BlockPos pos, CollisionContext ctx) {
SINK.accept(EntityHooks.fromCollision(ctx) + " is colliding with " + state);
return super.getCollisionShape(state, bg, pos, ctx);
}
});
public static final RegistrySupplier<Item> TEST_BLOCK_ITEM = ITEMS.register("test_block", () ->
new BlockItem(TEST_BLOCK.get(), new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
public static final RegistrySupplier<Item> COLLISION_BLOCK_ITEM = ITEMS.register("collision_block", () ->
new BlockItem(COLLISION_BLOCK.get(), new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
public static void initialize() {
BLOCKS.register();

View File

@@ -0,0 +1,47 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021 shedaniel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package me.shedaniel.architectury.test.tags;
import me.shedaniel.architectury.event.events.BlockEvent;
import me.shedaniel.architectury.hooks.TagHooks;
import me.shedaniel.architectury.test.TestMod;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.Tag;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.block.Block;
public class TestTags {
public static void initialize() {
// This will not be present, but it should return an empty tag
Tag.Named<Block> heartParticles = TagHooks.getBlockOptional(new ResourceLocation(TestMod.MOD_ID, "heart_particles"));
// This will act like a normal tag, we have emerald block here
Tag.Named<Block> heartParticles2 = TagHooks.getBlockOptional(new ResourceLocation(TestMod.MOD_ID, "heart_particles2"));
BlockEvent.BREAK.register((world, pos, state, player, xp) -> {
if (player != null && !world.isClientSide() && (state.is(heartParticles) || state.is(heartParticles2))) {
((ServerLevel) world).sendParticles(player, ParticleTypes.HEART, false, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 10, 0.0, 0.0, 0.0, 0.0);
}
return InteractionResult.PASS;
});
}
}

View File

@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:emerald_block"
]
}

View File

@@ -5,6 +5,7 @@ plugins {
architectury {
platformSetupLoomIde()
fabric()
}
dependencies {
@@ -14,16 +15,16 @@ dependencies {
modCompile "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
implementation project(path: ":fabric", configuration: "dev")
compileOnly(project(path: ":common")) {
implementation(project(path: ":common")) {
transitive = false
}
runtimeOnly(project(path: ":common", configuration: "transformDevelopmentFabric")) {
developmentFabric(project(path: ":common")) {
transitive = false
}
compileOnly(project(path: ":testmod-common")) {
implementation(project(path: ":testmod-common")) {
transitive = false
}
runtimeOnly(project(path: ":testmod-common", configuration: "transformDevelopmentFabric")) {
developmentFabric(project(path: ":testmod-common")) {
transitive = false
}
}

View File

@@ -4,7 +4,7 @@ plugins {
}
loom {
mixinConfig = "architectury.mixins.json"
mixinConfig "architectury.mixins.json"
localMods {
it.add(project(":forge").sourceSets.main)
@@ -13,6 +13,7 @@ loom {
architectury {
platformSetupLoomIde()
forge()
}
dependencies {
@@ -21,16 +22,16 @@ dependencies {
forge "net.minecraftforge:forge:${gradle.rootProject.architectury.minecraft}-${rootProject.forge_version}"
implementation project(path: ":forge", configuration: "dev")
compileOnly(project(path: ":common")) {
implementation(project(path: ":common")) {
transitive = false
}
runtimeOnly(project(path: ":common", configuration: "transformDevelopmentForge")) {
developmentForge(project(path: ":common")) {
transitive = false
}
compileOnly(project(path: ":testmod-common")) {
implementation(project(path: ":testmod-common")) {
transitive = false
}
runtimeOnly(project(path: ":testmod-common", configuration: "transformDevelopmentForge")) {
developmentForge(project(path: ":testmod-common")) {
transitive = false
}
}