mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-21 02:38:26 -05:00
Improve 24w21b port (#3801)
* Delete `FabricDimensions` This broke during the 1.21 cycle and can be easily replaced with `Entity#teleportTo`. * Rename testmod data directories * [Breaking] use singular path in GameTest * Fix attribute modifier in testmod * Small mixin refactors related to teleportTo * Fix behavior change in ModNioResourcePack for invalid paths * Fix javadocs referencing Identifier ctor * Add new FabricCodecDataProvider ctor * Move empty structure * Fix transfer api testmod * pro tip: don't write datagen output by hand * Refactor networking API to remove redundant code * Stop calling CustomDamageHandler in creative mode
This commit is contained in:
parent
b9828ba31a
commit
6fc22b9905
36 changed files with 49 additions and 373 deletions
|
@ -51,7 +51,7 @@ import net.fabricmc.fabric.impl.lookup.block.BlockApiLookupImpl;
|
|||
*
|
||||
* <pre>{@code
|
||||
* public final class MyApi {
|
||||
* public static final BlockApiLookup<FluidContainer, Direction> FLUID_CONTAINER = BlockApiLookup.get(new Identifier("mymod:fluid_container"), FluidContainer.class, Direction.class);
|
||||
* public static final BlockApiLookup<FluidContainer, Direction> FLUID_CONTAINER = BlockApiLookup.get(Identifier.of("mymod", "fluid_container"), FluidContainer.class, Direction.class);
|
||||
* }}</pre>
|
||||
* Using that, we can query instances of {@code FluidContainer}:
|
||||
*
|
||||
|
|
|
@ -45,7 +45,7 @@ import net.fabricmc.fabric.impl.lookup.entity.EntityApiLookupImpl;
|
|||
* <p>We need to create the EntityApiLookup. We don't need any context so we use {@link Void}.
|
||||
* <pre>{@code
|
||||
* public class MyApi {
|
||||
* public static final EntityApiLookup<Leveled, Void> LEVELED_ENTITY = EntityApiLookup.get(new Identifier("mymod:leveled_entity"), Leveled.class, Void.class);
|
||||
* public static final EntityApiLookup<Leveled, Void> LEVELED_ENTITY = EntityApiLookup.get(Identifier.of("mymod", "leveled_entity"), Leveled.class, Void.class);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
|
|
|
@ -47,7 +47,7 @@ import net.fabricmc.fabric.impl.lookup.item.ItemApiLookupImpl;
|
|||
*
|
||||
* <pre>{@code
|
||||
* public final class MyApi {
|
||||
* public static final ItemApiLookup<FluidContainer, Void> FLUID_CONTAINER_ITEM = ItemApiLookup.get(new Identifier("mymod:fluid_container"), FluidContainer.class, Void.class);
|
||||
* public static final ItemApiLookup<FluidContainer, Void> FLUID_CONTAINER_ITEM = ItemApiLookup.get(Identifier.of("mymod", "fluid_container"), FluidContainer.class, Void.class);
|
||||
* }}</pre>
|
||||
* API instances are easy to access:
|
||||
*
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:beach",
|
||||
"minecraft:desert",
|
||||
"minecraft:savanna",
|
||||
"minecraft:badlands"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import net.minecraft.registry.RegistryWrapper;
|
|||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeKeys;
|
||||
|
||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
|
||||
|
@ -37,5 +38,10 @@ public class TestBiomeTagProvider extends FabricTagProvider<Biome> {
|
|||
getOrCreateTagBuilder(TagKey.of(RegistryKeys.BIOME, Identifier.of(FabricBiomeTest.MOD_ID, "biome_tag_test")))
|
||||
.add(TestBiomes.CUSTOM_PLAINS)
|
||||
.add(TestBiomes.TEST_END_HIGHLANDS);
|
||||
getOrCreateTagBuilder(TagKey.of(RegistryKeys.BIOME, Identifier.of(FabricBiomeTest.MOD_ID, "tag_selector_test")))
|
||||
.add(BiomeKeys.BEACH)
|
||||
.add(BiomeKeys.DESERT)
|
||||
.add(BiomeKeys.SAVANNA)
|
||||
.add(BiomeKeys.BADLANDS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import com.mojang.serialization.JsonOps;
|
|||
import net.minecraft.data.DataOutput;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.DataWriter;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryOps;
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -49,12 +51,20 @@ public abstract class FabricCodecDataProvider<T> implements DataProvider {
|
|||
private final CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture;
|
||||
private final Codec<T> codec;
|
||||
|
||||
protected FabricCodecDataProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, DataOutput.OutputType outputType, String directoryName, Codec<T> codec) {
|
||||
this.pathResolver = dataOutput.getResolver(outputType, directoryName);
|
||||
private FabricCodecDataProvider(DataOutput.PathResolver pathResolver, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, Codec<T> codec) {
|
||||
this.pathResolver = pathResolver;
|
||||
this.registriesFuture = Objects.requireNonNull(registriesFuture);
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
protected FabricCodecDataProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, DataOutput.OutputType outputType, String directoryName, Codec<T> codec) {
|
||||
this(dataOutput.getResolver(outputType, directoryName), registriesFuture, codec);
|
||||
}
|
||||
|
||||
protected FabricCodecDataProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, RegistryKey<? extends Registry<?>> key, Codec<T> codec) {
|
||||
this(dataOutput.getResolver(key), registriesFuture, codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> run(DataWriter writer) {
|
||||
return this.registriesFuture.thenCompose(lookup -> {
|
||||
|
|
|
@ -28,11 +28,11 @@ import com.google.gson.JsonElement;
|
|||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
|
||||
import net.minecraft.data.DataOutput;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.DataWriter;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.loot.context.LootContextType;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.RegistryOps;
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -81,7 +81,7 @@ public final class FabricLootTableProviderImpl {
|
|||
}
|
||||
|
||||
private static Path getOutputPath(FabricDataOutput dataOutput, Identifier lootTableId) {
|
||||
return dataOutput.getResolver(DataOutput.OutputType.DATA_PACK, "loot_table").resolveJson(lootTableId);
|
||||
return dataOutput.getResolver(RegistryKeys.LOOT_TABLE).resolveJson(lootTableId);
|
||||
}
|
||||
|
||||
private FabricLootTableProviderImpl() {
|
||||
|
|
|
@ -186,7 +186,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
|||
/* Generate test recipes using all types of custom ingredients for easy testing */
|
||||
// Testing procedure for vanilla and fabric clients:
|
||||
// - Create a new fabric server with the ingredient API.
|
||||
// - Copy the generated recipes to a datapack, for example to world/datapacks/<packname>/data/test/recipes/.
|
||||
// - Copy the generated recipes to a datapack, for example to world/datapacks/<packname>/data/test/recipe/.
|
||||
// - Remember to also include a pack.mcmeta file in world/datapacks/<packname>.
|
||||
// (see https://minecraft.wiki/w/Tutorials/Creating_a_data_pack)
|
||||
// - Start the server and connect to it with a vanilla client.
|
||||
|
@ -466,7 +466,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
|||
|
||||
private static class TestPredicateProvider extends FabricCodecDataProvider<LootCondition> {
|
||||
private TestPredicateProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
|
||||
super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, "predicate", LootCondition.CODEC);
|
||||
super(dataOutput, registriesFuture, RegistryKeys.PREDICATE, LootCondition.CODEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, ['fabric-api-base'])
|
||||
|
||||
testDependencies(project, [
|
||||
':fabric-command-api-v2',
|
||||
':fabric-resource-loader-v0',
|
||||
':fabric-lifecycle-events-v1'
|
||||
':fabric-resource-loader-v0'
|
||||
])
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.dimension.v1;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.TeleportTarget;
|
||||
|
||||
import net.fabricmc.fabric.impl.dimension.FabricDimensionInternals;
|
||||
|
||||
/**
|
||||
* This class consists exclusively of static methods that operate on world dimensions.
|
||||
*/
|
||||
public final class FabricDimensions {
|
||||
private FabricDimensions() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports an entity to a different dimension, placing it at the specified destination.
|
||||
*
|
||||
* <p>When teleporting to another dimension, the entity may be replaced with a new entity in the target
|
||||
* dimension. This is not the case for players, but needs to be accounted for by the caller.
|
||||
*
|
||||
* @param teleported the entity to teleport
|
||||
* @param target where the entity will be placed in the target world.
|
||||
* As in Vanilla, the target's velocity is not applied to players.
|
||||
* @param <E> the type of the teleported entity
|
||||
* @return Returns the teleported entity in the target dimension, which may be a new entity or <code>teleported</code>,
|
||||
* depending on the entity type.
|
||||
* @throws IllegalStateException if this method is called on a client entity
|
||||
* @apiNote this method must be called from the main server thread
|
||||
*/
|
||||
@Nullable
|
||||
public static <E extends Entity> E teleport(E teleported, TeleportTarget target) {
|
||||
Preconditions.checkNotNull(target, "A target must be provided");
|
||||
Preconditions.checkState(!teleported.getWorld().isClient, "Entities can only be teleported on the server side");
|
||||
|
||||
return FabricDimensionInternals.changeDimension(teleported, target);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.dimension;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.world.TeleportTarget;
|
||||
|
||||
public final class FabricDimensionInternals {
|
||||
private FabricDimensionInternals() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E extends Entity> E changeDimension(E teleported, TeleportTarget target) {
|
||||
Preconditions.checkArgument(!teleported.getWorld().isClient, "Entities can only be teleported on the server side");
|
||||
Preconditions.checkArgument(Thread.currentThread() == ((ServerWorld) teleported.getWorld()).getServer().getThread(), "Entities must be teleported from the main server thread");
|
||||
|
||||
// Fast path for teleporting within the same dimension.
|
||||
if (teleported.getWorld() == target.world()) {
|
||||
if (teleported instanceof ServerPlayerEntity serverPlayerEntity) {
|
||||
serverPlayerEntity.networkHandler.requestTeleport(target.pos().x, target.pos().y, target.pos().z, target.yaw(), target.pitch());
|
||||
} else {
|
||||
teleported.refreshPositionAndAngles(target.pos().x, target.pos().y, target.pos().z, target.yaw(), target.pitch());
|
||||
}
|
||||
|
||||
teleported.setVelocity(target.velocity());
|
||||
teleported.setHeadYaw(target.yaw());
|
||||
|
||||
return teleported;
|
||||
}
|
||||
|
||||
return (E) teleported.teleportTo(target);
|
||||
}
|
||||
}
|
|
@ -16,184 +16,22 @@
|
|||
|
||||
package net.fabricmc.fabric.test.dimension;
|
||||
|
||||
import static net.minecraft.entity.EntityType.COW;
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.command.argument.DimensionArgumentType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.TeleportTarget;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionOptions;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.dimension.v1.FabricDimensions;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
|
||||
public class FabricDimensionTest implements ModInitializer {
|
||||
// The dimension options refer to the JSON-file in the dimension subfolder of the data pack,
|
||||
// which will always share its ID with the world that is created from it
|
||||
private static final RegistryKey<DimensionOptions> DIMENSION_KEY = RegistryKey.of(RegistryKeys.DIMENSION, Identifier.of("fabric_dimension", "void"));
|
||||
private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Text.literal("Teleportation failed!"));
|
||||
|
||||
private static RegistryKey<World> WORLD_KEY = RegistryKey.of(RegistryKeys.WORLD, DIMENSION_KEY.getValue());
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Registry.register(Registries.CHUNK_GENERATOR, Identifier.of("fabric_dimension", "void"), VoidChunkGenerator.CODEC);
|
||||
|
||||
WORLD_KEY = RegistryKey.of(RegistryKeys.WORLD, Identifier.of("fabric_dimension", "void"));
|
||||
|
||||
if (System.getProperty("fabric-api.gametest") != null) {
|
||||
// The gametest server does not support custom worlds
|
||||
return;
|
||||
}
|
||||
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||
ServerWorld world = server.getWorld(WORLD_KEY);
|
||||
|
||||
if (world == null) throw new AssertionError("Test world doesn't exist.");
|
||||
|
||||
Entity entity = COW.create(overworld);
|
||||
|
||||
if (entity == null) throw new AssertionError("Could not create entity!");
|
||||
if (!entity.getWorld().getRegistryKey().equals(World.OVERWORLD)) throw new AssertionError("Entity starting world isn't the overworld");
|
||||
|
||||
TeleportTarget target = new TeleportTarget(world, Vec3d.ZERO, new Vec3d(1, 1, 1), 45f, 60f);
|
||||
|
||||
Entity teleported = FabricDimensions.teleport(entity, target);
|
||||
|
||||
if (teleported == null) throw new AssertionError("Entity didn't teleport");
|
||||
|
||||
if (!teleported.getWorld().getRegistryKey().equals(WORLD_KEY)) throw new AssertionError("Target world not reached.");
|
||||
|
||||
if (!teleported.getPos().equals(target.pos())) throw new AssertionError("Target Position not reached.");
|
||||
});
|
||||
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
dispatcher.register(literal("fabric_dimension_test")
|
||||
.executes(FabricDimensionTest.this::swapTargeted));
|
||||
|
||||
// Used to test https://github.com/FabricMC/fabric/issues/2239
|
||||
// Dedicated-only
|
||||
if (environment != CommandManager.RegistrationEnvironment.INTEGRATED) {
|
||||
dispatcher.register(literal("fabric_dimension_test_desync")
|
||||
.executes(FabricDimensionTest.this::testDesync));
|
||||
}
|
||||
|
||||
// Used to test https://github.com/FabricMC/fabric/issues/2238
|
||||
dispatcher.register(literal("fabric_dimension_test_entity")
|
||||
.executes(FabricDimensionTest.this::testEntityTeleport));
|
||||
|
||||
// Used to test teleport to vanilla dimension
|
||||
dispatcher.register(literal("fabric_dimension_test_tp")
|
||||
.then(argument("target", DimensionArgumentType.dimension())
|
||||
.executes((context) ->
|
||||
testVanillaTeleport(context, DimensionArgumentType.getDimensionArgument(context, "target")))));
|
||||
});
|
||||
}
|
||||
|
||||
private int swapTargeted(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
context.getSource().sendFeedback(() -> Text.literal("You must be a player to execute this command."), false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ServerWorld serverWorld = player.getServerWorld();
|
||||
ServerWorld modWorld = getModWorld(context);
|
||||
|
||||
if (serverWorld != modWorld) {
|
||||
TeleportTarget target = new TeleportTarget(modWorld, new Vec3d(0.5, 101, 0.5), Vec3d.ZERO, 0, 0);
|
||||
FabricDimensions.teleport(player, target);
|
||||
|
||||
if (player.getWorld() != modWorld) {
|
||||
throw FAILED_EXCEPTION.create();
|
||||
}
|
||||
|
||||
modWorld.setBlockState(new BlockPos(0, 100, 0), Blocks.DIAMOND_BLOCK.getDefaultState());
|
||||
modWorld.setBlockState(new BlockPos(0, 101, 0), Blocks.TORCH.getDefaultState());
|
||||
} else {
|
||||
TeleportTarget target = new TeleportTarget(getWorld(context, World.OVERWORLD), new Vec3d(0, 100, 0), Vec3d.ZERO,
|
||||
(float) Math.random() * 360 - 180, (float) Math.random() * 360 - 180);
|
||||
FabricDimensions.teleport(player, target);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int testDesync(CommandContext<ServerCommandSource> context) {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
context.getSource().sendFeedback(() -> Text.literal("You must be a player to execute this command."), false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TeleportTarget target = new TeleportTarget((ServerWorld) player.getWorld(), player.getPos().add(5, 0, 0), player.getVelocity(), player.getYaw(), player.getPitch());
|
||||
FabricDimensions.teleport(player, target);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int testEntityTeleport(CommandContext<ServerCommandSource> context) {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
context.getSource().sendFeedback(() -> Text.literal("You must be a player to execute this command."), false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Entity entity = player.getWorld()
|
||||
.getOtherEntities(player, player.getBoundingBox().expand(100, 100, 100))
|
||||
.stream()
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (entity == null) {
|
||||
context.getSource().sendFeedback(() -> Text.literal("No entities found."), false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TeleportTarget target = new TeleportTarget((ServerWorld) entity.getWorld(), player.getPos(), player.getVelocity(), player.getYaw(), player.getPitch());
|
||||
FabricDimensions.teleport(entity, target);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int testVanillaTeleport(CommandContext<ServerCommandSource> context, ServerWorld targetWorld) throws CommandSyntaxException {
|
||||
Entity entity = context.getSource().getEntityOrThrow();
|
||||
TeleportTarget target = new TeleportTarget(targetWorld, entity.getPos(), entity.getVelocity(), entity.getYaw(), entity.getPitch());
|
||||
FabricDimensions.teleport(entity, target);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private ServerWorld getModWorld(CommandContext<ServerCommandSource> context) {
|
||||
return getWorld(context, WORLD_KEY);
|
||||
}
|
||||
|
||||
private ServerWorld getWorld(CommandContext<ServerCommandSource> context, RegistryKey<World> dimensionRegistryKey) {
|
||||
return context.getSource().getServer().getWorld(dimensionRegistryKey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ abstract class EntityMixin {
|
|||
private World world;
|
||||
|
||||
@Inject(method = "teleportTo", at = @At("RETURN"))
|
||||
private void afterWorldChanged(TeleportTarget targetSupplier, CallbackInfoReturnable<Entity> cir) {
|
||||
private void afterWorldChanged(TeleportTarget target, CallbackInfoReturnable<Entity> cir) {
|
||||
// Ret will only have an entity if the teleport worked (entity not removed, teleportTarget was valid, entity was successfully created)
|
||||
Entity ret = cir.getReturnValue();
|
||||
|
||||
|
|
|
@ -78,8 +78,7 @@ abstract class ServerPlayerEntityMixin extends LivingEntityMixin {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called by both "moveToWorld" and "teleport".
|
||||
* So this is suitable to handle the after event from both call sites.
|
||||
* This is called by {@code teleportTo}.
|
||||
*/
|
||||
@Inject(method = "worldChanged(Lnet/minecraft/server/world/ServerWorld;)V", at = @At("TAIL"))
|
||||
private void afterWorldChanged(ServerWorld origin, CallbackInfo ci) {
|
||||
|
|
|
@ -7,7 +7,7 @@ loom {
|
|||
testmodClient {
|
||||
client()
|
||||
name = "Testmod Client"
|
||||
vmArg "-Dfabric-api.gametest.structures.output-dir=${file("src/testmod/resources/data/fabric-gametest-api-v1-testmod/gametest/structures")}"
|
||||
vmArg "-Dfabric-api.gametest.structures.output-dir=${file("src/testmod/resources/data/fabric-gametest-api-v1-testmod/gametest/structure")}"
|
||||
|
||||
ideConfigGenerated = false
|
||||
source sourceSets.testmodClient
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
* causes explosion, or that hoppers can insert items into barrels. A test method is always annotated
|
||||
* with {@link net.minecraft.test.GameTest}. For most cases you can set the {@link
|
||||
* net.minecraft.test.GameTest#templateName()} as {@link net.fabricmc.fabric.api.gametest.v1.FabricGameTest#EMPTY_STRUCTURE}.
|
||||
* For complex tests, you can also save a structure as an SNBT file under {@code modid/gametest/structures/}
|
||||
* For complex tests, you can also save a structure as an SNBT file under {@code modid/gametest/structure/}
|
||||
* in the test mod's data pack and reference that structure. It will then be loaded before the test.
|
||||
*
|
||||
* <p>Test methods are instance methods (i.e. not static) and take exactly one argument - {@link
|
||||
|
|
|
@ -58,7 +58,7 @@ public final class FabricGameTestHelper {
|
|||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FabricGameTestHelper.class);
|
||||
|
||||
private static final String GAMETEST_STRUCTURE_PATH = "gametest/structures";
|
||||
private static final String GAMETEST_STRUCTURE_PATH = "gametest/structure";
|
||||
|
||||
public static final ResourceFinder GAMETEST_STRUCTURE_FINDER = new ResourceFinder(GAMETEST_STRUCTURE_PATH, ".snbt");
|
||||
|
||||
|
|
|
@ -49,7 +49,15 @@ public abstract class ItemStackMixin implements FabricItemStack {
|
|||
private void hookDamage(ItemStack instance, int amount, ServerWorld serverWorld, ServerPlayerEntity serverPlayerEntity, Consumer<Item> consumer, Operation<Void> original, @Local(argsOnly = true) LivingEntity entity, @Local(argsOnly = true) EquipmentSlot slot) {
|
||||
CustomDamageHandler handler = ((ItemExtensions) getItem()).fabric_getCustomDamageHandler();
|
||||
|
||||
if (handler != null) {
|
||||
/*
|
||||
This is called by creative mode players, post-24w21a.
|
||||
The other damage method (which original.call discards) handles the creative mode check.
|
||||
Since it doesn't make sense to call an event to calculate a to-be-discarded value
|
||||
(and to prevent mods from breaking item stacks in Creative mode),
|
||||
we preserve the pre-24w21a behavior of not calling in creative mode.
|
||||
*/
|
||||
|
||||
if (handler != null && !entity.isInCreativeMode()) {
|
||||
// Track whether an item has been broken by custom handler
|
||||
MutableBoolean mut = new MutableBoolean(false);
|
||||
amount = handler.damage((ItemStack) (Object) this, amount, entity, slot, () -> {
|
||||
|
|
|
@ -26,11 +26,13 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class UpdatingItem extends Item {
|
||||
private static final Identifier PLUS_FIVE_ID = Identifier.of("fabric-item-api-v1-testmod", "plus_five");
|
||||
private static final EntityAttributeModifier PLUS_FIVE = new EntityAttributeModifier(
|
||||
BASE_ATTACK_DAMAGE_MODIFIER_ID, 5, EntityAttributeModifier.Operation.ADD_VALUE);
|
||||
PLUS_FIVE_ID, 5, EntityAttributeModifier.Operation.ADD_VALUE);
|
||||
|
||||
private final boolean allowUpdateAnimation;
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.networking;
|
||||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public interface DisconnectPacketSource {
|
||||
Packet<?> createDisconnectPacket(Text message);
|
||||
}
|
|
@ -22,13 +22,11 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
|
@ -38,11 +36,9 @@ import net.minecraft.network.NetworkState;
|
|||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.PacketCallbackListener;
|
||||
|
||||
|
@ -51,12 +47,6 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
@Shadow
|
||||
private PacketListener packetListener;
|
||||
|
||||
@Shadow
|
||||
public abstract void disconnect(Text disconnectReason);
|
||||
|
||||
@Shadow
|
||||
public abstract void send(Packet<?> packet, @Nullable PacketCallbacks arg);
|
||||
|
||||
@Unique
|
||||
private Map<NetworkPhase, Collection<Identifier>> playChannels;
|
||||
|
||||
|
@ -65,19 +55,6 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
this.playChannels = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
// Must be fully qualified due to mixin not working in production without it
|
||||
@Redirect(method = "exceptionCaught", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V"))
|
||||
private void resendOnExceptionCaught(ClientConnection self, Packet<?> packet, PacketCallbacks listener, ChannelHandlerContext context, Throwable ex) {
|
||||
PacketListener handler = this.packetListener;
|
||||
Text disconnectMessage = Text.translatable("disconnect.genericReason", "Internal Exception: " + ex);
|
||||
|
||||
if (handler instanceof DisconnectPacketSource) {
|
||||
this.send(((DisconnectPacketSource) handler).createDisconnectPacket(disconnectMessage), listener);
|
||||
} else {
|
||||
this.disconnect(disconnectMessage); // Don't send packet if we cannot send proper packets
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "sendImmediately", at = @At(value = "FIELD", target = "Lnet/minecraft/network/ClientConnection;packetsSentCounter:I"))
|
||||
private void checkPacket(Packet<?> packet, PacketCallbacks callback, boolean flush, CallbackInfo ci) {
|
||||
if (this.packetListener instanceof PacketCallbackListener) {
|
||||
|
|
|
@ -28,23 +28,19 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ConnectedClientData;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerConfigurationTask;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.FabricServerConfigurationNetworkHandler;
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon;
|
||||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ServerConfigurationNetworkHandler.class, priority = 900)
|
||||
public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions, DisconnectPacketSource, FabricServerConfigurationNetworkHandler {
|
||||
public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions, FabricServerConfigurationNetworkHandler {
|
||||
@Shadow
|
||||
@Nullable
|
||||
private ServerPlayerConfigurationTask currentTask;
|
||||
|
@ -146,11 +142,6 @@ public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommo
|
|||
return addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createDisconnectPacket(Text message) {
|
||||
return new DisconnectS2CPacket(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(ServerPlayerConfigurationTask task) {
|
||||
tasks.add(task);
|
||||
|
|
|
@ -27,20 +27,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.login.LoginDisconnectS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerLoginNetworkHandler;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.PacketCallbackListener;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerLoginNetworkAddon;
|
||||
|
||||
@Mixin(ServerLoginNetworkHandler.class)
|
||||
abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtensions, DisconnectPacketSource, PacketCallbackListener {
|
||||
abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtensions, PacketCallbackListener {
|
||||
@Shadow
|
||||
protected abstract void tickVerify(GameProfile profile);
|
||||
|
||||
|
@ -90,9 +87,4 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
public ServerLoginNetworkAddon getAddon() {
|
||||
return this.addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createDisconnectPacket(Text message) {
|
||||
return new LoginDisconnectS2CPacket(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,22 +23,18 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ConnectedClientData;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon;
|
||||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ServerPlayNetworkHandler.class, priority = 999)
|
||||
abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions, DisconnectPacketSource {
|
||||
abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions {
|
||||
@Unique
|
||||
private ServerPlayNetworkAddon addon;
|
||||
|
||||
|
@ -64,9 +60,4 @@ abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler
|
|||
public ServerPlayNetworkAddon getAddon() {
|
||||
return this.addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createDisconnectPacket(Text message) {
|
||||
return new DisconnectS2CPacket(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,7 +256,7 @@ public class ModNioResourcePack implements ResourcePack, ModResourcePack {
|
|||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
String filename = nsPath.relativize(file).toString().replace(separator, "/");
|
||||
Identifier identifier = Identifier.of(namespace, filename);
|
||||
Identifier identifier = Identifier.tryParse(namespace, filename);
|
||||
|
||||
if (identifier == null) {
|
||||
LOGGER.error("Invalid path in mod resource-pack {}: {}:{}, ignoring", id, namespace, filename);
|
||||
|
|
|
@ -50,7 +50,7 @@ import net.minecraft.screen.ScreenHandlerType;
|
|||
* // Creating and registering the type
|
||||
* public static final ExtendedScreenHandlerType<OvenScreenHandler> OVEN =
|
||||
* new ExtendedScreenHandlerType((syncId, inventory, data) -> ..., OvenData.PACKET_CODEC);
|
||||
* Registry.register(Registry.SCREEN_HANDLER, new Identifier(...), OVEN);
|
||||
* Registry.register(Registry.SCREEN_HANDLER, Identifier.of(...), OVEN);
|
||||
*
|
||||
* // Note: remember to also register the screen using vanilla's HandledScreens!
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue