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

@@ -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
}
}