From 1c9e76139d1e77362deaeb12c93e3e3b3abc2e2c Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Wed, 12 Jun 2024 20:51:15 +0200 Subject: [PATCH 001/226] disable SpongeForge during snapshots --- .github/workflows/deploy.yaml | 4 ++-- settings.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 009eda82dbb..c4a65192b77 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -44,8 +44,8 @@ jobs: echo "GIT_BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - name: Publish to Sponge Maven & GitHub Packages - run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish :SpongeForge:publish - # run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish + # run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish :SpongeForge:publish + run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish env: CI_SYSTEM: Github Actions GITHUB_USERNAME: "${{ github.actor }}" diff --git a/settings.gradle.kts b/settings.gradle.kts index 6ad57d49c5e..2484c22d7a1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -89,7 +89,7 @@ if (spongeForge.exists()) { ).joinToString(separator = System.lineSeparator(), postfix = System.lineSeparator())) } val spongeForgeEnabledInCi: String = startParameter.projectProperties.getOrDefault("enableSpongeForge", "false") -if (spongeForgeEnabledInCi.toBoolean()) { +if (false && spongeForgeEnabledInCi.toBoolean()) { include(":SpongeForge") project(":SpongeForge").projectDir = file("forge") } From 92040febb6162f256423ea1edb70b1df63eae3a6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Wed, 29 May 2024 20:00:19 +0200 Subject: [PATCH 002/226] Bump MC to 1.21-pre1 --- gradle.properties | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 235cbf86e39..4b728d745c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.20.6 +minecraftVersion=1.21-pre1 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 3383d8bae5a..0cf0b9f54b9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1038,6 +1038,14 @@ + + + + + + + + From 541c65c1d55c0ab880b03d536486cac0e4874be0 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Wed, 29 May 2024 20:25:42 +0200 Subject: [PATCH 003/226] fix ResourceLocation usage --- .../vanilla/generator/EnumEntriesValidator.java | 12 ++++++------ .../vanilla/generator/GeneratorMain.java | 4 ++-- .../vanilla/generator/MapEntriesValidator.java | 10 +++++----- .../vanilla/generator/RegistryEntriesValidator.java | 10 +++++----- .../common/adventure/SpongeAdventure.java | 2 +- .../data/provider/block/entity/MobSpawnerData.java | 4 ++-- .../common/datapack/DataPackSerializer.java | 2 +- .../common/event/tracking/PhaseTracker.java | 2 +- .../common/item/recipe/SpongeRecipeRegistration.java | 2 +- .../common/network/channel/SpongeChannel.java | 3 ++- .../packet/ChangeViewerEnvironmentPacket.java | 2 +- .../common/registry/RegistryHolderLogic.java | 6 +++--- .../common/registry/SpongeResourceKeyBuilder.java | 2 +- .../common/registry/SpongeResourceKeyFactory.java | 6 +++--- .../registry/loader/VanillaRegistryLoader.java | 2 +- .../common/world/server/SpongeWorldTemplate.java | 4 ++-- .../common/mixin/core/adventure/KeyMixin.java | 2 +- .../vanilla/server/packs/PluginPackResources.java | 2 +- 18 files changed, 39 insertions(+), 38 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java index 3a873a67397..3c780058308 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java @@ -119,7 +119,7 @@ public void generate(final Context ctx) { } catch (Exception e) { throw new IllegalStateException("Failed to name for enum field in class " + this.clazz.getName(), e); } - final ResourceLocation key = new ResourceLocation(this.namespace, name); + final ResourceLocation key = ResourceLocation.fromNamespaceAndPath(this.namespace, name); final FieldDeclaration existing = fields.remove(key); if (existing != null) { @@ -150,24 +150,24 @@ private ResourceLocation extractFieldIdentifier(final FieldDeclaration declarati final VariableDeclarator var = declaration.getVariable(0); final Expression initializer = var.getInitializer().orElse(null); if (!(initializer instanceof MethodCallExpr) || ((MethodCallExpr) initializer).getArguments().size() != 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } final Expression argument = ((MethodCallExpr) initializer).getArgument(0); if (!(argument instanceof final MethodCallExpr keyInitializer) || keyInitializer.getArguments().size() < 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } if (keyInitializer.getArguments().size() == 1) { // method name as namespace - return new ResourceLocation(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); + return ResourceLocation.fromNamespaceAndPath(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); } else if (keyInitializer.getArguments().size() == 2) { // (namespace, path) - return new ResourceLocation( + return ResourceLocation.fromNamespaceAndPath( keyInitializer.getArgument(0).asStringLiteralExpr().asString(), keyInitializer.getArgument(1).asStringLiteralExpr().asString() ); } else { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } } diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index e463cc3c9d0..a4b1384f60d 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -212,7 +212,7 @@ private static List generators(final Context context) { final Map out = new HashMap<>(map.size()); map.forEach((BiConsumer) (k, v) -> { var key = (GameRules.Key) k; - out.put(new ResourceLocation("sponge:" + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key.getId())), v); + out.put(ResourceLocation.fromNamespaceAndPath("sponge", CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key.getId())), v); }); return out; } @@ -419,7 +419,7 @@ private static List generators(final Context context) { "EntityTypes", Registries.ENTITY_TYPE, $ -> true, - Set.of(new ResourceLocation("sponge", "human")) // Sponge's Human type is an extra addition + Set.of(ResourceLocation.fromNamespaceAndPath("sponge", "human")) // Sponge's Human type is an extra addition ), new RegistryEntriesGenerator<>( "fluid", diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/MapEntriesValidator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/MapEntriesValidator.java index bdd0891cf69..f970695fdd8 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/MapEntriesValidator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/MapEntriesValidator.java @@ -161,24 +161,24 @@ private ResourceLocation extractFieldIdentifier(final FieldDeclaration declarati final VariableDeclarator var = declaration.getVariable(0); final Expression initializer = var.getInitializer().orElse(null); if (!(initializer instanceof MethodCallExpr) || ((MethodCallExpr) initializer).getArguments().size() != 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } final Expression argument = ((MethodCallExpr) initializer).getArgument(0); if (!(argument instanceof final MethodCallExpr keyInitializer) || keyInitializer.getArguments().size() < 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } if (keyInitializer.getArguments().size() == 1) { // method name as namespace - return new ResourceLocation(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); + return ResourceLocation.fromNamespaceAndPath(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); } else if (keyInitializer.getArguments().size() == 2) { // (namespace, path) - return new ResourceLocation( + return ResourceLocation.fromNamespaceAndPath( keyInitializer.getArgument(0).asStringLiteralExpr().asString(), keyInitializer.getArgument(1).asStringLiteralExpr().asString() ); } else { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } } diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesValidator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesValidator.java index d22ebf63fce..5fed02e72aa 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesValidator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesValidator.java @@ -163,24 +163,24 @@ private ResourceLocation extractFieldIdentifier(final FieldDeclaration declarati final VariableDeclarator var = declaration.getVariable(0); final Expression initializer = var.getInitializer().orElse(null); if (!(initializer instanceof MethodCallExpr) || ((MethodCallExpr) initializer).getArguments().size() != 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } final Expression argument = ((MethodCallExpr) initializer).getArgument(0); if (!(argument instanceof final MethodCallExpr keyInitializer) || keyInitializer.getArguments().size() < 1) { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } if (keyInitializer.getArguments().size() == 1) { // method name as namespace - return new ResourceLocation(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); + return ResourceLocation.fromNamespaceAndPath(keyInitializer.getNameAsString(), keyInitializer.getArgument(0).asStringLiteralExpr().asString()); } else if (keyInitializer.getArguments().size() == 2) { // (namespace, path) - return new ResourceLocation( + return ResourceLocation.fromNamespaceAndPath( keyInitializer.getArgument(0).asStringLiteralExpr().asString(), keyInitializer.getArgument(1).asStringLiteralExpr().asString() ); } else { - return new ResourceLocation(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess + return ResourceLocation.parse(var.getNameAsString().toLowerCase(Locale.ROOT)); // a best guess } } diff --git a/src/main/java/org/spongepowered/common/adventure/SpongeAdventure.java b/src/main/java/org/spongepowered/common/adventure/SpongeAdventure.java index d195b1c6961..ef073687f61 100644 --- a/src/main/java/org/spongepowered/common/adventure/SpongeAdventure.java +++ b/src/main/java/org/spongepowered/common/adventure/SpongeAdventure.java @@ -762,7 +762,7 @@ public static ResourceLocation asVanilla(final Key key) { if ((Object) key instanceof ResourceLocation) { return (ResourceLocation) (Object) key; } - return new ResourceLocation(key.namespace(), key.value()); + return ResourceLocation.fromNamespaceAndPath(key.namespace(), key.value()); } public static @Nullable ResourceLocation asVanillaNullable(final @Nullable Key key) { diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java index 561119d02e5..8188239c476 100644 --- a/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java @@ -121,7 +121,7 @@ private static WeightedSerializableObject getNextEntity(final B final String resourceLocation = logic.accessor$nextSpawnData().entityToSpawn().getString(Constants.Entity.ENTITY_TYPE_ID); final Registry> entityTypeRegistry = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE); - final EntityType type = entityTypeRegistry.getOptional(new ResourceLocation(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); + final EntityType type = entityTypeRegistry.getOptional(ResourceLocation.parse(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); final CompoundTag data = logic.accessor$nextSpawnData().entityToSpawn(); @@ -152,7 +152,7 @@ private static WeightedTable getEntities(final BaseSpawner logi final String resourceLocation = nbt.getString(Constants.Entity.ENTITY_TYPE_ID); final Registry> entityTypeRegistry = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE); - final EntityType type = entityTypeRegistry.getOptional(new ResourceLocation(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); + final EntityType type = entityTypeRegistry.getOptional(ResourceLocation.parse(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); final EntityArchetype archetype = SpongeEntityArchetypeBuilder.pooled() .type(type) diff --git a/src/main/java/org/spongepowered/common/datapack/DataPackSerializer.java b/src/main/java/org/spongepowered/common/datapack/DataPackSerializer.java index e59448ddff2..fa934269483 100644 --- a/src/main/java/org/spongepowered/common/datapack/DataPackSerializer.java +++ b/src/main/java/org/spongepowered/common/datapack/DataPackSerializer.java @@ -68,7 +68,7 @@ public Path packEntryFile(final SpongeDataPackType packType, final Resourc } public ResourceLocation location(final SpongeDataPackType packType, final ResourceKey key) { - return new ResourceLocation(key.namespace(), packType.dir() + "/" + key.value() + this.fileEnding()); + return ResourceLocation.fromNamespaceAndPath(key.namespace(), packType.dir() + "/" + key.value() + this.fileEnding()); } public abstract String fileEnding(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/PhaseTracker.java b/src/main/java/org/spongepowered/common/event/tracking/PhaseTracker.java index 236a3e850d4..b5258e55a14 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/PhaseTracker.java +++ b/src/main/java/org/spongepowered/common/event/tracking/PhaseTracker.java @@ -139,7 +139,7 @@ public static Block validateBlockForNeighborNotification(final ServerLevel world if (type != null) { @Nullable ResourceLocation id = BlockEntityType.getKey(type); if (id == null) { - id = new ResourceLocation(source.getClass().getCanonicalName()); + id = ResourceLocation.parse(source.getClass().getCanonicalName()); } final Map autoFixedTiles = trackerConfig.autoFixNullSourceBlockProvidingBlockEntities; final boolean contained = autoFixedTiles.containsKey(type.toString()); diff --git a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java index 7b1a01885c3..23991b0a0f3 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java @@ -73,7 +73,7 @@ public SpongeRecipeRegistration(final ResourceLocation key, this.advancement = Advancement.Builder.advancement() .addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(key)) .rewards(AdvancementRewards.Builder.recipe(key)) - .build(new ResourceLocation(key.getNamespace(), "recipes/" + recipeCategory.getFolderName() + "/" + key.getPath())); + .build(ResourceLocation.fromNamespaceAndPath(key.getNamespace(), "recipes/" + recipeCategory.getFolderName() + "/" + key.getPath())); this.group = group == null ? "" : group; } diff --git a/src/main/java/org/spongepowered/common/network/channel/SpongeChannel.java b/src/main/java/org/spongepowered/common/network/channel/SpongeChannel.java index 9029e20e9ca..0dabdf2ae4d 100644 --- a/src/main/java/org/spongepowered/common/network/channel/SpongeChannel.java +++ b/src/main/java/org/spongepowered/common/network/channel/SpongeChannel.java @@ -26,6 +26,7 @@ import com.google.common.collect.Multimap; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -68,7 +69,7 @@ public SpongeChannel(final int type, final ResourceKey key, final SpongeChannelM this.key = key; this.manager = manager; this.logger = LogManager.getLogger("channel/" + key.formatted()); - this.payloadType = CustomPacketPayload.createType(key.toString()); + this.payloadType = new CustomPacketPayload.Type<>((ResourceLocation) (Object) key); } public int getType() { diff --git a/src/main/java/org/spongepowered/common/network/packet/ChangeViewerEnvironmentPacket.java b/src/main/java/org/spongepowered/common/network/packet/ChangeViewerEnvironmentPacket.java index 4bef4e30d6b..937a61543aa 100644 --- a/src/main/java/org/spongepowered/common/network/packet/ChangeViewerEnvironmentPacket.java +++ b/src/main/java/org/spongepowered/common/network/packet/ChangeViewerEnvironmentPacket.java @@ -44,7 +44,7 @@ public ChangeViewerEnvironmentPacket(final DimensionType dimensionType) { @Override public void read(final ChannelBuf buf) { - this.dimensionLogic = new ResourceLocation(buf.readString()); + this.dimensionLogic = ResourceLocation.parse(buf.readString()); } @Override diff --git a/src/main/java/org/spongepowered/common/registry/RegistryHolderLogic.java b/src/main/java/org/spongepowered/common/registry/RegistryHolderLogic.java index 44f15600238..5b1d397126f 100644 --- a/src/main/java/org/spongepowered/common/registry/RegistryHolderLogic.java +++ b/src/main/java/org/spongepowered/common/registry/RegistryHolderLogic.java @@ -59,13 +59,13 @@ public final class RegistryHolderLogic implements RegistryHolder { public RegistryHolderLogic() { this.roots.put( - (ResourceKey) (Object) new ResourceLocation("minecraft", "root"), + (ResourceKey) (Object) ResourceLocation.withDefaultNamespace("root"), new MappedRegistry<>( net.minecraft.resources.ResourceKey.createRegistryKey((ResourceLocation) (Object) RegistryRoots.MINECRAFT), Lifecycle.experimental() ) ); - final ResourceLocation sponge = new ResourceLocation("sponge", "root"); + final ResourceLocation sponge = ResourceLocation.fromNamespaceAndPath("sponge", "root"); this.roots.put( (ResourceKey) (Object) sponge, new MappedRegistry<>( @@ -81,7 +81,7 @@ public RegistryHolderLogic() { public RegistryHolderLogic(final RegistryAccess dynamicAccess) { this(); - final WritableRegistry root = (WritableRegistry) this.roots.get(new ResourceLocation("minecraft", "root")); + final WritableRegistry root = (WritableRegistry) this.roots.get(ResourceLocation.withDefaultNamespace("root")); // Add the dynamic registries. These are server-scoped in Vanilla dynamicAccess.registries().forEach(entry -> root.register(entry.key(), entry.value(), RegistrationInfo.BUILT_IN)); diff --git a/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyBuilder.java b/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyBuilder.java index a3d5933b6c9..87c23eab65e 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyBuilder.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyBuilder.java @@ -57,7 +57,7 @@ public ResourceKey build() throws IllegalStateException { Preconditions.checkState(this.value != null, "Value cannot be empty"); try { - final ResourceLocation resourceLocation = new ResourceLocation(this.namespace, this.value); + final ResourceLocation resourceLocation = ResourceLocation.fromNamespaceAndPath(this.namespace, this.value); return (ResourceKey) (Object) resourceLocation; } catch (ResourceLocationException e) { throw new IllegalStateException(e); diff --git a/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyFactory.java b/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyFactory.java index a04fca8bbb7..325fd990a89 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyFactory.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeResourceKeyFactory.java @@ -34,7 +34,7 @@ public final class SpongeResourceKeyFactory implements ResourceKey.Factory { @Override public ResourceKey of(final String namespace, final String value) { try { - final ResourceLocation resourceLocation = new ResourceLocation(namespace, value); + final ResourceLocation resourceLocation = ResourceLocation.fromNamespaceAndPath(namespace, value); return (ResourceKey) (Object) resourceLocation; } catch (ResourceLocationException e) { throw new IllegalStateException(e); @@ -44,7 +44,7 @@ public ResourceKey of(final String namespace, final String value) { @Override public ResourceKey of(final PluginContainer plugin, final String value) { try { - final ResourceLocation resourceLocation = new ResourceLocation(plugin.metadata().id(), value); + final ResourceLocation resourceLocation = ResourceLocation.fromNamespaceAndPath(plugin.metadata().id(), value); return (ResourceKey) (Object) resourceLocation; } catch (ResourceLocationException e) { throw new IllegalStateException(e); @@ -54,7 +54,7 @@ public ResourceKey of(final PluginContainer plugin, final String value) { @Override public ResourceKey resolve(final String formatted) { try { - final ResourceLocation resourceLocation = new ResourceLocation(formatted); + final ResourceLocation resourceLocation = ResourceLocation.parse(formatted); return (ResourceKey) (Object) resourceLocation; } catch (ResourceLocationException e) { throw new IllegalStateException(e); diff --git a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java index bca61ec13b1..443a1ec052f 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java @@ -341,7 +341,7 @@ private Registry naming(final RegistryType type, final int values, // To address Vanilla shortcomings, some mods will manually prefix their modid onto values they put into Vanilla registry-like // registrars. We need to account for that possibility if (rawId.contains(":")) { - map.put((ResourceKey) (Object) new ResourceLocation(rawId), (A) value.getKey()); + map.put((ResourceKey) (Object) ResourceLocation.parse(rawId), (A) value.getKey()); } else { map.put(ResourceKey.sponge(rawId), (A) value.getKey()); } diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeWorldTemplate.java b/src/main/java/org/spongepowered/common/world/server/SpongeWorldTemplate.java index 0cb311ae3ec..96183174218 100644 --- a/src/main/java/org/spongepowered/common/world/server/SpongeWorldTemplate.java +++ b/src/main/java/org/spongepowered/common/world/server/SpongeWorldTemplate.java @@ -94,8 +94,8 @@ public record SpongeWorldTemplate(ResourceKey key, LevelStem levelStem, DataPack .create(r -> r .group( SpongeAdventure.STRING_CODEC.optionalFieldOf("display_name").forGetter(v -> Optional.ofNullable(v.displayName)), - ResourceLocation.CODEC.optionalFieldOf("game_mode").forGetter(v -> Optional.ofNullable(v.gameMode).map(t -> new ResourceLocation("sponge", t.getName()))), - ResourceLocation.CODEC.optionalFieldOf("difficulty").forGetter(v -> Optional.ofNullable(v.difficulty).map(t -> new ResourceLocation("sponge", t.getKey()))), + ResourceLocation.CODEC.optionalFieldOf("game_mode").forGetter(v -> Optional.ofNullable(v.gameMode).map(t -> ResourceLocation.fromNamespaceAndPath("sponge", t.getName()))), + ResourceLocation.CODEC.optionalFieldOf("difficulty").forGetter(v -> Optional.ofNullable(v.difficulty).map(t -> ResourceLocation.fromNamespaceAndPath("sponge", t.getKey()))), EnumCodec.create(SerializationBehavior.class).optionalFieldOf("serialization_behavior") .forGetter(v -> Optional.ofNullable(v.serializationBehavior)), Codec.INT.optionalFieldOf("view_distance").forGetter(v -> Optional.ofNullable(v.viewDistance)), diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/adventure/KeyMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/adventure/KeyMixin.java index 96de0a69f8b..44b643db01a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/adventure/KeyMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/adventure/KeyMixin.java @@ -40,6 +40,6 @@ public interface KeyMixin { */ @Overwrite static @NonNull Key key(final @NonNull String namespace, final @NonNull String value) { - return (ResourceKey) (Object) new ResourceLocation(namespace, value); + return (ResourceKey) (Object) ResourceLocation.fromNamespaceAndPath(namespace, value); } } diff --git a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java index 0f3f38e8a01..7053ed5dad6 100644 --- a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java +++ b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java @@ -98,7 +98,7 @@ public void listResources(final PackType type, final String namespace, final Str .map(namespaceDir::relativize) .map(Object::toString) // TODO filter needed? .filter(p -> filterValidPath(namespace, p, fileNameValidator)) - .map(s -> new ResourceLocation(namespace, s)) + .map(s -> ResourceLocation.fromNamespaceAndPath(namespace, s)) .forEach(loc -> { out.accept(loc, this.getResource(type, loc)); }); From e80ee135e119f3a158945df0a0633106585ef56f Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 15:55:43 +0200 Subject: [PATCH 004/226] moving MUSIC_DISC to vanilla registry jukebox_playable --- .../resources/mixins.sponge.accessors.json | 1 - .../common/effect/record/SpongeMusicDisc.java | 72 ------------------- .../common/registry/SpongeRegistries.java | 1 - .../registry/loader/SpongeRegistryLoader.java | 26 ------- .../world/item/JukeboxSongMixin_API.java} | 20 ++++-- src/mixins/resources/mixins.sponge.api.json | 1 + 6 files changed, 15 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/org/spongepowered/common/effect/record/SpongeMusicDisc.java rename src/{accessors/java/org/spongepowered/common/accessor/world/item/RecordItemAccessor.java => mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/JukeboxSongMixin_API.java} (69%) diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 617440b2156..100d5af69de 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -139,7 +139,6 @@ "world.inventory.SlotAccessor", "world.item.AdventureModePredicateAccessor", "world.item.ItemCooldowns_CooldownInstanceAccessor", - "world.item.RecordItemAccessor", "world.item.component.CustomDataAccessor", "world.item.enchantment.ItemEnchantmentsAccessor", "world.item.trading.MerchantOfferAccessor", diff --git a/src/main/java/org/spongepowered/common/effect/record/SpongeMusicDisc.java b/src/main/java/org/spongepowered/common/effect/record/SpongeMusicDisc.java deleted file mode 100644 index 7dcd35cfc6c..00000000000 --- a/src/main/java/org/spongepowered/common/effect/record/SpongeMusicDisc.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.effect.record; - - -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; -import net.minecraft.world.item.RecordItem; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.effect.sound.SoundType; -import org.spongepowered.api.effect.sound.music.MusicDisc; -import org.spongepowered.common.accessor.world.item.RecordItemAccessor; -import org.spongepowered.math.vector.Vector3i; - -import java.util.Objects; - -public final class SpongeMusicDisc implements MusicDisc { - - /** - * This is the effect ID that is used by the Effect packet to play a record effect. - * http://wiki.vg/Protocol#Effect - */ - private static final int EFFECT_ID = 1010; - - private final RecordItem item; - private final int id; - - public SpongeMusicDisc(final RecordItem item) { - this.item = item; - this.id = BuiltInRegistries.ITEM.getId(item); - } - - public int getId() { - return this.id; - } - - @Override - public SoundType sound() { - return (SoundType) ((RecordItemAccessor) this.item).accessor$sound(); - } - - public static ClientboundLevelEventPacket createPacket(final Vector3i position, final @Nullable MusicDisc recordType) { - Objects.requireNonNull(position, "position"); - final BlockPos pos = new BlockPos(position.x(), position.y(), position.z()); - // see RecordItem.useOn - return new ClientboundLevelEventPacket(SpongeMusicDisc.EFFECT_ID, pos, recordType == null ? 0 : - ((SpongeMusicDisc) recordType).getId(), false); - } -} diff --git a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java index 3e14c3cac24..952d980de09 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java @@ -67,7 +67,6 @@ public static void registerEarlyGlobalRegistries(final SpongeRegistryHolder hold holder.createFrozenRegistry(RegistryTypes.GOAL_TYPE, SpongeRegistryLoader.goalType()); holder.createFrozenRegistry(RegistryTypes.MATTER_TYPE, SpongeRegistryLoader.matterType()); holder.createFrozenRegistry(RegistryTypes.MOVEMENT_TYPE, SpongeRegistryLoader.movementType()); - holder.createFrozenRegistry(RegistryTypes.MUSIC_DISC, SpongeRegistryLoader.musicDisc()); holder.createFrozenRegistry(RegistryTypes.NOTE_PITCH, SpongeRegistryLoader.notePitch()); holder.createFrozenRegistry(RegistryTypes.OPERATION, SpongeRegistryLoader.operation()); holder.createFrozenRegistry(RegistryTypes.ORIENTATION, SpongeRegistryLoader.orientation()); diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index 07bb8d929ef..cb96f1e1b69 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -27,8 +27,6 @@ import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.RecordItem; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset; import net.minecraft.world.level.material.MapColor; import org.spongepowered.api.ResourceKey; @@ -51,8 +49,6 @@ import org.spongepowered.api.effect.particle.ParticleOption; import org.spongepowered.api.effect.particle.ParticleOptions; import org.spongepowered.api.effect.potion.PotionEffectType; -import org.spongepowered.api.effect.sound.music.MusicDisc; -import org.spongepowered.api.effect.sound.music.MusicDiscs; import org.spongepowered.api.entity.ai.goal.GoalExecutorType; import org.spongepowered.api.entity.ai.goal.GoalExecutorTypes; import org.spongepowered.api.entity.ai.goal.GoalType; @@ -126,7 +122,6 @@ import org.spongepowered.common.economy.SpongeAccountDeletionResultType; import org.spongepowered.common.economy.SpongeTransactionType; import org.spongepowered.common.effect.particle.SpongeParticleOption; -import org.spongepowered.common.effect.record.SpongeMusicDisc; import org.spongepowered.common.entity.ai.SpongeGoalExecutorType; import org.spongepowered.common.entity.ai.goal.SpongeGoalType; import org.spongepowered.common.event.cause.entity.SpongeDismountType; @@ -300,27 +295,6 @@ public static RegistryLoader movementType() { ))); } - public static RegistryLoader musicDisc() { - return RegistryLoader.of(l -> { - // TODO ItemTags.MUSIC_DISCS to check for completion - l.add(MusicDiscs.BLOCKS, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_BLOCKS)); - l.add(MusicDiscs.CAT, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_CAT)); - l.add(MusicDiscs.CHIRP, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_CHIRP)); - l.add(MusicDiscs.FAR, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_FAR)); - l.add(MusicDiscs.MALL, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_MALL)); - l.add(MusicDiscs.MELLOHI, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_MELLOHI)); - l.add(MusicDiscs.MUSIC_DISC_5, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_5)); - l.add(MusicDiscs.MUSIC_DISC_11, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_11)); - l.add(MusicDiscs.MUSIC_DISC_13, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_13)); - l.add(MusicDiscs.OTHERSIDE, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_OTHERSIDE)); - l.add(MusicDiscs.PIGSTEP, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_PIGSTEP)); - l.add(MusicDiscs.STAL, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_STAL)); - l.add(MusicDiscs.STRAD, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_STRAD)); - l.add(MusicDiscs.WAIT, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_WAIT)); - l.add(MusicDiscs.WARD, k -> new SpongeMusicDisc((RecordItem) Items.MUSIC_DISC_WARD)); - }); - } - public static RegistryLoader notePitch() { return RegistryLoader.of(l -> { l.addWithId(0, NotePitches.F_SHARP0, SpongeNotePitch::new); diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/item/RecordItemAccessor.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/JukeboxSongMixin_API.java similarity index 69% rename from src/accessors/java/org/spongepowered/common/accessor/world/item/RecordItemAccessor.java rename to src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/JukeboxSongMixin_API.java index b311321d94a..7b7fa4a636a 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/item/RecordItemAccessor.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/JukeboxSongMixin_API.java @@ -22,16 +22,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.accessor.world.item; +package org.spongepowered.common.mixin.api.minecraft.world.item; +import net.minecraft.core.Holder; import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.item.RecordItem; +import net.minecraft.world.item.JukeboxSong; +import org.spongepowered.api.effect.sound.SoundType; +import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.Shadow; -@Mixin(RecordItem.class) -public interface RecordItemAccessor { +@Mixin(JukeboxSong.class) +public abstract class JukeboxSongMixin_API implements MusicDisc { - @Accessor("sound") SoundEvent accessor$sound(); + @Shadow @Final private Holder soundEvent; + @Override + public SoundType sound() { + return (SoundType) this.soundEvent.value(); + } } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 23fed4650a4..0c3cedbfa17 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -297,6 +297,7 @@ "minecraft.world.item.ItemDisplayContextMixin_API", "minecraft.world.item.ItemMixin_API", "minecraft.world.item.ItemStackMixin_API", + "minecraft.world.item.JukeboxSongMixin_API", "minecraft.world.item.RarityMixin_API", "minecraft.world.item.TiersMixin_API", "minecraft.world.item.alchemy.PotionMixin_API", From d43e8e055e4e8284a4961de3aaaf40baf607f779 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:21:29 +0200 Subject: [PATCH 005/226] fix Keys.PAINTING_VARIANT fix PaintingVariantMixin_API --- .../entity/decoration/PaintingAccessor.java | 38 ------------------- .../resources/mixins.sponge.accessors.json | 1 - .../data/provider/entity/PaintingData.java | 10 +++-- .../decoration/PaintingVariantMixin_API.java | 15 -------- 4 files changed, 6 insertions(+), 58 deletions(-) delete mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/entity/decoration/PaintingAccessor.java diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/decoration/PaintingAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/decoration/PaintingAccessor.java deleted file mode 100644 index eba402e5269..00000000000 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/decoration/PaintingAccessor.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.accessor.world.entity.decoration; - -import net.minecraft.core.Holder; -import net.minecraft.world.entity.decoration.Painting; -import net.minecraft.world.entity.decoration.PaintingVariant; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(Painting.class) -public interface PaintingAccessor { - - @Invoker("setVariant") void invoker$setVariant(final Holder direction); - -} diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 100d5af69de..e68ac10c351 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -89,7 +89,6 @@ "world.entity.decoration.ArmorStandAccessor", "world.entity.decoration.HangingEntityAccessor", "world.entity.decoration.ItemFrameAccessor", - "world.entity.decoration.PaintingAccessor", "world.entity.item.FallingBlockEntityAccessor", "world.entity.item.PrimedTntAccessor", "world.entity.monster.BlazeAccessor", diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/PaintingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/PaintingData.java index 5e8966c9dfc..b5f7f253f77 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/PaintingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/PaintingData.java @@ -25,6 +25,7 @@ package org.spongepowered.common.data.provider.entity; import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerPlayerConnection; @@ -32,10 +33,10 @@ import net.minecraft.world.entity.decoration.PaintingVariant; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.ArtType; +import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; import org.spongepowered.common.accessor.server.level.ChunkMap_TrackedEntityAccessor; import org.spongepowered.common.accessor.world.entity.decoration.HangingEntityAccessor; -import org.spongepowered.common.accessor.world.entity.decoration.PaintingAccessor; import org.spongepowered.common.data.provider.DataProviderRegistrator; public final class PaintingData { @@ -48,14 +49,15 @@ public static void register(final DataProviderRegistrator registrator) { registrator .asMutable(Painting.class) .create(Keys.ART_TYPE) - .get(h -> (ArtType) h.getVariant().value()) + .get(h -> (ArtType) (Object) h.getVariant().value()) .setAnd((h, v) -> { if (!h.level().isClientSide) { final Holder oldArt = h.getVariant(); - ((PaintingAccessor)h).invoker$setVariant(Holder.direct((PaintingVariant) v)); + var newArt = SpongeCommon.server().registryAccess().registryOrThrow(Registries.PAINTING_VARIANT).wrapAsHolder((PaintingVariant) (Object) v); + h.setVariant(newArt); ((HangingEntityAccessor) h).invoker$setDirection(h.getDirection()); if (!h.survives()) { - ((PaintingAccessor)h).invoker$setVariant(oldArt); + h.setVariant(oldArt); ((HangingEntityAccessor) h).invoker$setDirection(h.getDirection()); return false; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/PaintingVariantMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/PaintingVariantMixin_API.java index e8650bb5bc6..e8d4d2f761b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/PaintingVariantMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/PaintingVariantMixin_API.java @@ -26,23 +26,8 @@ import org.spongepowered.api.data.type.ArtType; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; @Mixin(net.minecraft.world.entity.decoration.PaintingVariant.class) public abstract class PaintingVariantMixin_API implements ArtType { - // @formatter:off - @Shadow public abstract int shadow$getWidth(); - @Shadow public abstract int shadow$getHeight(); - // @formatter:on - - @Override - public int width() { - return this.shadow$getWidth(); - } - - @Override - public int height() { - return this.shadow$getHeight(); - } } From 49192201ec205bcfaedce885fe628aa1920afe1d Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:32:44 +0200 Subject: [PATCH 006/226] fix Keys.ACCELERATION --- .../AbstractHurtingProjectileAccessor.java | 40 ------------------- .../resources/mixins.sponge.accessors.json | 1 - .../entity/DamagingProjectileData.java | 10 +---- 3 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractHurtingProjectileAccessor.java diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractHurtingProjectileAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractHurtingProjectileAccessor.java deleted file mode 100644 index 10b4479551f..00000000000 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractHurtingProjectileAccessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.accessor.world.entity.projectile; - -import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(AbstractHurtingProjectile.class) -public interface AbstractHurtingProjectileAccessor { - - @Accessor("xPower") void accessor$xPower(final double xPower); - - @Accessor("yPower") void accessor$yPower(final double yPower); - - @Accessor("zPower") void accessor$zPower(final double zPower); - -} diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index e68ac10c351..053435c1c39 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -110,7 +110,6 @@ "world.entity.player.AbilitiesAccessor", "world.entity.player.PlayerAccessor", "world.entity.projectile.AbstractArrowAccessor", - "world.entity.projectile.AbstractHurtingProjectileAccessor", "world.entity.projectile.ArrowAccessor", "world.entity.projectile.EyeOfEnderAccessor", "world.entity.projectile.FireworkRocketEntityAccessor", diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/DamagingProjectileData.java b/src/main/java/org/spongepowered/common/data/provider/entity/DamagingProjectileData.java index d5f6114647e..637e43bf59b 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/DamagingProjectileData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/DamagingProjectileData.java @@ -26,9 +26,7 @@ import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; import org.spongepowered.api.data.Keys; -import org.spongepowered.common.accessor.world.entity.projectile.AbstractHurtingProjectileAccessor; import org.spongepowered.common.data.provider.DataProviderRegistrator; -import org.spongepowered.math.vector.Vector3d; public final class DamagingProjectileData { @@ -40,12 +38,8 @@ public static void register(final DataProviderRegistrator registrator) { registrator .asMutable(AbstractHurtingProjectile.class) .create(Keys.ACCELERATION) - .get(h -> new Vector3d(h.xPower, h.yPower, h.zPower)) - .set((h, v) -> { - ((AbstractHurtingProjectileAccessor) h).accessor$xPower(v.x()); - ((AbstractHurtingProjectileAccessor) h).accessor$yPower(v.y()); - ((AbstractHurtingProjectileAccessor) h).accessor$zPower(v.z()); - }); + .get(h -> h.accelerationPower) + .set((h, v) -> h.accelerationPower = v); } // @formatter:on } From f6208aff83bd4dff892aff0ad87b4e59a02bd4ce Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:34:53 +0200 Subject: [PATCH 007/226] fix Keys.IS_SADDLED --- .../spongepowered/common/data/provider/entity/PigData.java | 2 +- .../core/world/entity/animal/horse/AbstractHorseMixin.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/PigData.java b/src/main/java/org/spongepowered/common/data/provider/entity/PigData.java index c654314342d..310a184ba5a 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/PigData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/PigData.java @@ -42,7 +42,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(Pig::isSaddled) .set((h, v) -> { if (v) { - h.equipSaddle(null); + h.equipSaddle(null, null); } else { ((PigAccessor) h).accessor$steering().setSaddle(false); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/horse/AbstractHorseMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/horse/AbstractHorseMixin.java index 33cc5b887f9..a95b5af8bb9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/horse/AbstractHorseMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/horse/AbstractHorseMixin.java @@ -28,6 +28,7 @@ import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.animal.horse.AbstractHorse; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -39,7 +40,7 @@ public abstract class AbstractHorseMixin extends AgableMobMixin implements Abstr // @formatter:off @Shadow protected SimpleContainer inventory; - @Shadow public abstract void shadow$equipSaddle(@Nullable SoundSource sound); + @Shadow public abstract void shadow$equipSaddle(ItemStack stack, @Nullable SoundSource sound); @Shadow public abstract boolean shadow$isSaddled(); // @formatter:on @@ -51,7 +52,7 @@ public abstract class AbstractHorseMixin extends AgableMobMixin implements Abstr @Override public void bridge$setSaddled(boolean saddled) { if (!this.shadow$isSaddled() && saddled) { - this.shadow$equipSaddle(null); + this.shadow$equipSaddle(new ItemStack(Items.SADDLE), null); } else if (this.shadow$isSaddled() && !saddled){ this.inventory.setItem(0, ItemStack.EMPTY); } From 0aad865419ca397f527680f3aea524646652a740 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 18:54:34 +0200 Subject: [PATCH 008/226] fix Keys.ITEM_STACK_SNAPSHOT jukebox fix playing records from API --- .../data/provider/block/entity/JukeBoxData.java | 6 +++--- .../minecraft/server/level/ServerPlayerMixin_API.java | 11 ++++++++--- .../api/minecraft/world/level/LevelMixin_API.java | 7 +++++-- .../block/entity/JukeboxBlockEntityMixin_API.java | 9 ++------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/JukeBoxData.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/JukeBoxData.java index e09add8bd25..7ac2bca0ec7 100644 --- a/src/main/java/org/spongepowered/common/data/provider/block/entity/JukeBoxData.java +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/JukeBoxData.java @@ -24,8 +24,8 @@ */ package org.spongepowered.common.data.provider.block.entity; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.RecordItem; import net.minecraft.world.level.block.entity.JukeboxBlockEntity; import org.spongepowered.api.data.Keys; import org.spongepowered.common.data.provider.DataProviderRegistrator; @@ -44,8 +44,8 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> h.getItem(0).isEmpty() ? null : ItemStackUtil.snapshotOf(h.getItem(0))) .setAnd((h, v) -> { final ItemStack record = ItemStackUtil.fromSnapshotToNative(v); - if (record.getItem() instanceof RecordItem) { - h.setItem(0, record); + if (record.has(DataComponents.JUKEBOX_PLAYABLE)) { + h.setTheItem(record); return true; } if (record.isEmpty()) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java index b0a12a1592b..439050000b2 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java @@ -51,6 +51,7 @@ import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; import net.minecraft.network.protocol.game.ClientboundDeleteChatPacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; @@ -66,6 +67,7 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.JukeboxSong; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.NonNull; @@ -109,7 +111,6 @@ import org.spongepowered.common.bridge.server.network.ServerCommonPacketListenerImplBridge; import org.spongepowered.common.bridge.world.level.border.WorldBorderBridge; import org.spongepowered.common.effect.particle.SpongeParticleHelper; -import org.spongepowered.common.effect.record.SpongeMusicDisc; import org.spongepowered.common.entity.player.SpongeUserView; import org.spongepowered.common.entity.player.tab.SpongeTabList; import org.spongepowered.common.event.tracking.PhaseTracker; @@ -117,6 +118,7 @@ import org.spongepowered.common.profile.SpongeGameProfile; import org.spongepowered.common.util.BookUtil; import org.spongepowered.common.util.NetworkUtil; +import org.spongepowered.common.util.VecHelper; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3i; @@ -263,12 +265,15 @@ public boolean kick(final Component message) { @Override public void playMusicDisc(final Vector3i position, final MusicDisc recordType) { - this.connection.send(SpongeMusicDisc.createPacket(Objects.requireNonNull(position, "position"), Objects.requireNonNull(recordType, "recordType"))); + Objects.requireNonNull(position, "position"); + Objects.requireNonNull(recordType, "recordType"); + int songId = this.shadow$level().registryAccess().registryOrThrow(Registries.JUKEBOX_SONG).getId((JukeboxSong) (Object) recordType); + this.connection.send(new ClientboundLevelEventPacket(1010, VecHelper.toBlockPos(position), songId, false)); } @Override public void stopMusicDisc(final Vector3i position) { - this.connection.send(SpongeMusicDisc.createPacket(position, null)); + this.connection.send(new ClientboundLevelEventPacket(1011, VecHelper.toBlockPos(position), 0, false)); } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java index f2a76d5506d..6fb2c57038a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java @@ -27,6 +27,7 @@ import net.kyori.adventure.sound.Sound; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; @@ -39,6 +40,8 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Tuple; +import net.minecraft.world.item.JukeboxSong; +import net.minecraft.world.item.JukeboxSongPlayer; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; @@ -89,7 +92,6 @@ import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.effect.particle.SpongeParticleHelper; -import org.spongepowered.common.effect.record.SpongeMusicDisc; import org.spongepowered.common.entity.SpongeEntityTypes; import org.spongepowered.common.registry.RegistryHolderLogic; import org.spongepowered.common.registry.SpongeRegistryHolder; @@ -414,7 +416,8 @@ public ArchetypeVolume createArchetypeVolume(final Vector3i min, final Vector3i } private void api$playRecord(final Vector3i position, @Nullable final MusicDisc recordType) { - this.shadow$getServer().getPlayerList().broadcastAll(SpongeMusicDisc.createPacket(position, recordType), this.shadow$dimension()); + var songPlayer = new JukeboxSongPlayer(() -> {}, VecHelper.toBlockPos(position)); + songPlayer.play((Level) (Object) this, Holder.direct((JukeboxSong) (Object) recordType)); } // EntityVolume diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java index 21b6efe0cae..8c298d407be 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java @@ -25,7 +25,6 @@ package org.spongepowered.common.mixin.api.minecraft.world.level.block.entity; import net.minecraft.world.item.Item; -import net.minecraft.world.item.RecordItem; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.JukeboxBlock; import net.minecraft.world.level.block.entity.JukeboxBlockEntity; @@ -48,7 +47,7 @@ public abstract class JukeboxBlockEntityMixin_API extends BlockEntityMixin_API i @Shadow public abstract void shadow$setTheItem(final net.minecraft.world.item.ItemStack $$1); - @Shadow public abstract void shadow$popOutRecord(); + @Shadow public abstract void shadow$popOutTheItem(); // @formatter:on @@ -70,19 +69,15 @@ public void stop() { public void eject() { final BlockState block = this.level.getBlockState(this.shadow$getBlockPos()); if (block.getBlock() == Blocks.JUKEBOX) { - this.shadow$popOutRecord(); + this.shadow$popOutTheItem(); } } @Override public void insert(final ItemStack record) { final net.minecraft.world.item.ItemStack itemStack = ItemStackUtil.toNative(record); - if (!(itemStack.getItem() instanceof RecordItem)) { - return; - } final BlockState block = this.level.getBlockState(this.shadow$getBlockPos()); if (block.getBlock() == Blocks.JUKEBOX) { - // Don't use BlockJukebox#insertRecord - it looses item data this.shadow$setTheItem(itemStack); this.level.setBlock(this.shadow$getBlockPos(), block.setValue(JukeboxBlock.HAS_RECORD, true), Constants.BlockChangeFlags.NOTIFY_CLIENTS); } From 67c59896ee67ab8bc4d2fcb21f92366f2d35baad Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 00:28:51 +0200 Subject: [PATCH 009/226] fix EquipmentGroups --- SpongeAPI | 2 +- .../common/registry/loader/VanillaRegistryLoader.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index e42b6256244..bd57cec8f88 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit e42b62562441016316e4c090f4498b0bbc0338fa +Subproject commit bd57cec8f88f2ff1bf7aaf4cc594e64901b7c9d7 diff --git a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java index 443a1ec052f..5da1997c44c 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java @@ -170,9 +170,9 @@ private void loadEnumRegistries() { this.automaticSerializedName(RegistryTypes.DOOR_HINGE, DoorHingeSide.values()); this.automaticSerializedName(RegistryTypes.DRIPSTONE_SEGMENT, DripstoneThickness.values()); this.manualName(RegistryTypes.EQUIPMENT_GROUP, EquipmentSlot.Type.values(), map -> { - map.put(EquipmentSlot.Type.ARMOR, "worn"); + map.put(EquipmentSlot.Type.HUMANOID_ARMOR, "worn"); map.put(EquipmentSlot.Type.HAND, "held"); - map.put(EquipmentSlot.Type.BODY, "body"); + map.put(EquipmentSlot.Type.ANIMAL_ARMOR, "animal_armor"); }); this.manualName(RegistryTypes.EQUIPMENT_TYPE, EquipmentSlot.values(), map -> { map.put(EquipmentSlot.CHEST, "chest"); From a7744ae2422d890f399a8882bafa3da1fef90375 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 17:29:22 +0200 Subject: [PATCH 010/226] fix enchantment data + tags --- .../vanilla/generator/GeneratorMain.java | 7 +++++ .../item/stack/BookPagesItemStackData.java | 10 +++++-- .../common/datapack/SpongeDataPackType.java | 4 +-- .../SpongeRandomEnchantmentListBuilder.java | 23 +++++++------- .../enchantment/EnchantmentMixin_API.java | 30 ++++--------------- .../item/enchantment/EnchantmentMixin.java | 17 ----------- .../EnchantmentContainerMixin_Inventory.java | 4 +-- 7 files changed, 35 insertions(+), 60 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index a4b1384f60d..a6840de5ee0 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -653,6 +653,13 @@ private static List generators(final Context context) { "tag", "FluidTypeTags" ), + new TagGenerator( + "ENCHANTMENT_TYPE", + Registries.ENCHANTMENT, + context.relativeClass("item.enchantment", "EnchantmentType"), + "tag", + "EnchantmenTypeTags" + ), new RegistryEntriesGenerator<>( "event.cause.entity.damage", "DamageTypes", diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java index 441af7e7f9e..c048167e2fd 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java @@ -26,12 +26,14 @@ import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.ItemEnchantments; import org.spongepowered.api.data.Keys; import org.spongepowered.api.item.enchantment.Enchantment; import org.spongepowered.api.item.enchantment.EnchantmentType; +import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.data.provider.DataProviderRegistrator; import org.spongepowered.common.util.Predicates; @@ -63,7 +65,7 @@ public static void register(final DataProviderRegistrator registrator) { private static List get(final ItemStack holder, final DataComponentType component) { return holder.getOrDefault(component, ItemEnchantments.EMPTY).entrySet().stream() - .map(e -> Enchantment.of((EnchantmentType) e.getKey().value(), e.getIntValue())).toList(); + .map(e -> Enchantment.of((EnchantmentType) (Object) e.getKey().value(), e.getIntValue())).toList(); } private static boolean set(final ItemStack holder, final List value, final Function, Stream> filter, @@ -71,10 +73,14 @@ private static boolean set(final ItemStack holder, final List value if (value.isEmpty()) { return BookPagesItemStackData.delete(holder, component); } + final var registry = SpongeCommon.server().registryAccess().registryOrThrow(Registries.ENCHANTMENT); holder.update(component, ItemEnchantments.EMPTY, ench -> { final ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(ench); mutable.keySet().clear(); - value.forEach(e -> mutable.set((net.minecraft.world.item.enchantment.Enchantment) e.type(), e.level())); + value.forEach(e -> { + var enchHolder = registry.wrapAsHolder((net.minecraft.world.item.enchantment.Enchantment) (Object) e.type()); + mutable.set(enchHolder, e.level()); + }); return mutable.toImmutable(); }); return true; diff --git a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java index 02a3d73970d..1aeb63341bb 100644 --- a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java +++ b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java @@ -26,10 +26,10 @@ import com.google.gson.JsonElement; import io.leangen.geantyref.TypeToken; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagManager; import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.advancement.AdvancementTemplate; import org.spongepowered.api.adventure.ChatTypeTemplate; @@ -260,7 +260,7 @@ public DataPackType damageType() { @Override public > DataPackType> tag(RegistryType registry) { - final String tagDir = TagManager.getTagDir(ResourceKey.createRegistryKey((ResourceLocation) (Object) registry.location())); + final String tagDir = Registries.tagsDirPath(ResourceKey.createRegistryKey((ResourceLocation) (Object) registry.location())); return SpongeDataPackType.custom(new TypeToken<>() {}, tagDir, new TagDataPackSerializer<>(SpongeTagTemplate::encode, null), // TODO decoder true); diff --git a/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java b/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java index f3be116cd2b..8471cf38d21 100644 --- a/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java +++ b/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java @@ -27,6 +27,8 @@ import com.google.common.collect.Lists; import net.minecraft.Util; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; import net.minecraft.util.RandomSource; import net.minecraft.util.random.WeightedRandom; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -47,7 +49,6 @@ public final class SpongeRandomEnchantmentListBuilder implements Enchantment.Ran private @Nullable Integer seed; private @Nullable Integer option; private @Nullable Integer level; - private boolean treasure; private @Nullable List pool; private @Nullable ItemStack item; @@ -71,12 +72,6 @@ public Enchantment.RandomListBuilder level(final int level) { return this; } - @Override - public Enchantment.RandomListBuilder treasure(final boolean treasure) { - this.treasure = treasure; - return this; - } - @Override public Enchantment.RandomListBuilder fixedPool(final List pool) { this.pool = pool; @@ -98,10 +93,9 @@ public List build() throws IllegalStateException { if (this.pool == null || this.pool.isEmpty()) { Objects.requireNonNull(this.item, "The item cannot be null"); this.randomSource.setSeed(this.seed + this.option); - enchantments = EnchantmentHelper.selectEnchantment(SpongeCommon.server().getWorldData().enabledFeatures(), - this.randomSource, ItemStackUtil.toNative(this.item), this.level, this.treasure); - - + final var registry = SpongeCommon.server().registryAccess().registryOrThrow(Registries.ENCHANTMENT); + var stream = registry.holders().map($$0x -> (Holder)$$0x); + enchantments = EnchantmentHelper.selectEnchantment(this.randomSource, ItemStackUtil.toNative(this.item), this.level, stream); } else { this.randomSource.setSeed(this.seed + this.option); enchantments = this.basedOfFixedPool(this.randomSource, this.pool); @@ -145,8 +139,11 @@ public static List fromNative(final List list) } public static List toNative(final List list) { - return list.stream().map(ench -> - new EnchantmentInstance(((net.minecraft.world.item.enchantment.Enchantment) ench.type()), ench.level()) + final var registry = SpongeCommon.server().registryAccess().registryOrThrow(Registries.ENCHANTMENT); + return list.stream().map(ench -> { + var mcEnch = registry.wrapAsHolder((net.minecraft.world.item.enchantment.Enchantment) (Object) ench.type()); + return new EnchantmentInstance(mcEnch, ench.level()); + } ).collect(Collectors.toList()); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java index bcc440ac9d0..d8757a27774 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java @@ -25,21 +25,18 @@ package org.spongepowered.common.mixin.api.minecraft.world.item.enchantment; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; +import net.minecraft.core.Holder; import net.minecraft.world.item.enchantment.Enchantment; import org.spongepowered.api.item.enchantment.EnchantmentType; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Interface.Remap; -import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.item.util.ItemStackUtil; @Mixin(net.minecraft.world.item.enchantment.Enchantment.class) -@Implements(@Interface(iface = EnchantmentType.class, prefix = "enchantment$", remap = Remap.NONE)) public abstract class EnchantmentMixin_API implements EnchantmentType { // @formatter:off @@ -47,15 +44,10 @@ public abstract class EnchantmentMixin_API implements EnchantmentType { @Shadow public abstract int shadow$getMaxLevel(); @Shadow public abstract int shadow$getMinCost(int level); @Shadow public abstract int shadow$getMaxCost(int level); - @Shadow protected abstract boolean shadow$checkCompatibility(net.minecraft.world.item.enchantment.Enchantment ench); - @Shadow protected abstract String shadow$getOrCreateDescriptionId(); - @Shadow public abstract boolean shadow$isTreasureOnly(); - @Shadow public abstract boolean shadow$isCurse(); @Shadow public abstract int shadow$getWeight(); - + @Shadow @Final private net.minecraft.network.chat.Component description; // @formatter:on - @Override public int weight() { return this.shadow$getWeight(); @@ -93,22 +85,12 @@ public boolean canBeAppliedToStack(final ItemStack stack) { @Override public boolean isCompatibleWith(final EnchantmentType ench) { - return this.shadow$checkCompatibility((net.minecraft.world.item.enchantment.Enchantment) ench); + return Enchantment.areCompatible(Holder.direct((Enchantment) (Object) this), Holder.direct((Enchantment) (Object) ench)); } @Override public Component asComponent() { - return Component.translatable(this.shadow$getOrCreateDescriptionId(), this.shadow$isCurse() ? NamedTextColor.RED : NamedTextColor.GRAY); - } - - @Override - public boolean isTreasure() { - return this.shadow$isTreasureOnly(); - } - - @Intrinsic - public boolean enchantment$isCurse() { - return this.shadow$isCurse(); + return SpongeAdventure.asAdventure(this.description); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/item/enchantment/EnchantmentMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/enchantment/EnchantmentMixin.java index e26802d5115..7968d13b542 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/item/enchantment/EnchantmentMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/enchantment/EnchantmentMixin.java @@ -24,27 +24,10 @@ */ package org.spongepowered.common.mixin.core.world.item.enchantment; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.enchantment.Enchantment; -import org.spongepowered.api.ResourceKey; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.StringJoiner; @Mixin(Enchantment.class) public abstract class EnchantmentMixin { - // @formatter:off - @Shadow public abstract String shadow$getDescriptionId(); - // @formatter:on - - @Override - public String toString() { - final ResourceKey key = (ResourceKey) (Object) BuiltInRegistries.ENCHANTMENT.getKey((Enchantment) (Object) this); - return new StringJoiner(", ", "EnchantmentType[", "]") - .add("Name=" + this.shadow$getDescriptionId()) - .add("Key=" + key) - .toString(); - } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/inventory/container/EnchantmentContainerMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/inventory/container/EnchantmentContainerMixin_Inventory.java index 878d5ff4611..e3a0315872f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/inventory/container/EnchantmentContainerMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/inventory/container/EnchantmentContainerMixin_Inventory.java @@ -25,10 +25,10 @@ package org.spongepowered.common.mixin.inventory.event.inventory.container; import net.minecraft.core.BlockPos; +import net.minecraft.core.RegistryAccess; import net.minecraft.util.RandomSource; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.DataSlot; import net.minecraft.world.inventory.EnchantmentMenu; @@ -74,7 +74,7 @@ public abstract class EnchantmentContainerMixin_Inventory { } @Inject(method = "getEnchantmentList", cancellable = true, at = @At(value = "RETURN")) - private void impl$onBuildEnchantmentList(final FeatureFlagSet ffs, + private void impl$onBuildEnchantmentList(final RegistryAccess ra, final ItemStack stack, final int enchantSlot, final int level, final CallbackInfoReturnable> cir) { final List newList = InventoryEventFactory .callEnchantEventEnchantmentList((EnchantmentMenu) (Object) this, this.enchantmentSeed.get(), stack, enchantSlot, level, cir.getReturnValue()); From 9df5a3977b8199cae1393c1a9adb97cdca745df6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 02:42:37 +0200 Subject: [PATCH 011/226] fix FishingRodItemMixin --- .../core/world/item/FishingRodItemMixin.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/item/FishingRodItemMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/FishingRodItemMixin.java index 2fbc110f0ef..ec6a39b5881 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/item/FishingRodItemMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/FishingRodItemMixin.java @@ -24,6 +24,7 @@ */ package org.spongepowered.common.mixin.core.world.item; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; @@ -62,23 +63,27 @@ private void cancelHookRetraction(Level world, Player player, InteractionHand ha @Inject(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V", ordinal = 1), cancellable = true) - private void onThrowEvent(Level world, Player player, InteractionHand hand, CallbackInfoReturnable> cir) { - if (world.isClientSide) { + private void onThrowEvent(Level level, Player player, InteractionHand hand, CallbackInfoReturnable> cir) { + if (level.isClientSide) { // Only fire event on server-side to avoid crash on client return; } ItemStack itemstack = player.getItemInHand(hand); - int k = EnchantmentHelper.getFishingSpeedBonus(itemstack); - int j = EnchantmentHelper.getFishingLuckBonus(itemstack); - FishingHook fishHook = new FishingHook(player, world, j, k); - PhaseTracker.getCauseStackManager().pushCause(player); - if (SpongeCommon.post(SpongeEventFactory.createFishingEventStart(PhaseTracker.getCauseStackManager().currentCause(), (FishingBobber) fishHook))) { - fishHook.remove(Entity.RemovalReason.DISCARDED); // Bye - cir.setReturnValue(new InteractionResultHolder<>(InteractionResult.SUCCESS, player.getItemInHand(hand))); - } else { - this.impl$fishHook = fishHook; + + if (level instanceof ServerLevel serverLevel) { + int $$6 = (int)(EnchantmentHelper.getFishingTimeReduction(serverLevel, itemstack, player) * 20.0F); + int $$7 = EnchantmentHelper.getFishingLuckBonus(serverLevel, itemstack, player); + FishingHook fishHook = new FishingHook(player, level, $$7, $$6); + + PhaseTracker.getCauseStackManager().pushCause(player); + if (SpongeCommon.post(SpongeEventFactory.createFishingEventStart(PhaseTracker.getCauseStackManager().currentCause(), (FishingBobber) fishHook))) { + fishHook.remove(Entity.RemovalReason.DISCARDED); // Bye + cir.setReturnValue(new InteractionResultHolder<>(InteractionResult.SUCCESS, player.getItemInHand(hand))); + } else { + this.impl$fishHook = fishHook; + } + PhaseTracker.getCauseStackManager().popCause(); } - PhaseTracker.getCauseStackManager().popCause(); } @Redirect(method = "use", at = @At(value = "NEW", target = "net/minecraft/world/entity/projectile/FishingHook")) From 4d5582c73347e0b6bc5f48b03128ee550a95c35e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 01:07:18 +0200 Subject: [PATCH 012/226] fix attributes --- .../SpongeAttributeModifierBuilder.java | 22 +++++++----------- .../AttributeInstanceMixin_API.java | 23 +++++++++---------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/spongepowered/common/entity/attribute/SpongeAttributeModifierBuilder.java b/src/main/java/org/spongepowered/common/entity/attribute/SpongeAttributeModifierBuilder.java index 54a5452e6cf..5b29661f430 100644 --- a/src/main/java/org/spongepowered/common/entity/attribute/SpongeAttributeModifierBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/attribute/SpongeAttributeModifierBuilder.java @@ -24,33 +24,28 @@ */ package org.spongepowered.common.entity.attribute; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.entity.attribute.AttributeModifier; import org.spongepowered.api.entity.attribute.AttributeOperation; import java.util.Objects; -import java.util.UUID; public final class SpongeAttributeModifierBuilder implements AttributeModifier.Builder { // Use a random id - private UUID id = UUID.randomUUID(); - private String name; private AttributeOperation operation; private double amount; + private ResourceLocation key; public SpongeAttributeModifierBuilder() { } @Override - public AttributeModifier.Builder id(final UUID id) { - this.id = Objects.requireNonNull(id, "Modifier id cannot be null"); + public AttributeModifier.Builder key(final ResourceKey key) { + this.key = (ResourceLocation) (Object) key; return this; } - @Override - public AttributeModifier.Builder name(final String name) { - this.name = Objects.requireNonNull(name, "Name cannot be null"); - return this; - } @Override public AttributeModifier.Builder operation(final AttributeOperation operation) { @@ -66,16 +61,15 @@ public AttributeModifier.Builder amount(final double amount) { @Override public AttributeModifier build() { - Objects.requireNonNull(this.name, "Name must be set"); + Objects.requireNonNull(this.key, "ResourceKey must be set"); Objects.requireNonNull(this.operation, "Operation must be set"); - return (AttributeModifier) (Object) new net.minecraft.world.entity.ai.attributes.AttributeModifier(this.id, this.name, this.amount, (net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation) (Object) this.operation); + return (AttributeModifier) (Object) new net.minecraft.world.entity.ai.attributes.AttributeModifier(this.key, this.amount, (net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation) (Object) this.operation); } @Override public AttributeModifier.Builder reset() { // Randomize id when reset - this.id = UUID.randomUUID(); - this.name = null; + this.key = null; this.amount = 0.0D; this.operation = null; return this; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java index 79d63af52ac..2d00107ceb0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java @@ -25,7 +25,9 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.ai.attributes; import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.entity.attribute.Attribute; import org.spongepowered.api.entity.attribute.AttributeModifier; import org.spongepowered.api.entity.attribute.AttributeOperation; @@ -44,6 +46,8 @@ import java.util.Set; import java.util.UUID; +import javax.annotation.Nullable; + @Mixin(AttributeInstance.class) @Implements(@Interface(iface = Attribute.class, prefix = "attribute$", remap = Remap.NONE)) public abstract class AttributeInstanceMixin_API implements Attribute { @@ -53,13 +57,13 @@ public abstract class AttributeInstanceMixin_API implements Attribute { @Shadow public abstract double shadow$getBaseValue(); @Shadow public abstract void shadow$setBaseValue(double baseValue); @Shadow public abstract double shadow$getValue(); - @Shadow public abstract net.minecraft.world.entity.ai.attributes.AttributeModifier shadow$getModifier(UUID uuid); - @Shadow public abstract boolean shadow$hasModifier(net.minecraft.world.entity.ai.attributes.AttributeModifier modifier); @Shadow protected abstract void shadow$addModifier(net.minecraft.world.entity.ai.attributes.AttributeModifier modifier); @Shadow public abstract void shadow$removeModifier(net.minecraft.world.entity.ai.attributes.AttributeModifier modifier); - @Shadow public abstract void shadow$removeModifier(UUID uuid); @Shadow abstract Map shadow$getModifiers(net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation p_225504_1_); @Shadow public abstract Set shadow$getModifiers(); + @Shadow public abstract boolean shadow$hasModifier(final ResourceLocation $$0); + @Shadow @Nullable public abstract net.minecraft.world.entity.ai.attributes.AttributeModifier shadow$getModifier(final ResourceLocation $$0); + // @formatter:on @Override @@ -94,12 +98,7 @@ public Collection modifiers(final AttributeOperation operatio @Override public boolean hasModifier(final AttributeModifier modifier) { - return this.shadow$hasModifier((net.minecraft.world.entity.ai.attributes.AttributeModifier) (Object) Objects.requireNonNull(modifier, "modifier")); - } - - @Override - public Optional modifier(final UUID uniqueId) { - return Optional.ofNullable((AttributeModifier) (Object) this.shadow$getModifier(Objects.requireNonNull(uniqueId, "uniqueId"))); + return this.shadow$hasModifier((ResourceLocation) (Object) modifier.key()); } @Override @@ -112,9 +111,9 @@ public void removeModifier(final AttributeModifier modifier) { this.shadow$removeModifier((net.minecraft.world.entity.ai.attributes.AttributeModifier) (Object) Objects.requireNonNull(modifier, "modifier")); } - @Intrinsic - public void attribute$removeModifier(final UUID uniqueId) { - this.shadow$removeModifier(Objects.requireNonNull(uniqueId, "uniqueId")); + @Override + public Optional modifier(final ResourceKey key) { + return Optional.ofNullable((AttributeModifier) (Object) this.shadow$getModifier((ResourceLocation) (Object) Objects.requireNonNull(key, "uniqueId"))); } } From 82a0232aa6ae770ec65602b7de9de8f85763f17e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 00:56:48 +0200 Subject: [PATCH 013/226] fix exp --- .../common/bridge/world/entity/LivingEntityBridge.java | 6 ++++-- .../common/mixin/core/server/level/ServerPlayerMixin.java | 4 ++-- .../common/mixin/core/world/entity/LivingEntityMixin.java | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java b/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java index f54588a7cf2..759abbee255 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java @@ -24,14 +24,16 @@ */ package org.spongepowered.common.bridge.world.entity; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; public interface LivingEntityBridge { boolean bridge$damageEntity(DamageSource damageSource, float damage); - default int bridge$getExperiencePointsOnDeath(LivingEntity entity) { - return entity.getExperienceReward(); + default int bridge$getExperiencePointsOnDeath(LivingEntity entity, ServerLevel $$0, Entity $$1) { + return entity.getExperienceReward($$0, $$1); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index 158166b3fd3..17add533a95 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -336,11 +336,11 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr } @Override - public int bridge$getExperiencePointsOnDeath(final LivingEntity entity) { + public int bridge$getExperiencePointsOnDeath(final LivingEntity entity, final ServerLevel $$0, final Entity $$1) { if (this.impl$keepInventory != null && this.impl$keepInventory) { return 0; } - return super.bridge$getExperiencePointsOnDeath(entity); + return super.bridge$getExperiencePointsOnDeath(entity, $$0, $$1); } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java index 7768e4e6173..849171a6cc0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java @@ -309,11 +309,11 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt } } - @Redirect(method = "dropExperience()V", + @Redirect(method = "dropExperience", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;getExperienceReward()I")) - protected int impl$exposeGetExperienceForDeath(final LivingEntity entity) { - return this.bridge$getExperiencePointsOnDeath(entity); + target = "Lnet/minecraft/world/entity/LivingEntity;getExperienceReward(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;)I")) + protected int impl$exposeGetExperienceForDeath(final LivingEntity instance, final ServerLevel $$0, final Entity $$1) { + return this.bridge$getExperiencePointsOnDeath(instance, $$0, $$1); } /** From aef1bb55d4f89702ef7b96fa57033e0afed79dba Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:56:01 +0200 Subject: [PATCH 014/226] Keys.FOOD_CONVERTS_TO --- .../provider/item/stack/ItemStackData.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index 5437c52e45d..efee62b5ac6 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -61,11 +61,12 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; @SuppressWarnings({"unchecked", "UnstableApiUsage"}) public final class ItemStackData { - public static final FoodProperties DEFAULT_FOOD_PROPERTIES = new FoodProperties(0, 0, false, 1.6F, List.of()); + public static final FoodProperties DEFAULT_FOOD_PROPERTIES = new FoodProperties(0, 0, false, 1.6F, Optional.empty(), List.of()); private ItemStackData() { } @@ -119,7 +120,7 @@ public static void register(final DataProviderRegistrator registrator) { } } h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, - fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), newEffects)); + fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), fp.usingConvertsTo(), newEffects)); }) .create(Keys.BURN_TIME) @@ -195,29 +196,38 @@ public static void register(final DataProviderRegistrator registrator) { return food == null ? null : food.nutrition(); }) .set((h, v) -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, - fp -> new FoodProperties(v, fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), fp.effects()))) + fp -> new FoodProperties(v, fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), fp.usingConvertsTo(), fp.effects()))) .create(Keys.REPLENISHED_SATURATION) .get(h -> { final var food = h.get(DataComponents.FOOD); return food == null ? null : (double) food.saturation(); }) .set((h, v) -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, - fp -> new FoodProperties(fp.nutrition(), v.floatValue(), fp.canAlwaysEat(), fp.eatSeconds(), fp.effects()))) + fp -> new FoodProperties(fp.nutrition(), v.floatValue(), fp.canAlwaysEat(), fp.eatSeconds(), fp.usingConvertsTo(), fp.effects()))) .create(Keys.CAN_ALWAYS_EAT) .get(h -> { final var food = h.get(DataComponents.FOOD); return food == null ? null : food.canAlwaysEat(); }) .set((h, v) -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, - fp -> new FoodProperties(fp.nutrition(), fp.saturation(), v, fp.eatSeconds(), fp.effects()))) + fp -> new FoodProperties(fp.nutrition(), fp.saturation(), v, fp.eatSeconds(), fp.usingConvertsTo(), fp.effects()))) .create(Keys.EATING_TIME) .get(h -> { final var food = h.get(DataComponents.FOOD); return food == null ? null : Ticks.of(food.eatDurationTicks()); }) .set((h, v) -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, - fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), v.ticks() / 20f, fp.effects()))) - .create(Keys.REPAIR_COST) + fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), v.ticks() / 20f, fp.usingConvertsTo(), fp.effects()))) + .create(Keys.FOOD_CONVERTS_TO) + .get(h -> { + final var food = h.get(DataComponents.FOOD); + return food == null ? null : food.usingConvertsTo().map(ItemStackUtil::fromNative).orElse(null); + }) + .set((h, v) -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, + fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), Optional.ofNullable(ItemStackUtil.toNative(v)), fp.effects()))) + .delete(h -> h.update(DataComponents.FOOD, DEFAULT_FOOD_PROPERTIES, + fp -> new FoodProperties(fp.nutrition(), fp.saturation(), fp.canAlwaysEat(), fp.eatSeconds(), Optional.empty(), fp.effects()))) + .create(Keys.REPAIR_COST) .get(h -> h.getOrDefault(DataComponents.REPAIR_COST, 0)) .set((stack, cost) -> stack.set(DataComponents.REPAIR_COST, cost)) .delete(stack -> stack.remove(DataComponents.REPAIR_COST)) From 888efb78009c366dacce9b24c1493cd1bb66c0e9 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 18:04:29 +0200 Subject: [PATCH 015/226] fix SpongeWorldManager multiworld check --- .../spongepowered/common/world/server/SpongeWorldManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java b/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java index c55ed636ee9..6499c58c5a4 100644 --- a/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java +++ b/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java @@ -37,6 +37,7 @@ import net.minecraft.data.worldgen.features.MiscOverworldFeatures; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; @@ -690,7 +691,7 @@ private void unloadWorld0(final ServerLevel world) throws IOException { public void loadLevel() { - final boolean multiworldEnabled = this.server.isSingleplayer() || this.server.isNetherEnabled(); + final boolean multiworldEnabled = this.server.isSingleplayer() || (this.server instanceof DedicatedServer ds && ds.getProperties().allowNether); if (!multiworldEnabled) { SpongeCommon.logger().warn("The option 'allow-nether' has been set to 'false' in the server.properties. " + "Multi-World support has been disabled and no worlds besides the default world will be loaded."); From a2abe142aca3d834d2ea95ef33b6778575cc1b38 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 01:50:50 +0200 Subject: [PATCH 016/226] fix client --- .../client/gui/widget/ScrollPanel.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/vanilla/src/main/java/org/spongepowered/vanilla/client/gui/widget/ScrollPanel.java b/vanilla/src/main/java/org/spongepowered/vanilla/client/gui/widget/ScrollPanel.java index a3f17120dda..cc70debc8d9 100644 --- a/vanilla/src/main/java/org/spongepowered/vanilla/client/gui/widget/ScrollPanel.java +++ b/vanilla/src/main/java/org/spongepowered/vanilla/client/gui/widget/ScrollPanel.java @@ -26,6 +26,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; @@ -183,7 +184,6 @@ public void render(final GuiGraphics stack, final int mouseX, final int mouseY, this.drawBackground(); final Tesselator tess = Tesselator.getInstance(); - final BufferBuilder worldr = tess.getBuilder(); final double scale = this.client.getWindow().getGuiScale(); RenderSystem.enableScissor((int) (this.left * scale), (int) (this.client.getWindow().getHeight() - (this.bottom * scale)), (int) (this.width * scale), @@ -193,16 +193,16 @@ public void render(final GuiGraphics stack, final int mouseX, final int mouseY, RenderSystem.setShaderTexture(0, Screen.MENU_BACKGROUND); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); final float texScale = 32.0F; - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); - worldr.vertex(this.left, this.bottom, 0.0f).uv(this.left / texScale, (this.bottom + (int) this.scrollDistance) / texScale) - .color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.right, this.bottom, 0.0f).uv(this.right / texScale, (this.bottom + (int) this.scrollDistance) / texScale) - .color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.right, this.top, 0.0f).uv(this.right / texScale, (this.top + (int) this.scrollDistance) / texScale) - .color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.left, this.top, 0.0f).uv(this.left / texScale, (this.top + (int) this.scrollDistance) / texScale) - .color(0x20, 0x20, 0x20, 0xFF).endVertex(); - tess.end(); + BufferBuilder worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); + worldr.addVertex(this.left, this.bottom, 0.0f).setUv(this.left / texScale, (this.bottom + (int) this.scrollDistance) / texScale) + .setColor(0x20, 0x20, 0x20, 0xFF); + worldr.addVertex(this.right, this.bottom, 0.0f).setUv(this.right / texScale, (this.bottom + (int) this.scrollDistance) / texScale) + .setColor(0x20, 0x20, 0x20, 0xFF); + worldr.addVertex(this.right, this.top, 0.0f).setUv(this.right / texScale, (this.top + (int) this.scrollDistance) / texScale) + .setColor(0x20, 0x20, 0x20, 0xFF); + worldr.addVertex(this.left, this.top, 0.0f).setUv(this.left / texScale, (this.top + (int) this.scrollDistance) / texScale) + .setColor(0x20, 0x20, 0x20, 0xFF); + BufferUploader.drawWithShader(worldr.buildOrThrow()); final int baseY = this.top + this.border - (int) this.scrollDistance; this.drawPanel(stack, this.right, baseY, tess, mouseX, mouseY); @@ -220,24 +220,24 @@ public void render(final GuiGraphics stack, final int mouseX, final int mouseY, // RenderSystem.disableTexture(); RenderSystem.setShader(GameRenderer::getPositionColorShader); - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(this.barLeft, this.bottom, 0.0f).color(0x00, 0x00, 0x00, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth, this.bottom, 0.0f).color(0x00, 0x00, 0x00, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth, this.top, 0.0f).color(0x00, 0x00, 0x00, 0xFF).endVertex(); - worldr.vertex(this.barLeft, this.top, 0.0f).color(0x00, 0x00, 0x00, 0xFF).endVertex(); - tess.end(); - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(this.barLeft, barTop + barHeight, 0.0f).color(0x80, 0x80, 0x80, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth, barTop + barHeight, 0.0f).color(0x80, 0x80, 0x80, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth, barTop, 0.0f).color(0x80, 0x80, 0x80, 0xFF).endVertex(); - worldr.vertex(this.barLeft, barTop, 0.0f).color(0x80, 0x80, 0x80, 0xFF).endVertex(); - tess.end(); - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(this.barLeft, barTop + barHeight - 1, 0.0f).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth - 1, barTop + barHeight - 1, 0.0f).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex(); - worldr.vertex(this.barLeft + this.barWidth - 1, barTop, 0.0f).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex(); - worldr.vertex(this.barLeft, barTop, 0.0f).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex(); - tess.end(); + worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(this.barLeft, this.bottom, 0.0f).setColor(0x00, 0x00, 0x00, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth, this.bottom, 0.0f).setColor(0x00, 0x00, 0x00, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth, this.top, 0.0f).setColor(0x00, 0x00, 0x00, 0xFF); + worldr.addVertex(this.barLeft, this.top, 0.0f).setColor(0x00, 0x00, 0x00, 0xFF); + BufferUploader.drawWithShader(worldr.buildOrThrow()); + worldr =tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(this.barLeft, barTop + barHeight, 0.0f).setColor(0x80, 0x80, 0x80, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth, barTop + barHeight, 0.0f).setColor(0x80, 0x80, 0x80, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth, barTop, 0.0f).setColor(0x80, 0x80, 0x80, 0xFF); + worldr.addVertex(this.barLeft, barTop, 0.0f).setColor(0x80, 0x80, 0x80, 0xFF); + BufferUploader.drawWithShader(worldr.buildOrThrow()); + worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(this.barLeft, barTop + barHeight - 1, 0.0f).setColor(0xC0, 0xC0, 0xC0, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth - 1, barTop + barHeight - 1, 0.0f).setColor(0xC0, 0xC0, 0xC0, 0xFF); + worldr.addVertex(this.barLeft + this.barWidth - 1, barTop, 0.0f).setColor(0xC0, 0xC0, 0xC0, 0xFF); + worldr.addVertex(this.barLeft, barTop, 0.0f).setColor(0xC0, 0xC0, 0xC0, 0xFF); + BufferUploader.drawWithShader(worldr.buildOrThrow()); } // RenderSystem.enableTexture(); From 515c245c7ebcc3f2b959960ba3fe4f9a8f6c13b3 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 01:23:30 +0200 Subject: [PATCH 017/226] fix ProjectileUtil --- .../entity/projectile/ProjectileUtil.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/spongepowered/common/entity/projectile/ProjectileUtil.java b/src/main/java/org/spongepowered/common/entity/projectile/ProjectileUtil.java index dbabf23f123..8d73b2dde50 100644 --- a/src/main/java/org/spongepowered/common/entity/projectile/ProjectileUtil.java +++ b/src/main/java/org/spongepowered/common/entity/projectile/ProjectileUtil.java @@ -42,6 +42,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.entity.DispenserBlockEntity; +import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.entity.carrier.Dispenser; import org.spongepowered.api.data.Keys; @@ -177,7 +178,7 @@ static

Optional

doLaunch(final World extent, final P p @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { - final net.minecraft.world.entity.projectile.Arrow arrow = new net.minecraft.world.entity.projectile.Arrow(source.level(), source, new ItemStack(this.item)); + final var arrow = new net.minecraft.world.entity.projectile.Arrow(source.level(), source, new ItemStack(this.item), source.getWeaponItem()); arrow.shoot(source.getXRot(), source.getYRot(), 0.0F, 3.0F, 0); return ProjectileUtil.doLaunch(loc.world(), (Arrow) arrow); } @@ -187,7 +188,7 @@ protected Optional createProjectile(final LivingEntity source, final Serv @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { - final net.minecraft.world.entity.projectile.SpectralArrow arrow = new net.minecraft.world.entity.projectile.SpectralArrow(source.level(), source, new ItemStack(this.item)); + final var arrow = new net.minecraft.world.entity.projectile.SpectralArrow(source.level(), source, new ItemStack(this.item), source.getWeaponItem()); arrow.shoot(source.getXRot(), source.getYRot(), 0.0F, 3.0F, 0); return ProjectileUtil.doLaunch(loc.world(), (SpectralArrow) arrow); } @@ -207,8 +208,7 @@ protected Optional createProjectile(final LivingEntity source, final Server @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { final net.minecraft.world.phys.Vec3 lookVec = source.getViewVector(1); - final net.minecraft.world.entity.projectile.SmallFireball fireball = new net.minecraft.world.entity.projectile.SmallFireball(source.level(), source, - lookVec.x * 4, lookVec.y * 4, lookVec.z * 4); + final var fireball = new net.minecraft.world.entity.projectile.SmallFireball(source.level(), source, lookVec.scale(4)); fireball.setPos(fireball.getX(), fireball.getY() + source.getEyeHeight(), fireball.getZ()); return ProjectileUtil.doLaunch(loc.world(), (SmallFireball) fireball); } @@ -257,8 +257,7 @@ protected Optional createProjectile(final LivingEntity source, final @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { final net.minecraft.world.phys.Vec3 lookVec = source.getViewVector(1); - final LargeFireball fireball = new LargeFireball(source.level(), source, - lookVec.x * 4, lookVec.y * 4, lookVec.z * 4, Constants.Entity.Fireball.DEFAULT_EXPLOSION_RADIUS); + final LargeFireball fireball = new LargeFireball(source.level(), source, lookVec.scale(4), Constants.Entity.Fireball.DEFAULT_EXPLOSION_RADIUS); fireball.setPos(fireball.getX(), fireball.getY() + source.getEyeHeight(), fireball.getZ()); return ProjectileUtil.doLaunch(loc.world(), (ExplosiveFireball) fireball); } @@ -271,14 +270,11 @@ public Optional createProjectile(final ProjectileSource sourc } final DispenserBlockEntity dispenser = (DispenserBlockEntity) source; final Direction enumfacing = DispenserSourceLogic.getFacing(dispenser); - final LivingEntity thrower = new ArmorStand(dispenser.getLevel(), loc.x() + enumfacing.getStepX(), - loc.y() + enumfacing.getStepY(), loc.z() + enumfacing.getStepZ()); - final LargeFireball fireball = new LargeFireball(dispenser.getLevel(), thrower, 0, 0, 0, Constants.Entity.Fireball.DEFAULT_EXPLOSION_RADIUS); + final LivingEntity thrower = new ArmorStand(dispenser.getLevel(), loc.x() + enumfacing.getStepX(), loc.y() + enumfacing.getStepY(), loc.z() + enumfacing.getStepZ()); + final LargeFireball fireball = new LargeFireball(dispenser.getLevel(), thrower, Vec3.ZERO, Constants.Entity.Fireball.DEFAULT_EXPLOSION_RADIUS); // Acceleration is set separately because the constructor applies a random value to it // As for 0.1; it is a reasonable default value - fireball.xPower = enumfacing.getStepX() * 0.1; - fireball.yPower = enumfacing.getStepY() * 0.1; - fireball.zPower = enumfacing.getStepZ() * 0.1; + fireball.accelerationPower = 0.1; return ProjectileUtil.doLaunch(loc.world(), (ExplosiveFireball) fireball); } }); @@ -287,8 +283,7 @@ public Optional createProjectile(final ProjectileSource sourc @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { final net.minecraft.world.phys.Vec3 lookVec = source.getViewVector(1); - final net.minecraft.world.entity.projectile.WitherSkull skull = new net.minecraft.world.entity.projectile.WitherSkull(source.level(), source, - lookVec.x * 4, lookVec.y * 4, lookVec.z * 4); + final var skull = new net.minecraft.world.entity.projectile.WitherSkull(source.level(), source, lookVec.scale(4)); skull.setPos(skull.getX(), skull.getY() + source.getEyeHeight(), skull.getZ()); return ProjectileUtil.doLaunch(loc.world(), (WitherSkull) skull); } @@ -343,8 +338,7 @@ public Optional createProjectile(final ProjectileSource source, @Override protected Optional createProjectile(final LivingEntity source, final ServerLocation loc) { final net.minecraft.world.phys.Vec3 lookVec = source.getViewVector(1); - final net.minecraft.world.entity.projectile.DragonFireball fireball = new net.minecraft.world.entity.projectile.DragonFireball(source.level(), source, - lookVec.x * 4, lookVec.y * 4, lookVec.z * 4); + final var fireball = new net.minecraft.world.entity.projectile.DragonFireball(source.level(), source, lookVec.scale(4)); fireball.setPos(fireball.getX(), fireball.getY() + source.getEyeHeight(), fireball.getZ()); return ProjectileUtil.doLaunch(loc.world(), (DragonFireball) fireball); } From 648a305f862725f5b1a416885fa9b9cec65b91bb Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 02:37:23 +0200 Subject: [PATCH 018/226] fix LivingEntityMixin --- .../mixin/core/world/entity/LivingEntityMixin.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java index 849171a6cc0..7fdf0dac480 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java @@ -44,6 +44,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeMap; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; import org.objectweb.asm.Opcodes; @@ -429,7 +430,7 @@ protected void actuallyHurt(final DamageSource damageSource, final float damage) } @Redirect( - method = "eat(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;", + method = "eat(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/food/FoodProperties;)Lnet/minecraft/world/item/ItemStack;", at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V" @@ -461,8 +462,8 @@ protected void actuallyHurt(final DamageSource damageSource, final float damage) return 0; } - @Inject(method = "broadcastBreakEvent(Lnet/minecraft/world/entity/EquipmentSlot;)V", at = @At("HEAD"), cancellable = true) - private void impl$vanishDoesNotBroadcastBreakEvents(final EquipmentSlot slot, final CallbackInfo ci) { + @Inject(method = "onEquippedItemBroken", at = @At("HEAD"), cancellable = true) + private void impl$vanishDoesNotBroadcastBreakEvents(final Item $$0, final EquipmentSlot $$1, final CallbackInfo ci) { if (this.bridge$vanishState().invisible()) { ci.cancel(); } @@ -493,7 +494,7 @@ protected void actuallyHurt(final DamageSource damageSource, final float damage) final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(stack); final HandType handType = (HandType) (Object) hand; this.impl$addSelfToFrame(frame, snapshot, handType); - final Ticks useDuration = SpongeTicks.ticksOrInfinite(stack.getUseDuration()); + final Ticks useDuration = SpongeTicks.ticksOrInfinite(stack.getUseDuration((LivingEntity) (Object) this)); event = SpongeEventFactory.createUseItemStackEventStart(PhaseTracker.getCauseStackManager().currentCause(), useDuration, useDuration, snapshot); } From 458d932cdbc5d9a0fdf6a451a096dde0d26cec33 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 03:44:38 +0200 Subject: [PATCH 019/226] Bump MC to 1.21-pre2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4b728d745c6..4c20fc55515 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21-pre1 +minecraftVersion=1.21-pre2 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose From 667d99f06e63faa63cebc6c4ea56236ad66d4fe6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 11:28:31 +0200 Subject: [PATCH 020/226] fix ServerPlayerMixin_HealthScale --- .../mixin/core/server/level/ServerPlayerMixin_HealthScale.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin_HealthScale.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin_HealthScale.java index 717bf7212b2..833dcd55865 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin_HealthScale.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin_HealthScale.java @@ -100,7 +100,7 @@ private void updateHealthPriorToArmor(final CallbackInfo ci) { // We need to use the dirty instances to signify that the player needs to have it updated, instead // of modifying the attribute instances themselves, we bypass other potentially detrimental logic // that would otherwise break the actual health scaling. - final Set dirtyInstances = this.shadow$getAttributes().getDirtyAttributes(); + final Set dirtyInstances = this.shadow$getAttributes().getAttributesToUpdate(); this.bridge$injectScaledHealth(dirtyInstances); // Send the new information to the client. From 8f282bbf223e52af6eaf51122230d1cb53e1c81e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 12:07:39 +0200 Subject: [PATCH 021/226] fix multiworld enabled --- .../minecraft/server/MinecraftServerMixin_API.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java index 1f2070c6da1..7d149e1aebe 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java @@ -40,6 +40,7 @@ import net.minecraft.server.ServerScoreboard; import net.minecraft.server.Services; import net.minecraft.server.WorldStem; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListenerFactory; import net.minecraft.server.packs.repository.PackRepository; @@ -93,6 +94,7 @@ import org.spongepowered.common.scheduler.ServerScheduler; import org.spongepowered.common.user.SpongeUserManager; import org.spongepowered.common.util.UsernameCache; +import org.spongepowered.common.world.server.SpongeWorldManager; import org.spongepowered.common.world.storage.SpongeChunkLayout; import org.spongepowered.common.world.storage.SpongePlayerDataManager; import org.spongepowered.common.world.teleport.SpongeTeleportHelper; @@ -130,7 +132,6 @@ public abstract class MinecraftServerMixin_API implements SpongeServer, SpongeRe @Shadow public abstract boolean shadow$isCommandBlockEnabled(); @Shadow public abstract boolean shadow$isSpawningMonsters(); @Shadow public abstract boolean shadow$isSpawningAnimals(); - @Shadow public abstract boolean shadow$isNetherEnabled(); @Shadow public abstract Commands shadow$getCommands(); @Shadow public abstract PackRepository shadow$getPackRepository(); @Shadow public abstract net.minecraft.server.packs.resources.ResourceManager shadow$getResourceManager(); @@ -142,6 +143,10 @@ public abstract class MinecraftServerMixin_API implements SpongeServer, SpongeRe @Shadow public abstract RegistryAccess.Frozen registryAccess(); + @Shadow public abstract boolean repliesToStatus(); + + @Shadow public abstract boolean isSingleplayer(); + private Iterable audiences; private ServerScheduler api$scheduler; private SpongeTeleportHelper api$teleportHelper; @@ -265,9 +270,12 @@ public boolean isAnimalSpawnsEnabled() { return this.shadow$isSpawningAnimals(); } + /** + * See {@link SpongeWorldManager#loadLevel()} + */ @Override public boolean isMultiWorldEnabled() { - return this.shadow$isNetherEnabled(); + return this.isSingleplayer() || ((Object) this instanceof DedicatedServer ds) && ds.getProperties().allowNether; } @Override From d3e9c3c294f49434c8c16fdc9e63ac1ac824f53e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 12:12:42 +0200 Subject: [PATCH 022/226] fix Hanging entity mixins fix HangingEntityMixin fix leashing --- .../BlockAttachedEntityMixin_API.java | 46 +++++++++++ .../decoration/HangingEntityMixin_API.java | 17 +--- .../LeashFenceKnotEntityMixin_API.java | 2 +- .../core/world/entity/LeashableMixin.java | 50 +++++++++++ .../mixin/core/world/entity/MobMixin.java | 33 +++----- .../decoration/BlockAttachedEntityMixin.java | 82 +++++++++++++++++++ .../entity/decoration/HangingEntityMixin.java | 52 +----------- src/mixins/resources/mixins.sponge.api.json | 1 + src/mixins/resources/mixins.sponge.core.json | 2 + 9 files changed, 194 insertions(+), 91 deletions(-) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/BlockAttachedEntityMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LeashableMixin.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/BlockAttachedEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/BlockAttachedEntityMixin_API.java new file mode 100644 index 00000000000..3759f1fdc78 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/BlockAttachedEntityMixin_API.java @@ -0,0 +1,46 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.decoration; + +import net.minecraft.world.entity.decoration.BlockAttachedEntity; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.entity.hanging.Hanging; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.mixin.api.minecraft.world.entity.EntityMixin_API; + +import java.util.Set; + +@Mixin(BlockAttachedEntity.class) +public abstract class BlockAttachedEntityMixin_API extends EntityMixin_API implements Hanging { + @Override + protected Set> api$getVanillaValues() { + final Set> values = super.api$getVanillaValues(); + + values.add(this.requireValue(Keys.DIRECTION).asImmutable()); + + return values; + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/HangingEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/HangingEntityMixin_API.java index 8a2ee63dd67..8fea8f4642f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/HangingEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/HangingEntityMixin_API.java @@ -25,24 +25,9 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.decoration; import net.minecraft.world.entity.decoration.HangingEntity; -import org.spongepowered.api.data.Keys; -import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.hanging.Hanging; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.mixin.api.minecraft.world.entity.EntityMixin_API; - -import java.util.Set; @Mixin(HangingEntity.class) -public abstract class HangingEntityMixin_API extends EntityMixin_API implements Hanging { - - @Override - protected Set> api$getVanillaValues() { - final Set> values = super.api$getVanillaValues(); - - values.add(this.requireValue(Keys.DIRECTION).asImmutable()); - - return values; - } +public abstract class HangingEntityMixin_API extends BlockAttachedEntityMixin_API { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/LeashFenceKnotEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/LeashFenceKnotEntityMixin_API.java index 10ede33fb39..1a9282891db 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/LeashFenceKnotEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/LeashFenceKnotEntityMixin_API.java @@ -29,6 +29,6 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(LeashFenceKnotEntity.class) -public abstract class LeashFenceKnotEntityMixin_API extends HangingEntityMixin_API implements LeashKnot { +public abstract class LeashFenceKnotEntityMixin_API extends BlockAttachedEntityMixin_API implements LeashKnot { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LeashableMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LeashableMixin.java new file mode 100644 index 00000000000..b0d13ae0a35 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LeashableMixin.java @@ -0,0 +1,50 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.entity; + +import net.minecraft.world.entity.Leashable; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Leashable.class) +public interface LeashableMixin { + + @Inject(method = "setLeashedTo(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity;Z)V", at = @At("HEAD"), cancellable = true) + private static void impl$onSetLeashedTo(final E $$0, final net.minecraft.world.entity.Entity $$1, final boolean $$2, final CallbackInfo ci) { + if (!$$0.level().isClientSide) { + final Cause currentCause = Sponge.server().causeStackManager().currentCause(); + if (Sponge.eventManager().post(SpongeEventFactory.createLeashEntityEvent(currentCause, (Entity) $$0))) { + ci.cancel(); + } + } + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java index 1b21c0b81c0..850ec6f5dd8 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java @@ -26,6 +26,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.Attributes; @@ -34,13 +35,10 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.Nullable; -import org.objectweb.asm.Opcodes; -import org.spongepowered.api.Sponge; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.ai.goal.GoalExecutorTypes; import org.spongepowered.api.entity.living.Agent; import org.spongepowered.api.entity.living.Living; -import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.cause.entity.damage.DamageFunction; @@ -75,13 +73,11 @@ public abstract class MobMixin extends LivingEntityMixin { @Shadow @Final protected GoalSelector goalSelector; @Shadow @Final protected GoalSelector targetSelector; @Shadow @Nullable private LivingEntity target; - @Shadow public abstract net.minecraft.world.entity.@Nullable Entity shadow$getLeashHolder(); + @Shadow public abstract Leashable.LeashData shadow$getLeashData(); @Shadow protected abstract void shadow$registerGoals(); // @formatter:on - @Shadow @Final protected float[] handDropChances; - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Mob;registerGoals()V")) private void impl$registerGoals(final Mob this$0) { this.impl$setupGoalSelectors(); @@ -101,18 +97,19 @@ public abstract class MobMixin extends LivingEntityMixin { } } - @Inject(method = "dropLeash", - at = @At(value = "FIELD", - target = "Lnet/minecraft/world/entity/Mob;leashHolder:Lnet/minecraft/world/entity/Entity;", - opcode = Opcodes.PUTFIELD - ), - cancellable = true) + @Inject(method = "dropLeash", cancellable = true, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Leashable;dropLeash(ZZ)V")) private void impl$ThrowUnleashEvent(final boolean sendPacket, final boolean dropLead, final CallbackInfo ci) { if (this.shadow$level().isClientSide) { return; } - final net.minecraft.world.entity.Entity entity = this.shadow$getLeashHolder(); + var leashData = this.shadow$getLeashData(); + if (leashData == null) { + return; + } + + final net.minecraft.world.entity.Entity entity = leashData.leashHolder; final CauseStackManager csm = PhaseTracker.getCauseStackManager(); if (entity == null) { @@ -281,14 +278,4 @@ public boolean doHurtTarget(final net.minecraft.world.entity.Entity targetEntity return result; } - @Inject(method = "setLeashedTo", at = @At("HEAD"), cancellable = true) - private void impl$onSetLeashedTo(final net.minecraft.world.entity.Entity param0, final boolean param1, final CallbackInfo ci) { - if (!this.shadow$level().isClientSide) { - final Cause currentCause = Sponge.server().causeStackManager().currentCause(); - if (Sponge.eventManager().post(SpongeEventFactory.createLeashEntityEvent(currentCause, (Entity) this))) { - ci.cancel(); - } - } - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java new file mode 100644 index 00000000000..fa4982e871b --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java @@ -0,0 +1,82 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.entity.decoration; + +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.decoration.BlockAttachedEntity; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.entity.AttackEntityEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.mixin.core.world.entity.EntityMixin; + +import java.util.ArrayList; + +@Mixin(BlockAttachedEntity.class) +public abstract class BlockAttachedEntityMixin extends EntityMixin { + // @formatter:off + @Shadow public abstract boolean shadow$survives(); + // @formatter:on + + private boolean impl$ignorePhysics = false; // TODO missing data key? + + /** + * Called to update the entity's position/logic. + */ + @Redirect(method = "tick()V", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/BlockAttachedEntity;survives()Z")) + private boolean impl$checkIfOnValidSurfaceAndIgnoresPhysics(final BlockAttachedEntity entityHanging) { + return this.shadow$survives() && !this.impl$ignorePhysics; + } + + @Inject(method = "hurt", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/BlockAttachedEntity;kill()V" + ), + cancellable = true + ) + private void impl$postEventOnAttackEntityFrom(final DamageSource source, final float amount, + final CallbackInfoReturnable cir) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(source); + final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), + (Entity) this, new ArrayList<>(), 0, amount); + SpongeCommon.post(event); + if (event.isCancelled()) { + cir.setReturnValue(true); + } + } + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/HangingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/HangingEntityMixin.java index 9f92286ccce..43163c7fe18 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/HangingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/HangingEntityMixin.java @@ -24,60 +24,10 @@ */ package org.spongepowered.common.mixin.core.world.entity.decoration; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.decoration.HangingEntity; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.AttackEntityEvent; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.mixin.core.world.entity.EntityMixin; - -import java.util.ArrayList; @Mixin(HangingEntity.class) -public abstract class HangingEntityMixin extends EntityMixin { - - // @formatter:off - @Shadow public abstract boolean shadow$survives(); - // @formatter:on - - private boolean impl$ignorePhysics = false; // TODO missing data key? - - /** - * Called to update the entity's position/logic. - */ - @Redirect(method = "tick()V", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/HangingEntity;survives()Z")) - private boolean impl$checkIfOnValidSurfaceAndIgnoresPhysics(final HangingEntity entityHanging) { - return this.shadow$survives() && !this.impl$ignorePhysics; - } - - @Inject(method = "hurt", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/HangingEntity;kill()V" - ), - cancellable = true - ) - private void impl$postEventOnAttackEntityFrom(final DamageSource source, final float amount, - final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(source); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), - (Entity) this, new ArrayList<>(), 0, amount); - SpongeCommon.post(event); - if (event.isCancelled()) { - cir.setReturnValue(true); - } - } - } +public abstract class HangingEntityMixin extends BlockAttachedEntityMixin { } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 0c3cedbfa17..4f7fdf022c9 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -189,6 +189,7 @@ "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManagerMixin_API", "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseMixin_API", "minecraft.world.entity.decoration.ArmorStandMixin_API", + "minecraft.world.entity.decoration.BlockAttachedEntityMixin_API", "minecraft.world.entity.decoration.HangingEntityMixin_API", "minecraft.world.entity.decoration.ItemFrameMixin_API", "minecraft.world.entity.decoration.LeashFenceKnotEntityMixin_API", diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 3732b775564..b4c7cd6e1de 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -113,6 +113,7 @@ "world.entity.EntityTypeMixin", "world.entity.ExperienceOrbMixin", "world.entity.GrieferBridgeMixin", + "world.entity.LeashableMixin", "world.entity.LightningBoltMixin", "world.entity.LivingEntityMixin", "world.entity.LivingEntityMixin_Attack_impl", @@ -133,6 +134,7 @@ "world.entity.animal.horse.AbstractHorseMixin", "world.entity.boss.enderdragon.EndCrystalMixin", "world.entity.decoration.ArmorStandMixin", + "world.entity.decoration.BlockAttachedEntityMixin", "world.entity.decoration.HangingEntityMixin", "world.entity.decoration.ItemFrameMixin", "world.entity.item.ItemEntityMixin", From 674c8161a3462fc08e6e897c96026aa6ef3749ca Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 17:59:19 +0200 Subject: [PATCH 023/226] fix HumanEntity --- .../entity/living/human/HumanEntity.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java b/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java index 288f4864fcd..2d705ac042a 100644 --- a/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java +++ b/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java @@ -42,6 +42,7 @@ import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; @@ -65,7 +66,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.ResolvableProfile; -import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -99,7 +99,7 @@ import java.util.stream.Stream; public final class HumanEntity extends PathfinderMob implements TeamMember, RangedAttackMob { - public static final ResourceKey> KEY = ResourceKey.create(Registries.ENTITY_TYPE, new ResourceLocation("sponge", "human")); + public static final ResourceKey> KEY = ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath("sponge", "human")); public static AttributeSupplier createAttributes() { return Mob.createMobAttributes() @@ -226,11 +226,6 @@ public void setAggressive(final boolean aggressive) { // NOOP, we handle the arm swing manually... } - @Override - public int getPortalWaitTime() { - return 1; - } - @Override protected SoundEvent getSwimSound() { return SoundEvents.PLAYER_SWIM; @@ -429,7 +424,7 @@ private boolean isAliveAndInWorld() { private void respawnOnClient() { this.pushPackets(new ClientboundRemoveEntitiesPacket(this.getId()), this.createPlayerListPacket(EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class))); - this.pushPackets(this.getAddEntityPacket()); + this.pushPackets(this.getAddEntityPacket(new ServerEntity((ServerLevel) this.level(), this, 1, true, packet -> {}))); } /** @@ -508,22 +503,21 @@ public Stream> popQueuedPackets(final @Nullable ServerPlayer player) { @Override public void performRangedAttack(final LivingEntity target, final float distanceFactor) { final ItemStack itemstack = this.getItemInHand(InteractionHand.OFF_HAND); - final Arrow arrow = new Arrow(this.level(), this, itemstack.getItem() instanceof ArrowItem ? itemstack : new ItemStack(Items.ARROW)); + final ItemStack weaponStack = this.getWeaponItem(); + final Arrow arrow = new Arrow(this.level(), this, itemstack.getItem() instanceof ArrowItem ? itemstack : new ItemStack(Items.ARROW), weaponStack); final double d0 = target.getX() - this.getX(); final double d1 = target.getBoundingBox().minY + target.getBbHeight() / 3.0F - arrow.getY(); final double d2 = target.getZ() - this.getZ(); final double d3 = Math.sqrt(d0 * d0 + d2 * d2); arrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, 14 - this.level().getDifficulty().getId() * 4); - arrow.setEnchantmentEffectsFromEntity(this, distanceFactor); - this.playSound(SoundEvents.ARROW_SHOOT, 1.0F, 1.0F / (this.random.nextFloat() * 0.4F + 0.8F)); this.level().addFreshEntity(arrow); } @Override - public Packet getAddEntityPacket() { - final ClientboundAddEntityPacket packet = new ClientboundAddEntityPacket(this); + public Packet getAddEntityPacket(ServerEntity $$0) { + final ClientboundAddEntityPacket packet = new ClientboundAddEntityPacket(this, $$0); ((ClientboundAddEntityPacketAccessor) packet).accessor$type(EntityType.PLAYER); return packet; } From f00ea69be4ff3cc215e7d0df3b7f704d42cca203 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 12:30:14 +0200 Subject: [PATCH 024/226] fix shadow$dropAllDeathLoot --- .../mixin/core/server/level/ServerPlayerMixin.java | 11 ++++++----- .../mixin/core/world/entity/LivingEntityMixin.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index 17add533a95..672221e2228 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -631,7 +631,8 @@ public void die(final DamageSource cause) { } // Sponge end - final boolean flag = this.shadow$level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES) && !event.isMessageCancelled(); + final var level = this.shadow$level(); + final boolean flag = level.getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES) && !event.isMessageCancelled(); if (flag) { final net.minecraft.network.chat.Component component = this.shadow$getCombatTracker().getDeathMessage(); final ClientboundPlayerCombatKillPacket packet = new ClientboundPlayerCombatKillPacket(this.shadow$getId(), component); @@ -666,7 +667,7 @@ public void die(final DamageSource cause) { } this.shadow$removeEntitiesOnShoulder(); - if (this.shadow$level().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { + if (level.getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { this.shadow$tellNeutralMobsThatIDied(); } @@ -674,8 +675,8 @@ public void die(final DamageSource cause) { // during the death update ticks this.impl$keepInventory = event.keepInventory(); - if (!this.shadow$isSpectator()) { - this.shadow$dropAllDeathLoot(cause); + if (!this.shadow$isSpectator() && level instanceof ServerLevel sLevel) { + this.shadow$dropAllDeathLoot(sLevel, cause); } // Sponge End @@ -688,7 +689,7 @@ public void die(final DamageSource cause) { this.shadow$createWitherRose(livingentity); } - this.shadow$level().broadcastEntityEvent((net.minecraft.server.level.ServerPlayer) (Object) this, (byte) 3); + level.broadcastEntityEvent((net.minecraft.server.level.ServerPlayer) (Object) this, (byte) 3); this.shadow$awardStat(Stats.DEATHS); this.shadow$resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_DEATH)); this.shadow$resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java index 7fdf0dac480..60be2feff60 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java @@ -138,7 +138,7 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); @Shadow public abstract ItemStack shadow$getItemInHand(InteractionHand hand); @Shadow protected abstract void shadow$dropEquipment(); - @Shadow protected abstract void shadow$dropAllDeathLoot(DamageSource damageSourceIn); + @Shadow protected abstract void shadow$dropAllDeathLoot(ServerLevel level, DamageSource damageSourceIn); @Shadow @Nullable public abstract LivingEntity shadow$getKillCredit(); @Shadow protected abstract void shadow$createWitherRose(@Nullable LivingEntity p_226298_1_); @Shadow public abstract Collection shadow$getActiveEffects(); From 2924a3323a821c0983afd69a8d2a8ab566802838 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 12:42:59 +0200 Subject: [PATCH 025/226] fix campfire mixins --- .../mixin/core/world/level/block/CampfireBlockMixin.java | 4 ++-- .../world/level/block/entity/CampfireBlockEntityMixin.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java index cf7f36d90a7..9f394ecba60 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java @@ -58,7 +58,7 @@ public abstract class CampfireBlockMixin extends BlockMixin { @Redirect(method = "entityInside", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSources;inFire()Lnet/minecraft/world/damagesource/DamageSource;")) + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSources;campfire()Lnet/minecraft/world/damagesource/DamageSource;")) private DamageSource impl$spongeRedirectForFireDamage(final DamageSources instance, final BlockState blockState, final Level world, final BlockPos blockPos, final Entity entity) { final DamageSource source = instance.inFire(); if (world.isClientSide) { // Short Circuit @@ -71,7 +71,7 @@ public abstract class CampfireBlockMixin extends BlockMixin { return (DamageSource) blockSource; } - @Inject(method = "useItemOn", locals = LocalCapture.CAPTURE_FAILEXCEPTION, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/CampfireBlockEntity;placeFood(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/item/ItemStack;I)Z")) + @Inject(method = "useItemOn", locals = LocalCapture.CAPTURE_FAILEXCEPTION, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/CampfireBlockEntity;placeFood(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;I)Z")) public void impl$placeFood(ItemStack $$0, BlockState $$1, Level $$2, BlockPos $$3, Player $$4, InteractionHand $$5, BlockHitResult $$6, CallbackInfoReturnable cir, BlockEntity tileEntity, CampfireBlockEntity campfire, ItemStack itemStack, Optional> optional) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/CampfireBlockEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/CampfireBlockEntityMixin.java index c85b2a4fd2e..0447f14ca14 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/CampfireBlockEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/CampfireBlockEntityMixin.java @@ -26,11 +26,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; -import net.minecraft.world.Container; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CampfireCookingRecipe; import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.CampfireBlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -100,7 +100,7 @@ public abstract class CampfireBlockEntityMixin implements CampfireBlockEntityBri target = "Lnet/minecraft/world/Containers;dropItemStack(Lnet/minecraft/world/level/Level;DDDLnet/minecraft/world/item/ItemStack;)V")) private static void impl$assembleCampfireResult(final Level level, final BlockPos pos, final BlockState state, final CampfireBlockEntity self, final CallbackInfo ci, final boolean hasChanged, final int i, - final ItemStack itemStack, final Container iInventory, final ItemStack itemStack1) { + final ItemStack itemStack, final SingleRecipeInput recipeInput, final ItemStack itemStack1) { final Cause cause = PhaseTracker.getCauseStackManager().currentCause(); final CampfireBlockEntityMixin mixinSelf = MixinTargetHelper.cast(self); final SlotTransaction transaction = new SlotTransaction(((Campfire) self).inventory().slot(i).get(), ItemStackUtil.snapshotOf(itemStack1), ItemStackSnapshot.empty()); From 7336cf109dd1d27dc1969315b6f15941c891ba04 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 12:48:46 +0200 Subject: [PATCH 026/226] fix DyeColorMixin_API --- .../api/minecraft/world/item/DyeColorMixin_API.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/DyeColorMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/DyeColorMixin_API.java index e1fb945f1f0..8a33c5f55ef 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/DyeColorMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/DyeColorMixin_API.java @@ -26,23 +26,20 @@ import org.spongepowered.api.data.type.DyeColor; import org.spongepowered.api.util.Color; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.math.GenericMath; @Mixin(net.minecraft.world.item.DyeColor.class) public abstract class DyeColorMixin_API implements DyeColor { // @formatter:off - @Shadow public abstract float[] shadow$getTextureDiffuseColors(); + @Shadow @Final private int textureDiffuseColor; + // @formatter:on @Override public Color color() { - float[] components = this.shadow$getTextureDiffuseColors(); - int r = GenericMath.floor(components[0] * 255); - int g = GenericMath.floor(components[1] * 255); - int b = GenericMath.floor(components[2] * 255); - return Color.ofRgb(r, g, b); + return Color.ofRgb(this.textureDiffuseColor); } } From c4e013166fd10516794c6a490f9c304ca0835451 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 14:33:41 +0200 Subject: [PATCH 027/226] fix disconnect --- .../common/mixin/core/network/ConnectionMixin.java | 2 +- .../server/network/ServerStatusPacketListenerImplMixin.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java index 77419f63755..f570dc049cc 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java @@ -209,7 +209,7 @@ public void accept(final Connection connection) { } } - @Inject(method = "disconnect", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;awaitUninterruptibly()Lio/netty/channel/ChannelFuture;"), cancellable = true) + @Inject(method = "disconnect(Lnet/minecraft/network/DisconnectionDetails;)V", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;awaitUninterruptibly()Lio/netty/channel/ChannelFuture;"), cancellable = true) private void impl$disconnectAsync(final CallbackInfo ci) { ci.cancel(); //This can cause deadlock within the event loop diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/network/ServerStatusPacketListenerImplMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/network/ServerStatusPacketListenerImplMixin.java index c7a58e5c0ca..1d7c62e6299 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/network/ServerStatusPacketListenerImplMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/network/ServerStatusPacketListenerImplMixin.java @@ -25,6 +25,7 @@ package org.spongepowered.common.mixin.core.server.network; import net.minecraft.network.Connection; +import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket; import net.minecraft.network.protocol.status.ServerStatus; @@ -61,7 +62,7 @@ public void handleStatusRequest(final ServerboundStatusRequestPacket packetIn) { if (response != null) { this.connection.send(new ClientboundStatusResponsePacket(response)); } else { - this.connection.disconnect(null); + this.connection.disconnect(new DisconnectionDetails(null)); } } } From 6451d82c433e72caec8d8252aa41f9049355695a Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 13:26:36 +0200 Subject: [PATCH 028/226] fix EntitySelectorParserMixin_API --- .../arguments/selector/EntitySelectorParserMixin_API.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/commands/arguments/selector/EntitySelectorParserMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/commands/arguments/selector/EntitySelectorParserMixin_API.java index 2ebbd43b490..2de473599c8 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/commands/arguments/selector/EntitySelectorParserMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/commands/arguments/selector/EntitySelectorParserMixin_API.java @@ -98,7 +98,7 @@ public abstract class EntitySelectorParserMixin_API implements Selector.Builder @Shadow @Nullable private Double deltaZ; @Shadow private WrappedMinMaxBounds rotX = WrappedMinMaxBounds.ANY; @Shadow private WrappedMinMaxBounds rotY = WrappedMinMaxBounds.ANY; - @Shadow private Predicate predicate; + @Shadow @Final private List> predicates; @Shadow private boolean currentEntity; @Shadow @Nullable private String playerName; @Shadow private int startPosition; @@ -415,7 +415,7 @@ public abstract class EntitySelectorParserMixin_API implements Selector.Builder this.deltaZ = null; this.rotX = WrappedMinMaxBounds.ANY; this.rotY = WrappedMinMaxBounds.ANY; - this.predicate = x -> true; + this.predicates.clear(); this.currentEntity = false; this.playerName = null; this.startPosition = 0; From 8e131111fc2b8b35e7f7fc5e2bc3453e25ca926e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 14:02:40 +0200 Subject: [PATCH 029/226] JigsawPoolElement waterlogging --- .../pools/StructurePoolElementMixin_API.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/levelgen/structure/pools/StructurePoolElementMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/levelgen/structure/pools/StructurePoolElementMixin_API.java index 1c277ea0257..f516709ee30 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/levelgen/structure/pools/StructurePoolElementMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/levelgen/structure/pools/StructurePoolElementMixin_API.java @@ -34,6 +34,7 @@ import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; +import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.world.generation.structure.jigsaw.JigsawPoolElement; @@ -48,12 +49,9 @@ public abstract class StructurePoolElementMixin_API implements JigsawPoolElement // @formatter:off @Shadow private volatile StructureTemplatePool.@Nullable Projection projection; - - @Shadow public abstract boolean shadow$place(final StructureTemplateManager var1, - final WorldGenLevel var2, final StructureManager var3, - final ChunkGenerator var4, final BlockPos var5, final BlockPos var6, - final Rotation var7, final BoundingBox var8, - final RandomSource var9, final boolean var10); + @Shadow public abstract boolean shadow$place(final StructureTemplateManager var1, final WorldGenLevel var2, final StructureManager var3, + final ChunkGenerator var4, final BlockPos var5, final BlockPos var6, final Rotation var7, final BoundingBox var8, final RandomSource var9, + final LiquidSettings var10, final boolean var11); // @formatter:on @Override @@ -68,9 +66,16 @@ public boolean place(final ServerLocation location) { @Override public boolean place(final ServerLocation location, boolean withStructureBlocks) { + return this.place(location, withStructureBlocks, true); + } + + @Override + public boolean place(final ServerLocation location, final boolean withStructureBlocks, final boolean waterLogging) { final StructureTemplateManager stm = SpongeCommon.server().getStructureManager(); final ServerLevel level = (ServerLevel) location.world(); return this.shadow$place(stm, level, level.structureManager(), level.getChunkSource().getGenerator(), - VecHelper.toBlockPos(location.blockPosition()), BlockPos.ZERO, Rotation.NONE, BoundingBox.infinite(), level.getRandom(), withStructureBlocks); + VecHelper.toBlockPos(location.blockPosition()), BlockPos.ZERO, Rotation.NONE, BoundingBox.infinite(), level.getRandom(), + waterLogging ? LiquidSettings.APPLY_WATERLOGGING : LiquidSettings.IGNORE_WATERLOGGING, + withStructureBlocks); } } From affb9b4ee9558a08b0606c375e301bfa7a88757b Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 15:18:00 +0200 Subject: [PATCH 030/226] fix client --- .../common/mixin/core/client/MinecraftMixin.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/client/MinecraftMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/client/MinecraftMixin.java index 386a1dd6fe0..9bf069259f9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/client/MinecraftMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/client/MinecraftMixin.java @@ -53,10 +53,6 @@ public abstract class MinecraftMixin extends ReentrantBlockableEventLoop Date: Sat, 1 Jun 2024 16:17:12 +0200 Subject: [PATCH 031/226] fix custom payload --- .../org/spongepowered/common/network/channel/ChannelUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/network/channel/ChannelUtils.java b/src/main/java/org/spongepowered/common/network/channel/ChannelUtils.java index 7a26ea1fe71..57514e417a1 100644 --- a/src/main/java/org/spongepowered/common/network/channel/ChannelUtils.java +++ b/src/main/java/org/spongepowered/common/network/channel/ChannelUtils.java @@ -25,6 +25,7 @@ package org.spongepowered.common.network.channel; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import org.spongepowered.api.Sponge; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.util.Constants; @@ -33,7 +34,7 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public final class ChannelUtils { - public static final CustomPacketPayload.Type REGISTER = CustomPacketPayload.createType(Constants.Channels.REGISTER_KEY.toString()); + public static final CustomPacketPayload.Type REGISTER = new CustomPacketPayload.Type<>((ResourceLocation) (Object) Constants.Channels.REGISTER_KEY); public static ArrayList spongeChannelCodecs(final int maxPayloadSize) { ArrayList channels = new ArrayList<>(); From 912d47d34d03e079781f538739dbdaaaedfe7c16 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 16:18:02 +0200 Subject: [PATCH 032/226] catch mixin errors in packet handling that would otherwise silently ignored --- .../common/mixin/core/network/ConnectionMixin.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java index f570dc049cc..77b90b76770 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java @@ -225,6 +225,17 @@ public void accept(final Connection connection) { } } + @Redirect(method = "genericsFtw", at = @At(value = "INVOKE", + target = "Lnet/minecraft/network/protocol/Packet;handle(Lnet/minecraft/network/PacketListener;)V")) + private static void impl$logPacketError(Packet $$0, PacketListener $$1) { + try { + $$0.handle((T)$$1); + } catch (ExceptionInInitializerError e) { + SpongeCommon.logger().error("Error handling packet " + $$0.getClass(), e); + throw e; + } + } + @Inject(method = "exceptionCaught", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/Connection;disconnect(Lnet/minecraft/network/chat/Component;)V")) private void impl$onExceptionDisconnect(final ChannelHandlerContext $$0, final Throwable $$1, final CallbackInfo ci) { SpongeCommon.logger().error("Disconnected due to error", $$1); From 6d8693b8fa78cd4dd4b12a3ed4d046a9a7f64540 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 02:54:05 +0200 Subject: [PATCH 033/226] start fixing chunks --- .../level/chunk/ChunkAccessMixin_API.java | 6 +- .../level/chunk/ProtoChunkMixin_API.java | 4 +- .../core/server/level/ChunkMapMixin.java | 48 ++------ .../level/chunk/ChunkSerializerMixin.java | 3 +- .../level/chunk/ChunkStatusTasksMixin.java | 65 +++++++++-- .../level/chunk/status/ChunkStatusMixin.java | 13 ++- .../level/chunk/storage/IOWorkerMixin.java | 2 +- .../server/level/ChunkMapMixin_Tracker.java | 61 +--------- .../level/ChunkStatusTasksMixin_Tracker.java | 104 ++++++++++++++++++ .../storage/ChunkSerializerMixin_Tracker.java | 3 +- .../resources/mixins.sponge.tracker.json | 1 + 11 files changed, 188 insertions(+), 122 deletions(-) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkStatusTasksMixin_Tracker.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ChunkAccessMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ChunkAccessMixin_API.java index 0fe361e5e9a..8d124e6d6b5 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ChunkAccessMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ChunkAccessMixin_API.java @@ -60,7 +60,7 @@ public abstract class ChunkAccessMixin_API

> implements Chunk

, LevelHeightAccessor { // @formatter:off - @Shadow public abstract ChunkStatus shadow$getStatus(); + @Shadow public abstract ChunkStatus shadow$getPersistedStatus(); @Shadow public abstract void shadow$addEntity(net.minecraft.world.entity.Entity entity); @Shadow public abstract void shadow$setInhabitedTime(long var1); @Shadow public abstract long shadow$getInhabitedTime(); @@ -86,12 +86,12 @@ public void addEntity(final Entity entity) { @Override public ChunkState state() { - return (ChunkState) this.shadow$getStatus(); + return (ChunkState) this.shadow$getPersistedStatus(); } @Override public boolean isEmpty() { - return this.shadow$getStatus() == ChunkStatus.EMPTY; + return this.shadow$getPersistedStatus() == ChunkStatus.EMPTY; } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ProtoChunkMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ProtoChunkMixin_API.java index ebc6e4ad0df..128c8e825f3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ProtoChunkMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/chunk/ProtoChunkMixin_API.java @@ -77,6 +77,8 @@ public abstract class ProtoChunkMixin_API extends ChunkAccess implements Generat @Shadow public abstract void shadow$setBlockEntity(final net.minecraft.world.level.block.entity.BlockEntity param1); @Shadow public abstract void shadow$removeBlockEntity(final BlockPos param0); @Shadow public abstract Holder shadow$getNoiseBiome(int $$0, int $$1, int $$2); + @Shadow public abstract ChunkStatus shadow$getPersistedStatus(); + //@formatter:on @@ -143,7 +145,7 @@ public boolean removeBlock(final int x, final int y, final int z) { @Override public boolean setBiome(final int x, final int y, final int z, final Biome biome) { - if (!this.getStatus().isOrAfter(ChunkStatus.BIOMES) && (this.belowZeroRetrogen == null || !this.belowZeroRetrogen.targetStatus().isOrAfter(ChunkStatus.BIOMES))) { + if (!this.shadow$getPersistedStatus().isOrAfter(ChunkStatus.BIOMES) && (this.belowZeroRetrogen == null || !this.belowZeroRetrogen.targetStatus().isOrAfter(ChunkStatus.BIOMES))) { throw new IllegalStateException("Asking for biomes before we have biomes"); } return VolumeStreamUtils.setBiomeOnNativeChunk(x, y, z, biome, () -> this.getSection(this.getSectionIndex(y)), () -> {}); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java index 8d4c5712540..60d98d8919b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java @@ -124,7 +124,7 @@ public abstract class ChunkMapMixin implements ChunkMapBridge { return chunkManager.write(pos, compound); } - @Redirect(method = "lambda$scheduleUnload$16", + @Redirect(method = "lambda$scheduleUnload$12", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;unload(Lnet/minecraft/world/level/chunk/LevelChunk;)V"), slice = @Slice( from = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkMap;save(Lnet/minecraft/world/level/chunk/ChunkAccess;)Z") @@ -173,51 +173,21 @@ public abstract class ChunkMapMixin implements ChunkMapBridge { } } - @Redirect(method = "lambda$protoChunkToFullChunk$35", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setLoaded(Z)V"), - slice = @Slice( - from = @At(value = "INVOKE", remap = false, target = "Lit/unimi/dsi/fastutil/longs/LongSet;add(J)Z"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;registerAllBlockEntitiesAfterLevelLoad()V") - ) - ) - private void impl$onLoad(final LevelChunk levelChunk, final boolean loaded) { - levelChunk.setLoaded(true); - final Vector3i chunkPos = VecHelper.toVector3i(levelChunk.getPos()); - if (ShouldFire.CHUNK_EVENT_BLOCKS_LOAD) { - final ChunkEvent.Blocks.Load loadEvent = SpongeEventFactory.createChunkEventBlocksLoad(PhaseTracker.getInstance().currentCause(), - ((BlockChunk) levelChunk), chunkPos, (ResourceKey) (Object) this.level.dimension().location()); - SpongeCommon.post(loadEvent); - } - - for (final Direction dir : Constants.Chunk.CARDINAL_DIRECTIONS) { - final Vector3i neighborPos = chunkPos.add(dir.asBlockOffset()); - ChunkAccess neighbor = this.level.getChunk(neighborPos.x(), neighborPos.z(), ChunkStatus.EMPTY, false); - if (neighbor instanceof ImposterProtoChunk) { - neighbor = ((ImposterProtoChunk) neighbor).getWrapped(); - } - if (neighbor instanceof LevelChunk) { - final int index = DirectionUtil.directionToIndex(dir); - final int oppositeIndex = DirectionUtil.directionToIndex(dir.opposite()); - ((LevelChunkBridge) levelChunk).bridge$setNeighborChunk(index, (LevelChunk) neighbor); - ((LevelChunkBridge) neighbor).bridge$setNeighborChunk(oppositeIndex, levelChunk); - } - } - } - @Inject(method = "schedule", at = @At("HEAD"), cancellable = true) +// @Inject(method = "schedule", at = @At("HEAD"), cancellable = true) private void impl$onSchedule(final CallbackInfoReturnable>> cir) { if (!((ServerLevelBridge) this.level).bridge$isLoaded()) { cir.setReturnValue(ChunkHolder.UNLOADED_CHUNK_FUTURE); } } - @Redirect(method = "lambda$scheduleChunkGeneration$30", - at = @At(value = "INVOKE", - target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", - remap = false), - slice = @Slice( - from = @At(value = "INVOKE", - target = "Lnet/minecraft/server/level/progress/ChunkProgressListener;onStatusChange(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/status/ChunkStatus;)V"))) +// @Redirect(method = "lambda$scheduleChunkGeneration$30", +// at = @At(value = "INVOKE", +// target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", +// remap = false), +// slice = @Slice( +// from = @At(value = "INVOKE", +// target = "Lnet/minecraft/server/level/progress/ChunkProgressListener;onStatusChange(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/status/ChunkStatus;)V"))) private CompletableFuture> impl$guardForUnloadedChunkOnGenerate(final CompletableFuture instance, final Function> function) { //See ChunkStatusTasksMixin, only applies for when generation is cancelled due to world unload diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkSerializerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkSerializerMixin.java index da219ed8d69..04956c160d1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkSerializerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkSerializerMixin.java @@ -33,6 +33,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.storage.ChunkSerializer; +import net.minecraft.world.level.chunk.storage.RegionStorageInfo; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -56,7 +57,7 @@ public abstract class ChunkSerializerMixin { } @Inject(method = "read", at = @At("RETURN")) - private static void impl$readSpongeChunkData(final ServerLevel level, final PoiManager poi, final ChunkPos pos, final CompoundTag compound, final CallbackInfoReturnable cir) { + private static void impl$readSpongeChunkData(final ServerLevel level, final PoiManager poi, final RegionStorageInfo $$2, final ChunkPos pos, final CompoundTag compound, final CallbackInfoReturnable cir) { if (!(cir.getReturnValue() instanceof ImposterProtoChunk imposter)) { return; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java index 422763c5588..346b44db633 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java @@ -24,21 +24,37 @@ */ package org.spongepowered.common.mixin.core.world.level.chunk; +import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.StaticCache2D; import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ImposterProtoChunk; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatusTasks; -import net.minecraft.world.level.chunk.status.ToFullChunk; +import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.levelgen.blending.Blender; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.world.chunk.ChunkEvent; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.world.chunk.BlockChunk; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge; +import org.spongepowered.common.event.ShouldFire; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.util.Constants; +import org.spongepowered.common.util.DirectionUtil; +import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.level.chunk.SpongeUnloadedChunkException; +import org.spongepowered.math.vector.Vector3i; -import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; @Mixin(ChunkStatusTasks.class) public abstract class ChunkStatusTasksMixin { @@ -62,13 +78,12 @@ public abstract class ChunkStatusTasksMixin { * * See IOWorkerMixin#createOldDataForRegion */ - @Overwrite - static CompletableFuture generateBiomes(final WorldGenContext $$0, final ChunkStatus $$1, final Executor $$2, - final ToFullChunk $$3, final List $$4, final ChunkAccess $$5) { - ServerLevel $$6 = $$0.level(); - WorldGenRegion $$7 = new WorldGenRegion($$6, $$4, $$1, -1); + // TODO update me @Overwrite + private static CompletableFuture FIXME$generateBiomes(final WorldGenContext $$0, final ChunkStep $$1, final StaticCache2D $$2, final ChunkAccess $$3) { + ServerLevel $$4 = $$0.level(); + WorldGenRegion $$5 = new WorldGenRegion($$4, $$2, $$1, $$3); try { //Sponge: Add try - return $$0.generator().createBiomes($$2, $$6.getChunkSource().randomState(), Blender.of($$7), $$6.structureManager().forWorldGenRegion($$7), $$5); + return $$0.generator().createBiomes($$4.getChunkSource().randomState(), Blender.of($$5), $$4.structureManager().forWorldGenRegion($$5), $$3); } catch (final Exception e) { //Sponge start: Add catch if (e.getCause() != SpongeUnloadedChunkException.INSTANCE) { throw e; @@ -77,4 +92,34 @@ static CompletableFuture generateBiomes(final WorldGenContext $$0, return null; } //Sponge end } + + + + @Redirect(method = "lambda$full$2", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setLoaded(Z)V") + ) + private static void impl$onLoad(final LevelChunk levelChunk, final boolean loaded) { + levelChunk.setLoaded(true); + final Vector3i chunkPos = VecHelper.toVector3i(levelChunk.getPos()); + if (ShouldFire.CHUNK_EVENT_BLOCKS_LOAD) { + final ChunkEvent.Blocks.Load loadEvent = SpongeEventFactory.createChunkEventBlocksLoad(PhaseTracker.getInstance().currentCause(), + ((BlockChunk) levelChunk), chunkPos, (ResourceKey) (Object) levelChunk.getLevel().dimension().location()); + SpongeCommon.post(loadEvent); + } + + for (final Direction dir : Constants.Chunk.CARDINAL_DIRECTIONS) { + final Vector3i neighborPos = chunkPos.add(dir.asBlockOffset()); + ChunkAccess neighbor = levelChunk.getLevel().getChunk(neighborPos.x(), neighborPos.z(), ChunkStatus.EMPTY, false); + if (neighbor instanceof ImposterProtoChunk) { + neighbor = ((ImposterProtoChunk) neighbor).getWrapped(); + } + if (neighbor instanceof LevelChunk) { + final int index = DirectionUtil.directionToIndex(dir); + final int oppositeIndex = DirectionUtil.directionToIndex(dir.opposite()); + ((LevelChunkBridge) levelChunk).bridge$setNeighborChunk(index, (LevelChunk) neighbor); + ((LevelChunkBridge) neighbor).bridge$setNeighborChunk(oppositeIndex, levelChunk); + } + } + } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java index c30b08c760a..0abf9cf4675 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java @@ -37,12 +37,13 @@ @Mixin(ChunkStatus.class) public abstract class ChunkStatusMixin { - @Redirect(method = "generate", at = @At(value = "INVOKE", - target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", - remap = false), - slice = @Slice( - from = @At(value = "INVOKE", - target = "Lnet/minecraft/world/level/chunk/status/ChunkStatus$GenerationTask;doWork(Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStatus;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/chunk/status/ToFullChunk;Ljava/util/List;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;"))) + // TODO update me +// @Redirect(method = "generate", at = @At(value = "INVOKE", +// target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", +// remap = false), +// slice = @Slice( +// from = @At(value = "INVOKE", +// target = "Lnet/minecraft/world/level/chunk/status/ChunkStatus$GenerationTask;doWork(Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStatus;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/chunk/status/ToFullChunk;Ljava/util/List;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;"))) private CompletableFuture impl$guardForUnloadedChunkOnGenerate(final CompletableFuture instance, final Function function) { //See ChunkStatusTasksMixin, only applies for when generation is cancelled due to world unload diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java index e94a7e7fddf..e679c81c3af 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java @@ -119,7 +119,7 @@ else if (this.impl$type == SpongeIOWorkerType.ENTITY) { * the task directly instead of indirectly from the background executor * and not blocking inside of it. */ - @Overwrite +// TODO update me @Overwrite private CompletableFuture createOldDataForRegion(final int x, final int z) { //The impl$submitTaskCancellable is related to another fix for a separate deadlock case. //The returned future is used inside the isOldChunkAround which tries to wait for the diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkMapMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkMapMixin_Tracker.java index 26cbcab7ebf..d868c48c8f8 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkMapMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkMapMixin_Tracker.java @@ -24,11 +24,9 @@ */ package org.spongepowered.common.mixin.tracker.server.level; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import org.apache.logging.log4j.Level; import org.checkerframework.checker.nullness.qual.NonNull; @@ -36,13 +34,9 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.applaunch.config.core.SpongeConfigs; -import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhasePrinter; import org.spongepowered.common.event.tracking.PhaseTracker; @@ -66,7 +60,7 @@ public abstract class ChunkMapMixin_Tracker { return exception; } - @Redirect(method = "lambda$prepareTickingChunk$42", + @Redirect(method = "lambda$prepareTickingChunk$27", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;startTickingChunk(Lnet/minecraft/world/level/chunk/LevelChunk;)V")) private void tracker$wrapUnpackTicks(final ServerLevel level, final LevelChunk chunk) { if (!PhaseTracker.SERVER.onSidedThread()) { @@ -95,57 +89,4 @@ public abstract class ChunkMapMixin_Tracker { } - @Redirect(method = "lambda$protoChunkToFullChunk$35", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V"), - slice = @Slice( - from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setFullStatus(Ljava/util/function/Supplier;)V"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;registerAllBlockEntitiesAfterLevelLoad()V") - ) - ) - private void tracker$startLoad(final LevelChunk chunk) { - chunk.runPostLoad(); - final boolean isFake = ((LevelBridge) chunk.getLevel()).bridge$isFake(); - if (isFake) { - return; - } - if (!PhaseTracker.SERVER.onSidedThread()) { - new PrettyPrinter(60).add("Illegal Async Chunk Load").centre().hr() - .addWrapped("Sponge relies on knowing when chunks are being loaded as chunks add entities" - + " to the parented world for management. These operations are generally not" - + " threadsafe and shouldn't be considered a \"Sponge bug \". Adding/removing" - + " entities from another thread to the world is never ok.") - .add() - .add(" %s : %s", "Chunk Pos", chunk.getPos().toString()) - .add() - .add(new Exception("Async Chunk Load Detected")) - .log(SpongeCommon.logger(), Level.ERROR); - return; - } - if (PhaseTracker.getInstance().getCurrentState() == GenerationPhase.State.CHUNK_REGENERATING_LOAD_EXISTING) { - return; - } - GenerationPhase.State.CHUNK_LOADING.createPhaseContext(PhaseTracker.getInstance()) - .source(chunk) - .world((ServerLevel) chunk.getLevel()) - .chunk(chunk) - .buildAndSwitch(); - } - - @Inject(method = "lambda$protoChunkToFullChunk$35", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;registerAllBlockEntitiesAfterLevelLoad()V", shift = At.Shift.BY, by = 2), - slice = @Slice( - from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V") - ), - require = 1 - ) - private void tracker$endLoad(final ChunkHolder chunkHolder, final ChunkAccess chunk, final CallbackInfoReturnable cir) { - if (!((LevelBridge) this.level).bridge$isFake() && PhaseTracker.SERVER.onSidedThread()) { - if (PhaseTracker.getInstance().getCurrentState() == GenerationPhase.State.CHUNK_REGENERATING_LOAD_EXISTING) { - return; - } - // IF we're not on the main thread, - PhaseTracker.getInstance().getPhaseContext().close(); - } - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkStatusTasksMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkStatusTasksMixin_Tracker.java new file mode 100644 index 00000000000..ea2d4ed8e56 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ChunkStatusTasksMixin_Tracker.java @@ -0,0 +1,104 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.tracker.server.level; + +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatusTasks; +import net.minecraft.world.level.chunk.status.WorldGenContext; +import org.apache.logging.log4j.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.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.world.level.LevelBridge; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.phase.generation.GenerationPhase; +import org.spongepowered.common.util.PrettyPrinter; + + +@Mixin(ChunkStatusTasks.class) +public abstract class ChunkStatusTasksMixin_Tracker { + + @Redirect(method = "lambda$full$2", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setFullStatus(Ljava/util/function/Supplier;)V"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;registerAllBlockEntitiesAfterLevelLoad()V") + ) + ) + private static void tracker$startLoad(final LevelChunk chunk) { + chunk.runPostLoad(); + final boolean isFake = ((LevelBridge) chunk.getLevel()).bridge$isFake(); + if (isFake) { + return; + } + if (!PhaseTracker.SERVER.onSidedThread()) { + new PrettyPrinter(60).add("Illegal Async Chunk Load").centre().hr() + .addWrapped("Sponge relies on knowing when chunks are being loaded as chunks add entities" + + " to the parented world for management. These operations are generally not" + + " threadsafe and shouldn't be considered a \"Sponge bug \". Adding/removing" + + " entities from another thread to the world is never ok.") + .add() + .add(" %s : %s", "Chunk Pos", chunk.getPos().toString()) + .add() + .add(new Exception("Async Chunk Load Detected")) + .log(SpongeCommon.logger(), Level.ERROR); + return; + } + if (PhaseTracker.getInstance().getCurrentState() == GenerationPhase.State.CHUNK_REGENERATING_LOAD_EXISTING) { + return; + } + GenerationPhase.State.CHUNK_LOADING.createPhaseContext(PhaseTracker.getInstance()) + .source(chunk) + .world((ServerLevel) chunk.getLevel()) + .chunk(chunk) + .buildAndSwitch(); + } + + @Inject(method = "lambda$full$2", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;registerAllBlockEntitiesAfterLevelLoad()V", shift = At.Shift.BY, by = 2), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V") + ), + require = 1 + ) + private static void tracker$endLoad(final ChunkAccess $$0x, final WorldGenContext $$1x, final GenerationChunkHolder $$2x, + final CallbackInfoReturnable cir) { + if (!((LevelBridge) $$1x.level()).bridge$isFake() && PhaseTracker.SERVER.onSidedThread()) { + if (PhaseTracker.getInstance().getCurrentState() == GenerationPhase.State.CHUNK_REGENERATING_LOAD_EXISTING) { + return; + } + // IF we're not on the main thread, + PhaseTracker.getInstance().getPhaseContext().close(); + } + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/chunk/storage/ChunkSerializerMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/chunk/storage/ChunkSerializerMixin_Tracker.java index ca37160211e..d33ce42dfdd 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/chunk/storage/ChunkSerializerMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/chunk/storage/ChunkSerializerMixin_Tracker.java @@ -33,6 +33,7 @@ import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.storage.ChunkSerializer; +import net.minecraft.world.level.chunk.storage.RegionStorageInfo; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -82,7 +83,7 @@ public abstract class ChunkSerializerMixin_Tracker { @Redirect(method = "read", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkAccess;setLightCorrect(Z)V")) - private static void impl$readSpongeLevelData(final ChunkAccess chunkAccess, final boolean var1, final ServerLevel param0, final PoiManager param2, final ChunkPos param3, final CompoundTag param4) { + private static void impl$readSpongeLevelData(final ChunkAccess chunkAccess, final boolean var1, final ServerLevel param0, final PoiManager param2, final RegionStorageInfo $$2, final ChunkPos param3, final CompoundTag param4) { if (!(chunkAccess instanceof LevelChunk)) { return; } diff --git a/src/mixins/resources/mixins.sponge.tracker.json b/src/mixins/resources/mixins.sponge.tracker.json index 49622ac84d8..4cc2dc73bf8 100644 --- a/src/mixins/resources/mixins.sponge.tracker.json +++ b/src/mixins/resources/mixins.sponge.tracker.json @@ -13,6 +13,7 @@ "server.TickTaskMixin_Tracker", "server.dedicated.DedicatedServerMixin_Tracker", "server.level.ChunkMapMixin_Tracker", + "server.level.ChunkStatusTasksMixin_Tracker", "server.level.ServerChunkCacheMixin_Tracker", "server.level.ServerLevelMixin_Tracker", "server.level.ServerPlayerGameModeMixin_Tracker", From 0b9fcd965eadd6322dbe401cf2167113b337d6d9 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sat, 1 Jun 2024 17:36:56 +0300 Subject: [PATCH 034/226] Update chunk generation deadlock fix --- .../chunk/SpongeUnloadedChunkException.java | 5 ++ .../core/server/level/ChunkMapMixin.java | 24 +------- .../level/GenerationChunkHolderMixin.java | 49 +++++++++++++++++ .../level/chunk/ChunkStatusTasksMixin.java | 15 ++--- .../level/chunk/status/ChunkStatusMixin.java | 55 ------------------- .../level/chunk/storage/IOWorkerMixin.java | 2 +- src/mixins/resources/mixins.sponge.core.json | 2 +- 7 files changed, 66 insertions(+), 86 deletions(-) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java delete mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java diff --git a/src/main/java/org/spongepowered/common/world/level/chunk/SpongeUnloadedChunkException.java b/src/main/java/org/spongepowered/common/world/level/chunk/SpongeUnloadedChunkException.java index 9a16a17fbd6..e59bdcac7e7 100644 --- a/src/main/java/org/spongepowered/common/world/level/chunk/SpongeUnloadedChunkException.java +++ b/src/main/java/org/spongepowered/common/world/level/chunk/SpongeUnloadedChunkException.java @@ -24,9 +24,14 @@ */ package org.spongepowered.common.world.level.chunk; +import net.minecraft.world.level.chunk.ChunkAccess; + +import java.util.concurrent.CompletableFuture; + public final class SpongeUnloadedChunkException extends Exception { public static final SpongeUnloadedChunkException INSTANCE = new SpongeUnloadedChunkException(); + public static final CompletableFuture INSTANCE_FUTURE = CompletableFuture.failedFuture(SpongeUnloadedChunkException.INSTANCE); private SpongeUnloadedChunkException() { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java index 60d98d8919b..2df47d7beea 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkMapMixin.java @@ -32,9 +32,7 @@ import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ImposterProtoChunk; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.storage.ChunkSerializer; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.event.SpongeEventFactory; @@ -70,7 +68,6 @@ import org.spongepowered.math.vector.Vector3i; import java.util.concurrent.CompletableFuture; -import java.util.function.Function; @Mixin(ChunkMap.class) public abstract class ChunkMapMixin implements ChunkMapBridge { @@ -173,27 +170,10 @@ public abstract class ChunkMapMixin implements ChunkMapBridge { } } - -// @Inject(method = "schedule", at = @At("HEAD"), cancellable = true) - private void impl$onSchedule(final CallbackInfoReturnable>> cir) { + @Inject(method = "applyStep", at = @At("HEAD"), cancellable = true) + private void impl$onApplyStep(final CallbackInfoReturnable>> cir) { if (!((ServerLevelBridge) this.level).bridge$isLoaded()) { cir.setReturnValue(ChunkHolder.UNLOADED_CHUNK_FUTURE); } } - -// @Redirect(method = "lambda$scheduleChunkGeneration$30", -// at = @At(value = "INVOKE", -// target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", -// remap = false), -// slice = @Slice( -// from = @At(value = "INVOKE", -// target = "Lnet/minecraft/server/level/progress/ChunkProgressListener;onStatusChange(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/status/ChunkStatus;)V"))) - private CompletableFuture> impl$guardForUnloadedChunkOnGenerate(final CompletableFuture instance, - final Function> function) { - //See ChunkStatusTasksMixin, only applies for when generation is cancelled due to world unload - if (instance != null) { - return instance.thenApply(function); - } - return ChunkHolder.UNLOADED_CHUNK_FUTURE; - } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java new file mode 100644 index 00000000000..fc7e8b0eb65 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java @@ -0,0 +1,49 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.server.level; + +import net.minecraft.server.level.ChunkResult; +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.status.ChunkStep; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.world.level.chunk.SpongeUnloadedChunkException; + +@Mixin(GenerationChunkHolder.class) +public abstract class GenerationChunkHolderMixin { + + /** + * See IOWorkerMixin#createOldDataForRegion and ChunkStatusTasksMixin#generateBiomes + */ + @Inject(method = "lambda$applyStep$0", at = @At("HEAD"), cancellable = true) + private void impl$guardForUnloadedChunkOnGenerate(final ChunkStep $$0x, final ChunkAccess $$1x, final Throwable $$2x, final CallbackInfoReturnable> cir) { + if ($$2x != null && $$2x.getCause() == SpongeUnloadedChunkException.INSTANCE) { + cir.setReturnValue(GenerationChunkHolder.UNLOADED_CHUNK); + } + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java index 346b44db633..f98f5ee33b9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java @@ -42,6 +42,7 @@ import org.spongepowered.api.util.Direction; import org.spongepowered.api.world.chunk.BlockChunk; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.common.SpongeCommon; @@ -63,6 +64,7 @@ public abstract class ChunkStatusTasksMixin { * @author aromaa - December 17th, 2023 - 1.19.4 * @author aromaa - December 18th, 2023 - Updated to 1.20.2 * @author aromaa - May 14th, 2024 - Updated to 1.20.6 + * @author aromaa - June 1st, 2024 - Updated to 1.21 * @reason Fixes a deadlock when the world is unloading/unloaded. * The Blender#of method calls to the IOWorker#isOldChunkAround which * submits a task to the main thread while blocking the current thread @@ -70,16 +72,15 @@ public abstract class ChunkStatusTasksMixin { * as it no longer responds to further work and causes the thread to block * indefinitely. Fixes this by special casing the IOWorker#isOldChunkAround * to throw a special exception when the IOWorker has finished up its work - * and catches it here to convert it to a ChunkLoadingFailure. + * and catches it here to convert it to a CompletableFuture. * * In previous versions you were able to return ChunkResult here but this - * is no longer the case, so we instead return null here which - * needs to be checking for in ChunkMap. + * is no longer the case. * - * See IOWorkerMixin#createOldDataForRegion + * See IOWorkerMixin#createOldDataForRegion and GenerationChunkHolderMixin#impl$guardForUnloadedChunkOnGenerate */ - // TODO update me @Overwrite - private static CompletableFuture FIXME$generateBiomes(final WorldGenContext $$0, final ChunkStep $$1, final StaticCache2D $$2, final ChunkAccess $$3) { + @Overwrite + static CompletableFuture generateBiomes(final WorldGenContext $$0, final ChunkStep $$1, final StaticCache2D $$2, final ChunkAccess $$3) { ServerLevel $$4 = $$0.level(); WorldGenRegion $$5 = new WorldGenRegion($$4, $$2, $$1, $$3); try { //Sponge: Add try @@ -89,7 +90,7 @@ public abstract class ChunkStatusTasksMixin { throw e; } - return null; + return SpongeUnloadedChunkException.INSTANCE_FUTURE; } //Sponge end } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java deleted file mode 100644 index 0abf9cf4675..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/status/ChunkStatusMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.mixin.core.world.level.chunk.status; - -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; - -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; - -@Mixin(ChunkStatus.class) -public abstract class ChunkStatusMixin { - - // TODO update me -// @Redirect(method = "generate", at = @At(value = "INVOKE", -// target = "Ljava/util/concurrent/CompletableFuture;thenApply(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;", -// remap = false), -// slice = @Slice( -// from = @At(value = "INVOKE", -// target = "Lnet/minecraft/world/level/chunk/status/ChunkStatus$GenerationTask;doWork(Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStatus;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/chunk/status/ToFullChunk;Ljava/util/List;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;"))) - private CompletableFuture impl$guardForUnloadedChunkOnGenerate(final CompletableFuture instance, - final Function function) { - //See ChunkStatusTasksMixin, only applies for when generation is cancelled due to world unload - if (instance != null) { - return instance.thenApply(function); - } - return null; - } -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java index e679c81c3af..e94a7e7fddf 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/IOWorkerMixin.java @@ -119,7 +119,7 @@ else if (this.impl$type == SpongeIOWorkerType.ENTITY) { * the task directly instead of indirectly from the background executor * and not blocking inside of it. */ -// TODO update me @Overwrite + @Overwrite private CompletableFuture createOldDataForRegion(final int x, final int z) { //The impl$submitTaskCancellable is related to another fix for a separate deadlock case. //The returned future is used inside the isOldChunkAround which tries to wait for the diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index b4c7cd6e1de..49c2ca4e607 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -70,6 +70,7 @@ "server.level.ChunkMap_TrackedEntityMixin", "server.level.ChunkMapMixin", "server.level.DistanceManagerMixin", + "server.level.GenerationChunkHolderMixin", "server.level.ServerBossEventMixin", "server.level.ServerChunkCacheMixin", "server.level.ServerEntityMixin", @@ -247,7 +248,6 @@ "world.level.chunk.ChunkSerializerMixin", "world.level.chunk.ChunkStatusTasksMixin", "world.level.chunk.LevelChunkMixin", - "world.level.chunk.status.ChunkStatusMixin", "world.level.chunk.storage.EntityStorageMixin", "world.level.chunk.storage.IOWorkerMixin", "world.level.dimension.DimensionTypeMixin", From 4bcd2f2d3e8d53667d15972db7b1c62b619f6104 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 19:53:40 +0200 Subject: [PATCH 035/226] update Painting generator --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index a6840de5ee0..41c22eb2b78 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -320,7 +320,8 @@ private static List generators(final Context context) { "ArtTypes", "ART_TYPE", context.relativeClass("data.type", "ArtType"), - Registries.PAINTING_VARIANT + Registries.PAINTING_VARIANT, + a -> true, RegistryScope.SERVER ), new RegistryEntriesGenerator<>( "entity.attribute.type", From 225ffe68b39342b36869d9509e95d4908f2f7e7c Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 19:56:03 +0200 Subject: [PATCH 036/226] MC 1.21 Entities --- .../entity/OminousItemSpawnerMixin_API.java | 33 +++++++++++++++++++ .../entity/animal/ArmadilloMixin_API.java | 33 +++++++++++++++++++ .../world/entity/monster/BoggedMixin_API.java | 33 +++++++++++++++++++ .../windcharge/BreezeWindChargeMixin_API.java | 33 +++++++++++++++++++ .../{ => windcharge}/WindChargeMixin_API.java | 3 +- src/mixins/resources/mixins.sponge.api.json | 6 +++- 6 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OminousItemSpawnerMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java rename src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/{ => windcharge}/WindChargeMixin_API.java (92%) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OminousItemSpawnerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OminousItemSpawnerMixin_API.java new file mode 100644 index 00000000000..7995b9f55ec --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OminousItemSpawnerMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.OminousItemSpawner; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.OminousItemSpawner.class) +public abstract class OminousItemSpawnerMixin_API extends EntityMixin_API implements OminousItemSpawner { + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java new file mode 100644 index 00000000000..53417095cf1 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.animal; + +import org.spongepowered.api.entity.living.animal.Armadillo; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.animal.armadillo.Armadillo.class) +public abstract class ArmadilloMixin_API extends AnimalMixin_API implements Armadillo { + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java new file mode 100644 index 00000000000..1adaf8b8328 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; + +import org.spongepowered.api.entity.living.monster.skeleton.Stray; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.monster.Bogged.class) +public abstract class BoggedMixin_API extends AbstractSkeletonMixin_API implements Stray { + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java new file mode 100644 index 00000000000..58cc04fea37 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.windcharge; + +import org.spongepowered.api.entity.projectile.windcharge.BreezeWindCharge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.ProjectileMixin_API; + +@Mixin(net.minecraft.world.entity.projectile.windcharge.BreezeWindCharge.class) +public abstract class BreezeWindChargeMixin_API extends ProjectileMixin_API implements BreezeWindCharge { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/WindChargeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java similarity index 92% rename from src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/WindChargeMixin_API.java rename to src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java index db52daee1f9..92aff8aebd6 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/WindChargeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java @@ -22,10 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile; +package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.windcharge; import org.spongepowered.api.entity.projectile.windcharge.WindCharge; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.AbstractHurtingProjectileMixin_API; @Mixin(net.minecraft.world.entity.projectile.windcharge.WindCharge.class) public abstract class WindChargeMixin_API extends AbstractHurtingProjectileMixin_API implements WindCharge { diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 4f7fdf022c9..e52564e867a 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -108,6 +108,7 @@ "minecraft.world.entity.MarkerMixin_API", "minecraft.world.entity.MobCategoryMixin_API", "minecraft.world.entity.MobMixin_API", + "minecraft.world.entity.OminousItemSpawnerMixin_API", "minecraft.world.entity.PathfinderMobMixin_API", "minecraft.world.entity.TamableAnimalMixin_API", "minecraft.world.entity.ai.attributes.AttributeInstanceMixin_API", @@ -133,6 +134,7 @@ "minecraft.world.entity.animal.AbstractGolemMixin_API", "minecraft.world.entity.animal.AbstractSchoolingFishMixin_API", "minecraft.world.entity.animal.AnimalMixin_API", + "minecraft.world.entity.animal.ArmadilloMixin_API", "minecraft.world.entity.animal.BeeMixin_API", "minecraft.world.entity.animal.CatMixin_API", "minecraft.world.entity.animal.CatVariantMixin_API", @@ -201,6 +203,7 @@ "minecraft.world.entity.monster.AbstractIllagerMixin_API", "minecraft.world.entity.monster.AbstractSkeletonMixin_API", "minecraft.world.entity.monster.BlazeMixin_API", + "minecraft.world.entity.monster.BoggedMixin_API", "minecraft.world.entity.monster.BreezeMixin_API", "minecraft.world.entity.monster.CaveSpiderMixin_API", "minecraft.world.entity.monster.CreeperMixin_API", @@ -274,8 +277,9 @@ "minecraft.world.entity.projectile.ThrownExperienceBottleMixin_API", "minecraft.world.entity.projectile.ThrownPotionMixin_API", "minecraft.world.entity.projectile.ThrownTridentMixin_API", - "minecraft.world.entity.projectile.WindChargeMixin_API", "minecraft.world.entity.projectile.WitherSkullMixin_API", + "minecraft.world.entity.projectile.windcharge.BreezeWindChargeMixin_API", + "minecraft.world.entity.projectile.windcharge.WindChargeMixin_API", "minecraft.world.entity.raid.Raid_RaidStatusMixin_API", "minecraft.world.entity.raid.RaiderMixin_API", "minecraft.world.entity.raid.RaidMixin_API", From b2cb8972250c0e457da6a8987ddc237fce0ca960 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Wed, 5 Jun 2024 23:00:31 +0200 Subject: [PATCH 037/226] Bump MC to 1.21-pre3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4c20fc55515..cc65ed2634c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21-pre2 +minecraftVersion=1.21-pre3 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose From 5f513bd716d63de312e97135f7607f3460c80f7a Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 14:52:13 +0200 Subject: [PATCH 038/226] fix chunk events --- .../core/server/level/ChunkHolderMixin.java | 37 +++-------------- .../level/GenerationChunkHolderMixin.java | 40 +++++++++++++++++++ .../level/chunk/ChunkStatusTasksMixin.java | 2 + 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkHolderMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkHolderMixin.java index 27e1e7c81cf..a58cb5b70d4 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkHolderMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ChunkHolderMixin.java @@ -28,10 +28,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkResult; import net.minecraft.server.level.FullChunkStatus; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ImposterProtoChunk; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.status.ChunkStatus; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.world.chunk.ChunkEvent; @@ -41,10 +38,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; -import org.spongepowered.common.bridge.server.level.ServerLevelBridge; import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.util.VecHelper; @@ -53,37 +47,16 @@ import java.util.concurrent.CompletableFuture; @Mixin(ChunkHolder.class) -abstract class ChunkHolderMixin { +abstract class ChunkHolderMixin extends GenerationChunkHolderMixin { // @formatter:off @Shadow public abstract CompletableFuture> shadow$getEntityTickingChunkFuture(); // @formatter:on - @Inject( - method = "replaceProtoChunk(Lnet/minecraft/world/level/chunk/ImposterProtoChunk;)V", - at = @At("TAIL") - ) - private void impl$throwChunkGeneratedEvent(final ImposterProtoChunk imposter, final CallbackInfo ci) { - if (!ShouldFire.CHUNK_EVENT_GENERATED) { - return; - } - final LevelChunk chunk = imposter.getWrapped(); - final Vector3i chunkPos = VecHelper.toVector3i(chunk.getPos()); - final ChunkEvent.Generated event = SpongeEventFactory.createChunkEventGenerated( - PhaseTracker.getInstance().currentCause(), chunkPos, - (ResourceKey) (Object) chunk.getLevel().dimension().location() - ); - SpongeCommon.post(event); - } - - @Inject(method = "getOrScheduleFuture", at = @At("HEAD"), cancellable = true) - private void impl$onGetOrScheduleFuture(final ChunkStatus $$0, final ChunkMap chunkMap, final CallbackInfoReturnable>> cir) { - if (!((ServerLevelBridge) ((ChunkMapAccessor) chunkMap).accessor$level()).bridge$isLoaded()) { - cir.setReturnValue(ChunkHolder.UNLOADED_CHUNK_FUTURE); - } - } - - @Inject(method = "lambda$scheduleFullChunkPromotion$5", at = @At("TAIL")) + /** + * After onFullChunkStatusChange + */ + @Inject(method = "lambda$scheduleFullChunkPromotion$4", at = @At("TAIL")) private void impl$onScheduleFullChunkPromotion(final ChunkMap $$0x, final FullChunkStatus $$1x, final CallbackInfo ci) { if ($$1x == FullChunkStatus.ENTITY_TICKING && ShouldFire.CHUNK_EVENT_LOAD) { this.shadow$getEntityTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).ifSuccess(chunk -> { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java index fc7e8b0eb65..20809321a9f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/GenerationChunkHolderMixin.java @@ -24,15 +24,33 @@ */ package org.spongepowered.common.mixin.core.server.level; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkResult; import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ImposterProtoChunk; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.world.chunk.ChunkEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; +import org.spongepowered.common.bridge.server.level.ServerLevelBridge; +import org.spongepowered.common.event.ShouldFire; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.level.chunk.SpongeUnloadedChunkException; +import org.spongepowered.math.vector.Vector3i; + +import java.util.concurrent.CompletableFuture; @Mixin(GenerationChunkHolder.class) public abstract class GenerationChunkHolderMixin { @@ -46,4 +64,26 @@ public abstract class GenerationChunkHolderMixin { cir.setReturnValue(GenerationChunkHolder.UNLOADED_CHUNK); } } + + @Inject(method = "replaceProtoChunk(Lnet/minecraft/world/level/chunk/ImposterProtoChunk;)V", at = @At("TAIL")) + private void impl$throwChunkGeneratedEvent(final ImposterProtoChunk imposter, final CallbackInfo ci) { + if (!ShouldFire.CHUNK_EVENT_GENERATED) { + return; + } + final LevelChunk chunk = imposter.getWrapped(); + final Vector3i chunkPos = VecHelper.toVector3i(chunk.getPos()); + final ChunkEvent.Generated event = SpongeEventFactory.createChunkEventGenerated( + PhaseTracker.getInstance().currentCause(), chunkPos, + (ResourceKey) (Object) chunk.getLevel().dimension().location() + ); + SpongeCommon.post(event); + } + + @Inject(method = "scheduleChunkGenerationTask", at = @At("HEAD"), cancellable = true) + private void impl$onGetOrScheduleFuture(final ChunkStatus $$0, final ChunkMap chunkMap, final CallbackInfoReturnable>> cir) { + if (!((ServerLevelBridge) ((ChunkMapAccessor) chunkMap).accessor$level()).bridge$isLoaded()) { + cir.setReturnValue(ChunkHolder.UNLOADED_CHUNK_FUTURE); + } + } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java index f98f5ee33b9..7da27e3cb22 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/ChunkStatusTasksMixin.java @@ -123,4 +123,6 @@ static CompletableFuture generateBiomes(final WorldGenContext $$0, } } + + } From 1bae845e3d637d2475d9cd49bc575a4591dc0605 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 1 Jun 2024 00:23:09 +0200 Subject: [PATCH 039/226] Attack/DamageEntityEvent Rework --- .../world/entity/LivingEntityBridge.java | 2 - .../entity/living/human/HumanEntity.java | 32 +- .../damage/SpongeDamageModifierType.java | 10 + .../registry/loader/SpongeRegistryLoader.java | 5 +- .../common/util/DamageEventUtil.java | 413 +++++++++++----- .../mixin/core/world/entity/EntityMixin.java | 21 - .../core/world/entity/ExperienceOrbMixin.java | 11 + .../core/world/entity/LivingEntityMixin.java | 195 +------- .../entity/LivingEntityMixin_Attack_impl.java | 301 ------------ .../mixin/core/world/entity/MobMixin.java | 83 +--- .../boss/enderdragon/EndCrystalMixin.java | 11 + .../entity/decoration/ArmorStandMixin.java | 174 ++++--- .../decoration/BlockAttachedEntityMixin.java | 31 +- .../entity/decoration/ItemFrameMixin.java | 30 +- .../world/entity/item/ItemEntityMixin.java | 12 + .../player/PlayerMixin_Attack_Impl.java | 428 ---------------- .../entity/projectile/ShulkerBulletMixin.java | 12 + .../entity/vehicle/MinecartTNTMixin.java | 21 +- .../entity/vehicle/VehicleEntityMixin.java | 28 +- .../core/world/level/ExplosionMixin.java | 6 +- src/mixins/resources/mixins.sponge.core.json | 2 - .../entity/LivingEntityMixin_Attack_impl.java | 462 ++++++++++++++++++ .../world/entity/MobMixin_Attack_Impl.java | 77 +++ .../player/PlayerMixin_Attack_Impl.java | 425 ++++++++++++++++ .../resources/mixins.spongevanilla.core.json | 3 + 25 files changed, 1439 insertions(+), 1356 deletions(-) delete mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java delete mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java create mode 100644 vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java create mode 100644 vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java create mode 100644 vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java diff --git a/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java b/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java index 759abbee255..02260b219ad 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/LivingEntityBridge.java @@ -25,13 +25,11 @@ package org.spongepowered.common.bridge.world.entity; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; public interface LivingEntityBridge { - boolean bridge$damageEntity(DamageSource damageSource, float damage); default int bridge$getExperiencePointsOnDeath(LivingEntity entity, ServerLevel $$0, Entity $$1) { return entity.getExperienceReward($$0, $$1); diff --git a/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java b/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java index 2d705ac042a..a38c2d70259 100644 --- a/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java +++ b/src/main/java/org/spongepowered/common/entity/living/human/HumanEntity.java @@ -43,6 +43,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; @@ -300,37 +301,6 @@ protected float tickHeadTurn(final float p_110146_1_, final float p_110146_2_) { return retValue; } - @Override - public boolean doHurtTarget(final Entity entityIn) { - super.doHurtTarget(entityIn); - this.swing(this.getUsedItemHand()); - float f = (float) this.getAttribute(Attributes.ATTACK_DAMAGE).getValue(); - int i = 0; - - f += EnchantmentHelper.getDamageBonus(this.getItemInHand(InteractionHand.MAIN_HAND), this.getType()); - i += EnchantmentHelper.getKnockbackBonus(this); - - final boolean flag = entityIn.hurt(this.damageSources().mobAttack(this), f); - - if (flag) { - if (i > 0) { - entityIn.push(-Mth.sin(this.getYRot() * (float) Math.PI / 180.0F) * i * 0.5F, 0.1D, - Mth.cos(this.getYRot() * (float) Math.PI / 180.0F) * i * 0.5F); - this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); - } - - final int j = EnchantmentHelper.getFireAspect(this); - - if (j > 0) { - entityIn.igniteForSeconds(j * 4); - } - - this.doEnchantDamageEffects(this, entityIn); - } - - return flag; - } - private void setProfileName(final net.minecraft.network.chat.@Nullable Component newName) { final Optional optName = Optional.ofNullable(newName).map(net.minecraft.network.chat.Component::getString); this.fakeProfile = new ResolvableProfile(optName, this.fakeProfile.id(), this.fakeProfile.properties()); diff --git a/src/main/java/org/spongepowered/common/event/cause/entity/damage/SpongeDamageModifierType.java b/src/main/java/org/spongepowered/common/event/cause/entity/damage/SpongeDamageModifierType.java index 754bf317462..f17035514b7 100644 --- a/src/main/java/org/spongepowered/common/event/cause/entity/damage/SpongeDamageModifierType.java +++ b/src/main/java/org/spongepowered/common/event/cause/entity/damage/SpongeDamageModifierType.java @@ -24,7 +24,17 @@ */ package org.spongepowered.common.event.cause.entity.damage; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.event.cause.entity.damage.DamageModifierType; +import org.spongepowered.api.registry.RegistryTypes; public final class SpongeDamageModifierType implements DamageModifierType { + + @Override + public String toString() { + return RegistryTypes.DAMAGE_MODIFIER_TYPE.get().findValueKey(this) + .map(ResourceKey::toString) + .map("DamageModifierType[%s]"::formatted) + .orElse(super.toString()); + } } diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index cb96f1e1b69..07e4d25d1cd 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -239,7 +239,10 @@ public static RegistryLoader damageModifierType() { DamageModifierTypes.OFFENSIVE_POTION_EFFECT, DamageModifierTypes.SHIELD, DamageModifierTypes.SWEEPING, - DamageModifierTypes.WEAPON_ENCHANTMENT + DamageModifierTypes.WEAPON_ENCHANTMENT, + DamageModifierTypes.WEAPON_BONUS, + DamageModifierTypes.ATTACK_STRENGTH, + DamageModifierTypes.FREEZING_BONUS ))); } diff --git a/src/main/java/org/spongepowered/common/util/DamageEventUtil.java b/src/main/java/org/spongepowered/common/util/DamageEventUtil.java index 7759a36ed64..fa8a4779dd5 100644 --- a/src/main/java/org/spongepowered/common/util/DamageEventUtil.java +++ b/src/main/java/org/spongepowered/common/util/DamageEventUtil.java @@ -26,45 +26,51 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.component.DataComponents; -import net.minecraft.tags.DamageTypeTags; +import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.ItemEnchantments; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.phys.AABB; -import org.spongepowered.api.Server; -import org.spongepowered.api.effect.potion.PotionEffect; -import org.spongepowered.api.entity.FallingBlock; +import org.apache.commons.lang3.mutable.MutableFloat; +import org.spongepowered.api.Sponge; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContext; import org.spongepowered.api.event.EventContextKeys; +import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.cause.entity.damage.DamageFunction; import org.spongepowered.api.event.cause.entity.damage.DamageModifier; +import org.spongepowered.api.event.cause.entity.damage.DamageModifierType; import org.spongepowered.api.event.cause.entity.damage.DamageModifierTypes; -import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.event.entity.AttackEntityEvent; +import org.spongepowered.api.event.entity.DamageEntityEvent; +import org.spongepowered.api.registry.DefaultedRegistryReference; +import org.spongepowered.api.util.Tuple; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.common.accessor.world.entity.LivingEntityAccessor; +import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.bridge.CreatorTrackedBridge; import org.spongepowered.common.bridge.world.damagesource.DamageSourceBridge; import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge; +import org.spongepowered.common.event.cause.entity.damage.SpongeDamageSources; +import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.item.util.ItemStackUtil; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.function.DoubleUnaryOperator; @@ -72,99 +78,57 @@ public final class DamageEventUtil { - public static final DoubleUnaryOperator HARD_HAT_FUNCTION = damage -> -(damage - (damage * 0.75F)); - private DamageEventUtil() { } - public static DoubleUnaryOperator createResistanceFunction(final int resistanceAmplifier) { - final int base = (resistanceAmplifier + 1) * 5; - final int modifier = 25 - base; - return damage -> -(damage - (Math.max(((damage * modifier) / 25.0F), 0.0f))); - } @SuppressWarnings("ConstantConditions") - public static Optional createHardHatModifier(final LivingEntity living, final DamageSource damageSource) { - if (damageSource.getDirectEntity() instanceof FallingBlock && !living.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - final DamageModifier modifier = DamageModifier.builder() - // TODO - Event Context Key for Helmet - .cause(Cause.of(EventContext.empty(), ((ItemStack) (Object) living.getItemBySlot(EquipmentSlot.HEAD)).createSnapshot())) - .type(DamageModifierTypes.HARD_HAT) - .build(); - return Optional.of(new DamageFunction(modifier, DamageEventUtil.HARD_HAT_FUNCTION)); - } - return Optional.empty(); + public static DamageFunction createHardHatModifier(final ItemStack headItem, final float multiplier) { + final var snapshot = ItemStackUtil.snapshotOf(headItem); + final var modifier = DamageEventUtil.buildDamageReductionModifier(DamageModifierTypes.HARD_HAT, snapshot); + return new DamageFunction(modifier, damage -> damage * multiplier); } - public static Optional createArmorModifiers(final LivingEntity living, final DamageSource damageSource) { - if (damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) { - return Optional.empty(); - } - - final DoubleUnaryOperator function = incomingDamage -> -(incomingDamage - CombatRules.getDamageAfterAbsorb((float) incomingDamage, damageSource, living.getArmorValue(), (float) living.getAttributeValue(Attributes.ARMOR_TOUGHNESS))); - final DamageFunction armorModifier; - try (final CauseStackManager.StackFrame frame = ((Server) living.getServer()).causeStackManager().pushCauseFrame()){ - frame.pushCause(living); - frame.pushCause(Attributes.ARMOR_TOUGHNESS); - armorModifier = DamageFunction.of(DamageModifier.builder() - .cause(frame.currentCause()) - .type(DamageModifierTypes.ARMOR) - .build(), function); - } + /** + * LivingEntity#getDamageAfterArmorAbsorb + */ + public static DamageFunction createArmorModifiers(final LivingEntity living, final DamageSource damageSource) { + final DoubleUnaryOperator function = dmg -> CombatRules.getDamageAfterAbsorb(living, (float) dmg, + damageSource, living.getArmorValue(), (float) living.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); + final var modifier = DamageEventUtil.buildDamageReductionModifierWithFrame(DamageModifierTypes.ARMOR, living, Attributes.ARMOR_TOUGHNESS); - return Optional.of(armorModifier); + return DamageFunction.of(modifier, function); } - public static Optional createResistanceModifier(final LivingEntity living, final DamageSource damageSource) { - final PotionEffect effect = ((PotionEffect) living.getEffect(MobEffects.DAMAGE_RESISTANCE)); - - if (effect != null && - !damageSource.is(DamageTypeTags.BYPASSES_EFFECTS) && - !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { - return Optional.of(new DamageFunction(DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), effect)) - .type(DamageModifierTypes.DEFENSIVE_POTION_EFFECT) - .build(), DamageEventUtil.createResistanceFunction(effect.amplifier()))); - } - return Optional.empty(); + /** + * LivingEntity#getDamageAfterMagicAbsorb + */ + public static DamageFunction createResistanceModifier(final LivingEntity living) { + final var effect = living.getEffect(MobEffects.DAMAGE_RESISTANCE); + var modifier = DamageEventUtil.buildDamageReductionModifier(DamageModifierTypes.DEFENSIVE_POTION_EFFECT, effect); + return new DamageFunction(modifier, DamageEventUtil.createResistanceFunction(living)); } - public static Optional> createEnchantmentModifiers(final LivingEntity living, final DamageSource damageSource) { - if (damageSource.is(DamageTypeTags.BYPASSES_ENCHANTMENTS)) { - return Optional.empty(); - } - final Iterable inventory = living.getArmorSlots(); - final int damageProtection = EnchantmentHelper.getDamageProtection(inventory, damageSource); - if (damageProtection <= 0) { - return Optional.empty(); - } - final List modifiers = new ArrayList<>(); - final DoubleUnaryOperator enchantmentFunction = incomingDamage -> -(incomingDamage - CombatRules.getDamageAfterMagicAbsorb((float) incomingDamage, damageProtection)); - try (final CauseStackManager.StackFrame frame = ((Server) living.getServer()).causeStackManager().pushCauseFrame()) { - frame.pushCause(living); - final DamageModifier enchantmentModifier = DamageModifier.builder() - .cause(frame.currentCause()) - .type(DamageModifierTypes.ARMOR_ENCHANTMENT) - .build(); - modifiers.add(new DamageFunction(enchantmentModifier, enchantmentFunction)); - } + public static DoubleUnaryOperator createResistanceFunction(final LivingEntity living) { + final var effect = living.getEffect(MobEffects.DAMAGE_RESISTANCE); + final int base = effect == null ? 0 : (effect.getAmplifier() + 1) * 5; + final int modifier = 25 - base; + return damage -> Math.max(((damage * modifier) / 25.0F), 0.0f); + } - return Optional.of(modifiers); + /** + * LivingEntity#getDamageAfterMagicAbsorb + */ + public static DamageFunction createEnchantmentModifiers(final LivingEntity living, final float damageProtection) { + final DoubleUnaryOperator func = damage -> CombatRules.getDamageAfterMagicAbsorb((float) damage, damageProtection); + final var modifier = DamageEventUtil.buildDamageReductionModifierWithFrame(DamageModifierTypes.ARMOR_ENCHANTMENT, living); + return new DamageFunction(modifier, func); } - public static Optional createAbsorptionModifier(final LivingEntity living) { - final float absorptionAmount = living.getAbsorptionAmount(); - if (absorptionAmount > 0) { - final DoubleUnaryOperator function = damage -> - -(Math.max(damage - Math.max(damage - absorptionAmount, 0.0F), 0.0F)); - final DamageModifier modifier = DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), living)) - .type(DamageModifierTypes.ABSORPTION) - .build(); - return Optional.of(new DamageFunction(modifier, function)); - } - return Optional.empty(); + public static DamageFunction createAbsorptionModifier(final LivingEntity living, final float absorptionAmount) { + final var modifier = DamageEventUtil.buildDamageReductionModifier(DamageModifierTypes.ABSORPTION, living); + return new DamageFunction(modifier, damage -> Math.max(damage - absorptionAmount, 0.0F)); } public static ServerLocation findFirstMatchingBlock(final Entity entity, final AABB bb, final Predicate predicate) { @@ -215,68 +179,251 @@ public static void generateCauseFor(final DamageSource damageSource, final Cause frame.pushCause(damageSource); } - public static List createAttackEnchantmentFunction(final net.minecraft.world.item.ItemStack heldItem, - final EntityType entityType, final float attackStrength) { - if (heldItem.isEmpty()) { - return Collections.emptyList(); - } - - final ItemEnchantments enchantmentCompounds = heldItem.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); - if (enchantmentCompounds.isEmpty()) { - return Collections.emptyList(); - } - - final List damageModifierFunctions = new ArrayList<>(); - final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(heldItem); + /** + * Mirrors {@link EnchantmentHelper#modifyDamage} + */ + public static List createAttackEnchantmentFunction(final ItemStack weapon, final Entity entity, final DamageSource damageSource) { + final var enchantments = weapon.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); + final var snapshot = ItemStackUtil.snapshotOf(weapon); - for (final var entry : enchantmentCompounds.entrySet()) { + return enchantments.entrySet().stream().map(entry -> { final var enchantment = entry.getKey().value(); final int level = entry.getIntValue(); - final DamageModifier enchantmentModifier = DamageModifier.builder() - .type(DamageModifierTypes.WEAPON_ENCHANTMENT) - .cause(Cause.of(EventContext.empty(), snapshot, enchantment)) - .build(); - final DoubleUnaryOperator enchantmentFunction = (damage) -> { - double totalDamage = 0; - totalDamage += enchantment.getDamageBonus(level, entityType) * attackStrength; - return totalDamage; - }; - damageModifierFunctions.add(new DamageFunction(enchantmentModifier, enchantmentFunction)); - } + final var modifier = DamageEventUtil.buildAttackEnchantmentModifier(DamageModifierTypes.WEAPON_ENCHANTMENT, snapshot, enchantment); + + return new DamageFunction(modifier, damage -> + DamageEventUtil.enchantmentDamageFunction(weapon, entity, damageSource, damage, enchantment, level)); + }).toList(); + } - return damageModifierFunctions; + public static DamageFunction provideSeparateEnchantmentFromBaseDamageFunction(final float baseDamage, final ItemStack weapon) { + final var modifier = DamageEventUtil.buildAttackEnchantmentModifier(DamageModifierTypes.WEAPON_ENCHANTMENT, ItemStackUtil.snapshotOf(weapon)); + return new DamageFunction(modifier, damage -> damage - baseDamage); } - public static DamageFunction provideCriticalAttackTuple(final Player player, double criticalModifier) { - final DamageModifier modifier = DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), player)) - .type(DamageModifierTypes.CRITICAL_HIT) - .build(); + public static DamageFunction provideCooldownEnchantmentStrengthFunction(final ItemStack weapon, final float attackStrength) { + final var snapshot = ItemStackUtil.snapshotOf(weapon); + final var modifier = DamageEventUtil.buildAttackEnchantmentModifier(DamageModifierTypes.ATTACK_STRENGTH, snapshot); + return new DamageFunction(modifier, damage -> damage * attackStrength); + } + + private static double enchantmentDamageFunction(final ItemStack weapon, final Entity entity, + final DamageSource damageSource, final double damage, final Enchantment enchantment, final int level) { + var totalDamage = new MutableFloat(damage); + enchantment.modifyDamage((ServerLevel) entity.level(), level, weapon, entity, damageSource, totalDamage); + return totalDamage.doubleValue(); + } + + public static DamageFunction provideCriticalAttackFunction(final Player player, double criticalModifier) { + final var modifier = DamageEventUtil.buildAttackDamageModifier(DamageModifierTypes.CRITICAL_HIT, player); final DoubleUnaryOperator function = (damage) -> damage * criticalModifier; return new DamageFunction(modifier, function); } public static DamageFunction provideCooldownAttackStrengthFunction(final Player player, final float attackStrength) { - final DamageModifier modifier = DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), player)) - .type(DamageModifierTypes.ATTACK_COOLDOWN) - .build(); - // The formula is as follows: - // Since damage needs to be "multiplied", this needs to basically add negative damage but re-add the "reduced" damage. - final DoubleUnaryOperator function = (damage) -> -damage + (damage * (0.2F + attackStrength * attackStrength * 0.8F)); + final var modifier = DamageEventUtil.buildAttackDamageModifier(DamageModifierTypes.ATTACK_STRENGTH, player); + final DoubleUnaryOperator function = (damage) -> damage * (0.2F + attackStrength * attackStrength * 0.8F); + return new DamageFunction(modifier, function); + } + + public static DamageFunction provideWeaponAttackDamageBonusFunction(final Entity targetEntity, final ItemStack weapon, final DamageSource damageSource) { + final var modifier = DamageEventUtil.buildAttackDamageModifier(DamageModifierTypes.WEAPON_BONUS, targetEntity); + final DoubleUnaryOperator function = (damage) -> damage + weapon.getItem().getAttackDamageBonus(targetEntity, (float) damage, damageSource); return new DamageFunction(modifier, function); } + public static DamageFunction provideSweepingDamageRatioFunction(final ItemStack held, final Player player, final double attackDamage) { + final var modifier = DamageEventUtil.buildAttackEnchantmentModifier(DamageModifierTypes.SWEEPING, ItemStackUtil.snapshotOf(held)); + return DamageFunction.of(modifier, damage -> damage + player.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * attackDamage); + } + @SuppressWarnings("ConstantConditions") - public static Optional createShieldFunction(final LivingEntity entity, final DamageSource source, final float amount) { - if (entity.isBlocking() && amount > 0.0 && ((LivingEntityAccessor) entity).invoker$isDamageSourceBlocked(source)) { - final DamageModifier modifier = DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), entity, ((ItemStack) (Object) entity.getUseItem()).createSnapshot())) - .type(DamageModifierTypes.SHIELD) - .build(); - return Optional.of(new DamageFunction(modifier, (damage) -> -damage)); + public static DamageFunction createShieldFunction(final LivingEntity entity) { + final var snapshot = ItemStackUtil.snapshotOf(entity.getUseItem()); + final var modifier = DamageEventUtil.buildDamageReductionModifier(DamageModifierTypes.SHIELD, entity, snapshot); + return new DamageFunction(modifier, (damage) -> 0); + } + + public static DamageFunction createFreezingBonus(final LivingEntity entity, final DamageSource damageSource, float multiplier) { + final var modifier = DamageEventUtil.buildDamageReductionModifier(DamageModifierTypes.FREEZING_BONUS, damageSource, entity); + return new DamageFunction(modifier, (damage) -> damage * multiplier); + } + + private static DamageModifier buildDamageReductionModifierWithFrame(final DefaultedRegistryReference modifierType, Object... causes) { + try (final CauseStackManager.StackFrame frame = Sponge.server().causeStackManager().pushCauseFrame()) { + for (final Object cause : causes) { + frame.pushCause(cause); + } + return DamageModifier.builder().damageReductionGroup() + .cause(frame.currentCause()).type(modifierType).build(); + } + } + + private static DamageModifier buildAttackDamageModifier(final DefaultedRegistryReference modifierType, Object... causes) { + return DamageModifier.builder().attackDamageGroup() + .cause(Cause.of(EventContext.empty(), Arrays.asList(causes))).type(modifierType).build(); + } + + private static DamageModifier buildAttackEnchantmentModifier(final DefaultedRegistryReference modifierType, Object... causes) { + return DamageModifier.builder().attackEnchantmentGroup() + .cause(Cause.of(EventContext.empty(), Arrays.asList(causes))).type(modifierType).build(); + } + + private static DamageModifier buildDamageReductionModifier(final DefaultedRegistryReference modifierType, Object... causes) { + return DamageModifier.builder().damageReductionGroup() + .cause(Cause.of(EventContext.empty(), Arrays.asList(causes))).type(modifierType).build(); + } + + public static AttackEntityEvent callPlayerAttackEntityEvent(final Attack attack, final float knockbackModifier) { + final boolean isMainthread = !attack.sourceEntity().level().isClientSide; + if (isMainthread) { + PhaseTracker.getInstance().pushCause(attack.dmgSource()); + } + final var currentCause = isMainthread + ? PhaseTracker.getInstance().currentCause() + : Cause.of(EventContext.empty(), attack.dmgSource()); + final var event = attack.postEvent(knockbackModifier, currentCause); + if (isMainthread) { + PhaseTracker.getInstance().popCause(); + } + return event; + } + + /** + * {@link Mob#doHurtTarget} + */ + public static AttackEntityEvent callMobAttackEvent(final Attack attack, final float knockbackModifier) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(attack.dmgSource()); + return attack.postEvent(knockbackModifier, frame.currentCause()); + } + } + + /** + * For {@link Entity#hurt} overrides without super call: + * {@link net.minecraft.world.entity.decoration.BlockAttachedEntity#hurt} + * {@link net.minecraft.world.entity.vehicle.VehicleEntity#hurt} + * {@link net.minecraft.world.entity.decoration.ItemFrame#hurt} + * {@link net.minecraft.world.entity.vehicle.MinecartTNT#hurt} + * {@link net.minecraft.world.entity.boss.enderdragon.EndCrystal#hurt} + * {@link net.minecraft.world.entity.projectile.ShulkerBullet#hurt} + * {@link net.minecraft.world.entity.ExperienceOrb#hurt} + * {@link net.minecraft.world.entity.item.ItemEntity#hurt} + */ + public static AttackEntityEvent callOtherAttackEvent( + final Entity targetEntity, + final DamageSource damageSource, + final double damage) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(damageSource); + final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) targetEntity, new ArrayList<>(), 0, damage); + SpongeCommon.post(event); + return event; } - return Optional.empty(); + } + + public static DamageEventResult callLivingDamageEntityEvent(final Hurt hurt, final ActuallyHurt actuallyHurt) { + + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + DamageEventUtil.generateCauseFor(actuallyHurt.dmgSource(), frame); + + final List originalFunctions = new ArrayList<>(); + originalFunctions.addAll(hurt.functions()); + originalFunctions.addAll(actuallyHurt.functions()); + final var event = SpongeEventFactory.createDamageEntityEvent(frame.currentCause(), + (org.spongepowered.api.entity.Entity) actuallyHurt.entity(), + originalFunctions, + actuallyHurt.baseDamage()); + + if (actuallyHurt.dmgSource() != SpongeDamageSources.IGNORED) { // Basically, don't throw an event if it's our own damage source + SpongeCommon.post(event); + } + + return new DamageEventResult(event, + actuallyHurt.dmgSource(), + DamageEventUtil.findDamageBefore(event, DamageModifierTypes.SHIELD), + DamageEventUtil.findDamageDifference(event, DamageModifierTypes.SHIELD), + DamageEventUtil.findDamageBefore(event, DamageModifierTypes.HARD_HAT), + DamageEventUtil.findDamageBefore(event, DamageModifierTypes.ARMOR), + DamageEventUtil.findDamageDifference(event, DamageModifierTypes.DEFENSIVE_POTION_EFFECT), // TODO Math.max(0, resisted)? + DamageEventUtil.findDamageDifference(event, DamageModifierTypes.ABSORPTION) + ); + } + + } + + private static Optional findDamageDifference(DamageEntityEvent event, DefaultedRegistryReference type) { + return DamageEventUtil.findModifier(event, type).map(event::damage).map(tuple -> tuple.first() - tuple.second()).map(Double::floatValue); + } + + + private static Optional findDamageBefore(DamageEntityEvent event, DefaultedRegistryReference type) { + return DamageEventUtil.findModifier(event, type).map(event::damage).map(Tuple::first).map(Double::floatValue); + } + + private static Optional findModifier(DamageEntityEvent event, DefaultedRegistryReference type) { + return event.originalFunctions().stream() + .map(DamageFunction::modifier) + .filter(mod -> type.get().equals(mod.type())) + .findFirst(); + } + + + public static DamageEntityEvent callSimpleDamageEntityEvent(final DamageSource source, final Entity targetEntity, final double amount) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + DamageEventUtil.generateCauseFor(source, frame); + final var event = SpongeEventFactory.createDamageEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) targetEntity, new ArrayList<>(), amount); + SpongeCommon.post(event); + return event; + } + } + + + + + public record DamageEventResult(DamageEntityEvent event, + DamageSource source, + Optional damageToShield, + Optional damageBlockedByShield, + Optional damageToHelmet, + Optional damageToArmor, + Optional damageResisted, + Optional damageAbsorbed + ) { + + } + + + public record Hurt(DamageSource dmgSource, List functions) { + + } + + public record ActuallyHurt(LivingEntity entity, + List functions, + DamageSource dmgSource, + float baseDamage) { + + } + + public record Attack(T sourceEntity, + Entity target, + ItemStack weapon, + DamageSource dmgSource, + float strengthScale, + float baseDamage, + List functions) { + + private AttackEntityEvent postEvent(final float knockbackModifier, final Cause cause) { + final var event = SpongeEventFactory.createAttackEntityEvent( + cause, + (org.spongepowered.api.entity.Entity) this.target, + this.functions, + knockbackModifier, + this.baseDamage); + SpongeCommon.post(event); + return event; + } + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java index e672d10d16d..a26ac2e7835 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java @@ -25,14 +25,11 @@ package org.spongepowered.common.mixin.core.world.entity; import com.google.common.collect.ImmutableList; -import net.minecraft.BlockUtil; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.syncher.SynchedEntityData; @@ -43,7 +40,6 @@ import net.minecraft.server.level.TicketType; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -178,39 +174,25 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow public abstract void shadow$remove(Entity.RemovalReason reason); @Shadow public abstract void shadow$discard(); @Shadow public abstract boolean shadow$isRemoved(); - @Shadow public abstract void shadow$setCustomName(@Nullable Component name); - @Shadow public abstract boolean shadow$hurt(DamageSource source, float amount); @Shadow public abstract int shadow$getId(); @Shadow public abstract boolean shadow$isVehicle(); @Shadow public abstract void shadow$playSound(SoundEvent soundIn, float volume, float pitch); - @Shadow protected abstract void shadow$removePassenger(Entity passenger); @Shadow public abstract boolean shadow$isInvisible(); @Shadow public abstract void shadow$setInvisible(boolean invisible); - @Shadow protected abstract int shadow$getFireImmuneTicks(); @Shadow public abstract EntityType shadow$getType(); @Shadow public abstract boolean shadow$isInWater(); @Shadow public abstract boolean shadow$isPassenger(); @Shadow public abstract void shadow$teleportToWithTicket(double x, double y, double z); @Shadow public abstract void shadow$teleportTo(double x, double y, double z); - @Shadow public abstract void shadow$doEnchantDamageEffects(LivingEntity entityLivingBaseIn, Entity entityIn); @Shadow public abstract CommandSourceStack shadow$createCommandSourceStack(); - @Shadow public abstract Level shadow$getCommandSenderWorld(); @Shadow public abstract net.minecraft.world.phys.Vec3 shadow$position(); - @Shadow public abstract MinecraftServer shadow$getServer(); @Shadow @Nullable public abstract ItemEntity shadow$spawnAtLocation(ItemStack stack, float offsetY); - @Shadow protected abstract void shadow$setRot(float yaw, float pitch); @Shadow @Nullable public abstract Entity shadow$getVehicle(); - @Shadow public abstract boolean shadow$isInvulnerableTo(DamageSource source); @Shadow public abstract AABB shadow$getBoundingBox(); - @Shadow public abstract boolean shadow$isSprinting(); - @Shadow public abstract boolean shadow$isAlliedTo(Entity entityIn); - @Shadow public abstract double shadow$distanceToSqr(Entity entityIn); - @Shadow public abstract SoundSource shadow$getSoundSource(); @Shadow @Nullable public abstract PlayerTeam shadow$getTeam(); @Shadow public abstract void shadow$clearFire(); @Shadow protected abstract void shadow$setSharedFlag(int flag, boolean set); @Shadow public abstract SynchedEntityData shadow$getEntityData(); - @Shadow public abstract void shadow$absMoveTo(double x, double y, double z, float yaw, float pitch); @Shadow public abstract net.minecraft.world.phys.Vec3 shadow$getDeltaMovement(); @Shadow public abstract void shadow$setDeltaMovement(net.minecraft.world.phys.Vec3 motion); @Shadow public abstract void shadow$unRide(); @@ -219,15 +201,12 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow protected abstract net.minecraft.world.phys.Vec3 shadow$getRelativePortalPosition(Direction.Axis direction$axis, BlockUtil.FoundRectangle teleportationrepositioner$result); @Shadow protected abstract void shadow$removeAfterChangingDimensions(); - @Shadow public abstract void shadow$absMoveTo(double p_242281_1_, double p_242281_3_, double p_242281_5_); @Shadow protected abstract int shadow$getPermissionLevel(); @Shadow public abstract float shadow$getYRot(); @Shadow public abstract float shadow$getXRot(); @Shadow public abstract void shadow$setYRot(final float param0); - @Shadow public abstract void shadow$setXRot(final float param0); @Shadow protected abstract Vec3 shadow$collide(Vec3 param0); @Shadow public abstract boolean shadow$fireImmune(); - @Shadow public abstract boolean shadow$isPickable(); @Shadow protected abstract void shadow$markHurt(); @Shadow protected String stringUUID; diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ExperienceOrbMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ExperienceOrbMixin.java index 62f2e3c4e93..0a56467684a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ExperienceOrbMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ExperienceOrbMixin.java @@ -24,11 +24,15 @@ */ package org.spongepowered.common.mixin.core.world.entity; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ExperienceOrb; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(ExperienceOrb.class) public abstract class ExperienceOrbMixin extends EntityMixin { @@ -41,4 +45,11 @@ public abstract class ExperienceOrbMixin extends EntityMixin { this.impl$callExpireEntityEvent(); } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/ExperienceOrb;markHurt()V")) + private void attackImpl$onAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); + } + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java index 60be2feff60..246dcc0946b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java @@ -28,22 +28,18 @@ import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; -import net.minecraft.stats.Stats; -import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatTracker; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeMap; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; @@ -52,17 +48,13 @@ import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.data.Transaction; import org.spongepowered.api.data.type.HandType; -import org.spongepowered.api.entity.FallingBlock; import org.spongepowered.api.entity.living.Living; -import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.action.SleepingEvent; import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.event.cause.entity.damage.DamageFunction; -import org.spongepowered.api.event.entity.DamageEntityEvent; import org.spongepowered.api.event.entity.MoveEntityEvent; import org.spongepowered.api.event.item.inventory.UseItemStackEvent; import org.spongepowered.api.item.inventory.ItemStackSnapshot; @@ -70,7 +62,6 @@ import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -87,19 +78,14 @@ import org.spongepowered.common.entity.living.human.HumanEntity; import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.SpongeCommonEventFactory; -import org.spongepowered.common.event.cause.entity.damage.SpongeDamageSources; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.common.util.Constants; -import org.spongepowered.common.util.DamageEventUtil; import org.spongepowered.common.util.SpongeTicks; import org.spongepowered.common.util.VecHelper; import org.spongepowered.math.vector.Vector3d; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Optional; @SuppressWarnings("ConstantConditions") @@ -115,39 +101,23 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt @Shadow private long lastDamageStamp; @Shadow public abstract AttributeInstance shadow$getAttribute(Holder attribute); - @Shadow public abstract void shadow$setHealth(float health); - @Shadow public abstract void shadow$setAbsorptionAmount(float amount); @Shadow public abstract void shadow$setItemInHand(InteractionHand hand, @Nullable ItemStack stack); @Shadow public abstract void shadow$stopUsingItem(); @Shadow public abstract int shadow$getUseItemRemainingTicks(); - @Shadow public abstract float shadow$getAbsorptionAmount(); @Shadow public abstract float shadow$getHealth(); - @Shadow public abstract boolean shadow$hasEffect(Holder potion); - @Shadow public abstract ItemStack shadow$getItemBySlot(EquipmentSlot slotIn); - @Shadow public abstract ItemStack shadow$getMainHandItem(); @Shadow public abstract CombatTracker shadow$getCombatTracker(); @Shadow public void shadow$kill() { } @Shadow public abstract InteractionHand shadow$getUsedItemHand(); - @Shadow protected abstract void shadow$hurtCurrentlyUsedShield(float p_184590_1_); - @Shadow protected abstract void shadow$blockUsingShield(LivingEntity p_190629_1_); @Shadow public abstract Optional shadow$getSleepingPos(); @Shadow protected abstract void shadow$spawnItemParticles(ItemStack stack, int count); - @Shadow public abstract boolean shadow$onClimbable(); - @Shadow public abstract void shadow$setSprinting(boolean sprinting); - @Shadow public abstract void shadow$setLastHurtMob(Entity entityIn); - @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); @Shadow public abstract ItemStack shadow$getItemInHand(InteractionHand hand); @Shadow protected abstract void shadow$dropEquipment(); @Shadow protected abstract void shadow$dropAllDeathLoot(ServerLevel level, DamageSource damageSourceIn); @Shadow @Nullable public abstract LivingEntity shadow$getKillCredit(); @Shadow protected abstract void shadow$createWitherRose(@Nullable LivingEntity p_226298_1_); - @Shadow public abstract Collection shadow$getActiveEffects(); @Shadow public abstract float shadow$getMaxHealth(); @Shadow public abstract AttributeMap shadow$getAttributes(); @Shadow public abstract void shadow$clearSleepingPos(); - @Shadow protected abstract float shadow$getDamageAfterArmorAbsorb(DamageSource param0, float param1); - @Shadow protected abstract float shadow$getDamageAfterMagicAbsorb(DamageSource param0, float param1); - @Shadow public abstract void shadow$stopRiding(); // @formatter:on @@ -155,147 +125,6 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt @Nullable private Vector3d impl$preTeleportPosition; private int impl$deathEventsPosted; - @Override - public boolean bridge$damageEntity(final DamageSource damageSource, float damage) { - if (this.shadow$isInvulnerableTo(damageSource)) { - return false; - } - final boolean isHuman = (LivingEntity) (Object) this instanceof Player; - // Sponge Start - Call platform hook for adjusting damage - damage = this.bridge$applyModDamage((LivingEntity) (Object) this, damageSource, damage); - // Sponge End - final float originalDamage = damage; - if (damage <= 0) { - return false; - } - - final List originalFunctions = new ArrayList<>(); - final Optional hardHatFunction = - DamageEventUtil.createHardHatModifier((LivingEntity) (Object) this, damageSource); - final Optional armorFunction = - DamageEventUtil.createArmorModifiers((LivingEntity) (Object) this, damageSource); - final Optional resistanceFunction = - DamageEventUtil.createResistanceModifier((LivingEntity) (Object) this, damageSource); - final Optional> armorEnchantments = - DamageEventUtil.createEnchantmentModifiers((LivingEntity) (Object) this, damageSource); - final Optional absorptionFunction = - DamageEventUtil.createAbsorptionModifier((LivingEntity) (Object) this); - final Optional shieldFunction = - DamageEventUtil.createShieldFunction((LivingEntity) (Object) this, damageSource, damage); - - hardHatFunction.ifPresent(originalFunctions::add); - - shieldFunction.ifPresent(originalFunctions::add); - - armorFunction.ifPresent(originalFunctions::add); - - resistanceFunction.ifPresent(originalFunctions::add); - - armorEnchantments.ifPresent(originalFunctions::addAll); - - absorptionFunction.ifPresent(originalFunctions::add); - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - DamageEventUtil.generateCauseFor(damageSource, frame); - - final DamageEntityEvent event = SpongeEventFactory - .createDamageEntityEvent(frame.currentCause(), (org.spongepowered.api.entity.Entity) this, originalFunctions, - originalDamage); - if (damageSource - != SpongeDamageSources.IGNORED) { // Basically, don't throw an event if it's our own damage source - SpongeCommon.post(event); - } - if (event.isCancelled()) { - return false; - } - - damage = (float) event.finalDamage(); - - // Sponge Start - Allow the platform to adjust damage before applying armor/etc - damage = this.bridge$applyModDamageBeforeFunctions((LivingEntity) (Object) this, damageSource, damage); - // Sponge End - - // Helmet - final ItemStack helmet = this.shadow$getItemBySlot(EquipmentSlot.HEAD); - // We still sanity check if a mod is calling to damage the entity with an anvil or falling block - // without using our mixin redirects in EntityFallingBlockMixin. - if ((damageSource.getDirectEntity() instanceof FallingBlock || damageSource.is(DamageTypeTags.DAMAGES_HELMET)) && !helmet.isEmpty()) { - helmet.hurtAndBreak((int) (event.baseDamage() * 4.0F + this.random.nextFloat() * event.baseDamage() * 2.0F), - (LivingEntity) (Object) this, EquipmentSlot.HEAD - ); - } - - boolean hurtStack = false; - // Shield - if (shieldFunction.isPresent()) { - this.shadow$hurtCurrentlyUsedShield((float) event.baseDamage()); - hurtStack = true; - if (!damageSource.is(DamageTypeTags.IS_PROJECTILE)) { - final Entity entity = damageSource.getDirectEntity(); - - if (entity instanceof LivingEntity) { - this.shadow$blockUsingShield((LivingEntity) entity); - } - } - } - - // Armor - if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR) && armorFunction.isPresent()) { - this.shadow$hurtArmor(damageSource, (float) event.baseDamage()); - hurtStack = true; - } - - // Sponge start - log inventory change due to taking damage - if (hurtStack && isHuman) { - PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange((Player) (Object) this, PlayerInventoryTransaction.EventCreator.STANDARD); - ((Player) (Object) this).inventoryMenu.broadcastChanges(); // capture - } - // Sponge end - - // Resistance modifier post calculation - if (resistanceFunction.isPresent()) { - final float f2 = (float) event.damage(resistanceFunction.get().modifier()) - damage; - if (f2 > 0.0F && f2 < 3.4028235E37F) { - if (((LivingEntity) (Object) this) instanceof net.minecraft.server.level.ServerPlayer) { - ((net.minecraft.server.level.ServerPlayer) ((LivingEntity) (Object) this)).awardStat(Stats.DAMAGE_RESISTED, Math.round(f2 * 10.0F)); - } else if (damageSource.getEntity() instanceof net.minecraft.server.level.ServerPlayer) { - ((net.minecraft.server.level.ServerPlayer) damageSource.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(f2 * 10.0F)); - } - } - } - - - double absorptionModifier = absorptionFunction.map(function -> event.damage(function.modifier())).orElse(0d); - if (absorptionFunction.isPresent()) { - absorptionModifier = event.damage(absorptionFunction.get().modifier()); - - } - - final float f = (float) event.finalDamage() - (float) absorptionModifier; - this.shadow$setAbsorptionAmount(Math.max(this.shadow$getAbsorptionAmount() + (float) absorptionModifier, 0.0F)); - if (f > 0.0F && f < 3.4028235E37F && ((LivingEntity) (Object) this) instanceof net.minecraft.server.level.ServerPlayer) { - ((Player) (Object) this).awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); - } - if (damage != 0.0F) { - if (isHuman) { - ((Player) (Object) this).causeFoodExhaustion(damageSource.getFoodExhaustion()); - } - final float f2 = this.shadow$getHealth(); - - this.shadow$setHealth(f2 - damage); - this.shadow$getCombatTracker().recordDamage(damageSource, damage); - - if (isHuman) { - if (damage < 3.4028235E37F) { - ((Player) (Object) this).awardStat(Stats.DAMAGE_TAKEN, Math.round(damage * 10.0F)); - } - return true; - } - - this.shadow$setAbsorptionAmount(this.shadow$getAbsorptionAmount() - damage); - } - return true; - } - } /** * Due to cancelling death events, "healing" the entity is the only way to cancel the death, but we still @@ -317,16 +146,6 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt return this.bridge$getExperiencePointsOnDeath(instance, $$0, $$1); } - /** - * @author bloodmc - * @author zidane - * @reason This shouldn't be used internally but a mod may still call it so we simply reroute to our hook. - */ - @Overwrite - protected void actuallyHurt(final DamageSource damageSource, final float damage) { - this.bridge$damageEntity(damageSource, damage); - } - @Inject(method = "die", at = @At("HEAD"), cancellable = true) private void impl$throwDestructEntityDeath(final DamageSource cause, final CallbackInfo ci) { final boolean throwEvent = !((LevelBridge) this.shadow$level()).bridge$isFake() && Sponge.isServerAvailable() && Sponge.server().onMainThread(); @@ -528,9 +347,9 @@ protected void actuallyHurt(final DamageSource damageSource, final float damage) private void impl$addSelfToFrame(final CauseStackManager.StackFrame frame, final ItemStackSnapshot snapshot) { frame.pushCause(this); frame.addContext(EventContextKeys.USED_ITEM, snapshot); - if (this instanceof ServerPlayer) { - frame.addContext(EventContextKeys.CREATOR, ((ServerPlayer) this).uniqueId()); - frame.addContext(EventContextKeys.NOTIFIER, ((ServerPlayer) this).uniqueId()); + if ((Object) this instanceof ServerPlayer spongePlayer) { + frame.addContext(EventContextKeys.CREATOR, spongePlayer.getUUID()); + frame.addContext(EventContextKeys.NOTIFIER, spongePlayer.getUUID()); } } @@ -669,10 +488,10 @@ protected void actuallyHurt(final DamageSource damageSource, final float damage) if (!SpongeCommon.post(SpongeEventFactory.createUseItemStackEventStop(PhaseTracker.getCauseStackManager().currentCause(), ticksDuration, ticksDuration, snapshot))) { stack.releaseUsing(world, self, duration); - if (self instanceof net.minecraft.server.level.ServerPlayer) { + if (self instanceof ServerPlayer) { // Log Change and capture SlotTransactions - PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange(((net.minecraft.server.level.ServerPlayer) self), PlayerInventoryTransaction.EventCreator.STANDARD); - ((net.minecraft.server.level.ServerPlayer) self).inventoryMenu.broadcastChanges(); + PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange(((ServerPlayer) self), PlayerInventoryTransaction.EventCreator.STANDARD); + ((ServerPlayer) self).inventoryMenu.broadcastChanges(); } } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java deleted file mode 100644 index 50b31eff002..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.mixin.core.world.entity; - -import net.minecraft.advancements.CriteriaTriggers; -import net.minecraft.core.Holder; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.stats.Stats; -import net.minecraft.tags.DamageTypeTags; -import net.minecraft.tags.EntityTypeTags; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; -import net.minecraft.world.entity.WalkAnimationState; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import org.apache.logging.log4j.Level; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.bridge.world.entity.EntityTypeBridge; -import org.spongepowered.common.bridge.world.entity.LivingEntityBridge; -import org.spongepowered.common.bridge.world.entity.PlatformLivingEntityBridge; -import org.spongepowered.common.event.cause.entity.damage.SpongeDamageSources; -import org.spongepowered.common.util.PrettyPrinter; - -@Mixin(value = LivingEntity.class, priority = 900) -public abstract class LivingEntityMixin_Attack_impl extends EntityMixin - implements LivingEntityBridge, PlatformLivingEntityBridge { - - //@formatter:off - @Shadow private DamageSource lastDamageSource; - @Shadow protected float lastHurt; - @Shadow protected int noActionTime; - @Shadow public int hurtDuration; - @Shadow public int hurtTime; - @Shadow protected int lastHurtByPlayerTime; - @Shadow @Nullable protected Player lastHurtByPlayer; - @Shadow private long lastDamageStamp; - - @Shadow public abstract boolean shadow$hasEffect(Holder param0); - @Shadow public abstract boolean shadow$isSleeping(); - @Shadow public abstract void shadow$stopSleeping(); - @Shadow public abstract boolean shadow$isDamageSourceBlocked(DamageSource param0); - @Shadow protected abstract void shadow$actuallyHurt(DamageSource param0, float param1); - @Shadow public abstract void shadow$setLastHurtByMob(@Nullable LivingEntity param0); - @Shadow public abstract void shadow$knockback(double param0, double param1, double param2); - @Shadow protected abstract boolean shadow$checkTotemDeathProtection(DamageSource param0); - @Shadow @Nullable protected abstract SoundEvent shadow$getDeathSound(); - @Shadow protected abstract float shadow$getSoundVolume(); - @Shadow protected abstract float shadow$getVoicePitch(); - @Shadow public abstract void shadow$die(DamageSource param0); - @Shadow protected abstract void shadow$playHurtSound(DamageSource param0); - @Shadow public abstract boolean shadow$isDeadOrDying(); - @Shadow @Final public WalkAnimationState walkAnimation; - @Shadow public abstract ItemStack shadow$getItemBySlot(final EquipmentSlot var1); - @Shadow protected abstract void shadow$hurtHelmet(final DamageSource $$0, final float $$1); - @Shadow public abstract void shadow$indicateDamage(final double $$0, final double $$1); - - // @formatter:on - - /** - * @author bloodmc - November 22, 2015 - * @author gabizou - Updated April 11th, 2016 - Update for 1.9 changes - * @author Aaron1011 - Updated Nov 11th, 2016 - Update for 1.11 changes - * @author gabizou - Updated Nov 15th, 2020 - Update for 1.15 changes - * @author gabizou - Updated Jan 26th, 2022 - Update for 1.16.5 changes - * @reason Reroute damageEntity calls to our hook in order to prevent damage. - */ - @Overwrite - public boolean hurt(final DamageSource source, float amount) { - // Sponge start - Add certain hooks for necessities - this.lastDamageSource = source; - if (source == null) { - new PrettyPrinter(60).centre().add("Null DamageSource").hr() - .addWrapped("Sponge has found a null damage source! This should NEVER happen " - + "as the DamageSource is used for all sorts of calculations. Usually" - + " this can be considered developer error. Please report the following" - + " stacktrace to the most appropriate mod/plugin available.") - .add() - .add(new IllegalArgumentException("Null DamageSource")) - .log(SpongeCommon.logger(), Level.WARN); - return false; - } - // Sponge - This hook is for forge use mainly - if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, amount)) { - return false; - } - // Sponge end - if (this.shadow$isInvulnerableTo(source)) { - return false; - } else if (this.shadow$level().isClientSide) { - return false; - // Sponge - Also ignore our customary damage source - } else if (this.shadow$isDeadOrDying() && source != SpongeDamageSources.IGNORED) { - return false; - } else if (source.is(DamageTypeTags.IS_FIRE) && this.shadow$hasEffect(MobEffects.FIRE_RESISTANCE)) { - return false; - } else { - if (this.shadow$isSleeping() && !this.shadow$level().isClientSide) { - this.shadow$stopSleeping(); - } - - this.noActionTime = 0; - final float f2 = amount; - // Sponge - ignore as this is handled in our damageEntityHook -// if ((source == DamageSource.ANVIL || source == DamageSource.FALLING_BLOCK) && !this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()) -// { -// this.getItemStackFromSlot(EquipmentSlotType.HEAD).damageItem((int)(amount * 4.0F + this.rand.nextFloat() * amount * 2.0F), this, (p_213341_0_) -> { -// p_213341_0_.sendBreakAnimation(EquipmentSlotType.HEAD); -// }); -// amount *= 0.75F; -// } - // Sponge End - - // Sponge - set the 'shield blocking ran' flag to the proper value, since - // we comment out the logic below - float blockedAmount = 0.0F; - boolean isBlocked = false; // $$3 - - if (amount > 0.0F && this.shadow$isDamageSourceBlocked(source)) { -// Sponge start - this is handled in our bridge$damageEntityHook -// this.hurtCurrentlyUsedShield($$1); - blockedAmount = amount; -// amount = 0.0F; -// if (!source.is(DamageTypeTags.IS_PROJECTILE)) { -// Entity $$5 = source.getDirectEntity(); -// if ($$5 instanceof LivingEntity $$6) { -// this.blockUsingShield($$6); -// } -// } - isBlocked = true; -// Sponge end - } - - if (source.is(DamageTypeTags.IS_FREEZING) && this.shadow$getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { - amount *= 5.0F; - } - - this.walkAnimation.setSpeed(1.5F); - boolean isNotInvulnerable = true; // $$7 - - if ((float) this.invulnerableTime > 10.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { - if (amount <= this.lastHurt) { // Technically, this is wrong since 'amount' won't be 0 if a shield is used. However, we need bridge$damageEntityHook so that we process the shield, so we leave it as-is - return false; - } - - // Sponge start - reroute to our damage hook - // only if the class is unmodded. If it's a modded class, then it should be calling our - // damageEntity method, which would re-run our bridge$damageEntityHook. - if (((EntityTypeBridge) this.shadow$getType()).bridge$overridesDamageEntity()) { - this.shadow$actuallyHurt(source, amount - this.lastHurt); - } else { - if (!this.bridge$damageEntity(source, amount - this.lastHurt)) { - return false; - } - } - // this.damageEntity(source, amount - this.lastHurt); // handled above - // Sponge end - this.lastHurt = amount; - isNotInvulnerable = false; - } else { - // Sponge start - reroute to our damage hook - if (((EntityTypeBridge) this.shadow$getType()).bridge$overridesDamageEntity()) { - this.shadow$actuallyHurt(source, amount); - } else { - if (!this.bridge$damageEntity(source, amount)) { - return false; - } - } - this.lastHurt = amount; - this.invulnerableTime = 20; - // this.damageEntity(source, amount); // handled above - // Sponge end - this.hurtDuration = 10; - this.hurtTime = this.hurtDuration; - } - - if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.shadow$getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - this.shadow$hurtHelmet(source, amount); - amount *= 0.75F; - } - - final Entity entity = source.getEntity(); // $$8 - if (entity != null) { - if (entity instanceof LivingEntity livingEntity && !source.is(DamageTypeTags.NO_ANGER)) { - this.shadow$setLastHurtByMob(livingEntity); - } - - if (entity instanceof Player player) { - this.lastHurtByPlayerTime = 100; - this.lastHurtByPlayer = player; - // Forge Start - use TameableEntity instead of WolfEntity - // } else if (entity1 instanceof WolfEntity) { - // WolfEntity wolfentity = (WolfEntity)entity1; - } else if (entity instanceof TamableAnimal animal && animal.isTame()) { - this.lastHurtByPlayerTime = 100; - final LivingEntity owner = animal.getOwner(); - if (owner instanceof Player player) { - this.lastHurtByPlayer = player; - } else { - this.lastHurtByPlayer = null; - } - } - } - - if (isNotInvulnerable) { - if (isBlocked) { - this.shadow$level().broadcastEntityEvent((LivingEntity) (Object) this, (byte) 29); - } else { - this.shadow$level().broadcastDamageEvent((LivingEntity) (Object) this, source); - } - - if (!source.is(DamageTypeTags.NO_IMPACT) && (!isBlocked /*|| amount > 0.0F*/)) { // Sponge - remove 'amount > 0.0F' - it's redundant in Vanilla, and breaks our handling of shields - this.shadow$markHurt(); - } - - if (entity != null && !source.is(DamageTypeTags.IS_EXPLOSION)) { - double xDir = entity.getX() - this.shadow$getX(); // $$13 - double zDir; // $$14 - - for (zDir = entity.getZ() - this.shadow$getZ(); - xDir * xDir + zDir * zDir < 1.0E-4D; - zDir = (Math.random() - Math.random()) * 0.01D) { - xDir = (Math.random() - Math.random()) * 0.01D; - } - - this.shadow$knockback(0.4F, xDir, zDir); - if (!isBlocked) { - this.shadow$indicateDamage(xDir, zDir); - } - } - } - - if (this.shadow$isDeadOrDying()) { - if (!this.shadow$checkTotemDeathProtection(source)) { - final SoundEvent soundevent = this.shadow$getDeathSound(); - if (isNotInvulnerable && soundevent != null) { - if (this.bridge$vanishState().createsSounds()) { // Sponge - Check that we're not vanished - this.shadow$playSound(soundevent, this.shadow$getSoundVolume(), this.shadow$getVoicePitch()); - } - } - - this.shadow$die(source); // Sponge tracker will redirect this call - } - } else if (isNotInvulnerable) { - if (this.bridge$vanishState().createsSounds()) { // Sponge - Check that we're not vanished - this.shadow$playHurtSound(source); - } - } - - final boolean notBlocked = !isBlocked /* || $$1 > 0.0F*/;// Sponge - remove 'amount > 0.0F' since it's handled in the event - if (notBlocked) { - this.lastDamageSource = source; - this.lastDamageStamp = this.shadow$level().getGameTime(); - } - - if ((LivingEntity) (Object) this instanceof net.minecraft.server.level.ServerPlayer player) { - CriteriaTriggers.ENTITY_HURT_PLAYER.trigger(player, source, f2, amount, isBlocked); - if (blockedAmount > 0.0F && blockedAmount < 3.4028235E37F) { - player.awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(blockedAmount * 10.0F)); - } - } - - if (entity instanceof net.minecraft.server.level.ServerPlayer player) { - CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(player, (Entity) (Object) this, source, f2, amount, isBlocked); - } - - return notBlocked; - } - } -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java index 850ec6f5dd8..1e00bcd8358 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin.java @@ -24,15 +24,11 @@ */ package org.spongepowered.common.mixin.core.world.entity; -import net.minecraft.util.Mth; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.GoalSelector; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.entity.Entity; @@ -41,8 +37,6 @@ import org.spongepowered.api.entity.living.Living; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.cause.entity.damage.DamageFunction; -import org.spongepowered.api.event.entity.AttackEntityEvent; import org.spongepowered.api.event.entity.UnleashEntityEvent; import org.spongepowered.api.event.entity.ai.SetAITargetEvent; import org.spongepowered.asm.mixin.Final; @@ -61,10 +55,6 @@ import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.util.DamageEventUtil; - -import java.util.ArrayList; -import java.util.List; @Mixin(Mob.class) public abstract class MobMixin extends LivingEntityMixin { @@ -186,78 +176,9 @@ public LivingEntity getTarget() { return thisEntity.canPickUpLoot() && ((GrieferBridge) this).bridge$canGrief(); } - /** - * @author gabizou - April 8th, 2016 - * @author gabizou - April 11th, 2016 - Update for 1.9 additions - * @author Aaron1011 - November 12, 2016 - Update for 1.11 - * @author Zidane - Minecraft 1.14.4 - * - * @reason Rewrite this to throw an {@link AttackEntityEvent} and process correctly. - * - * float f | baseDamage - * int i | knockbackModifier - * boolean flag | attackSucceeded - * - * @param targetEntity The entity to attack - * @return True if the attack was successful - */ - @Overwrite - public boolean doHurtTarget(final net.minecraft.world.entity.Entity targetEntity) { - // Sponge Start - Prepare our event values - // float baseDamage = this.getEntityAttribute(Attributes.attackDamage).getAttributeValue(); - final double originalBaseDamage = this.shadow$getAttribute(Attributes.ATTACK_DAMAGE).getValue(); - final List originalFunctions = new ArrayList<>(); - // Sponge End - float knockbackModifier = (float) this.shadow$getAttribute(Attributes.ATTACK_KNOCKBACK).getValue(); - - if (targetEntity instanceof LivingEntity) { - // Sponge Start - Gather modifiers - originalFunctions.addAll(DamageEventUtil - .createAttackEnchantmentFunction(this.shadow$getMainHandItem(), targetEntity.getType(), 1.0F)); // 1.0F is for full attack strength since mobs don't have the concept - // baseDamage += EnchantmentHelper.getModifierForCreature(this.getHeldItem(), ((EntityLivingBase) targetEntity).getCreatureAttribute()); - knockbackModifier += EnchantmentHelper.getKnockbackBonus((Mob) (Object) this); - } - - // Sponge Start - Throw our event and handle appropriately - final DamageSource damageSource = this.shadow$level().damageSources().mobAttack((Mob) (Object) this); - PhaseTracker.getCauseStackManager().pushCause(damageSource); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.entity.Entity) targetEntity, - originalFunctions, knockbackModifier, originalBaseDamage); - SpongeCommon.post(event); - PhaseTracker.getCauseStackManager().popCause(); - if (event.isCancelled()) { - return false; - } - knockbackModifier = event.knockbackModifier(); - // boolean attackSucceeded = targetEntity.attackEntityFrom(DamageSource.causeMobDamage(this), baseDamage); - final boolean attackSucceeded = targetEntity.hurt(damageSource, (float) event.finalOutputDamage()); - // Sponge End - if (attackSucceeded) { - if (knockbackModifier > 0 && targetEntity instanceof LivingEntity) { - ((LivingEntity)targetEntity).knockback(knockbackModifier * 0.5F, - Mth.sin(this.shadow$getYRot() * ((float)Math.PI / 180F)), -Mth.cos(this.shadow$getYRot() * ((float)Math.PI / 180F))); - this.shadow$setDeltaMovement(this.shadow$getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); - } - - final int j = EnchantmentHelper.getFireAspect((Mob) (Object) this); - - if (j > 0) { - targetEntity.igniteForSeconds(j * 4); - } - - this.shadow$doEnchantDamageEffects((Mob) (Object) this, targetEntity); - this.shadow$setLastHurtMob(targetEntity); - } - - return attackSucceeded; - } - @Nullable - @Redirect( - method = "checkDespawn()V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/level/Level;getNearestPlayer(Lnet/minecraft/world/entity/Entity;D)Lnet/minecraft/world/entity/player/Player;")) + @Redirect(method = "checkDespawn()V", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;getNearestPlayer(Lnet/minecraft/world/entity/Entity;D)Lnet/minecraft/world/entity/player/Player;")) private Player impl$getClosestPlayerForSpawning(final Level world, final net.minecraft.world.entity.Entity entityIn, final double distance) { double bestDistance = -1.0D; Player result = null; diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/boss/enderdragon/EndCrystalMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/boss/enderdragon/EndCrystalMixin.java index b51f8180849..358c4ebdd50 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/boss/enderdragon/EndCrystalMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/boss/enderdragon/EndCrystalMixin.java @@ -36,13 +36,16 @@ import org.spongepowered.api.world.server.ServerWorld; 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.explosives.ExplosiveBridge; import org.spongepowered.common.bridge.world.entity.boss.enderdragon.EndCrystalBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.core.world.entity.EntityMixin; import org.spongepowered.common.util.Constants; +import org.spongepowered.common.util.DamageEventUtil; import java.util.Optional; @@ -95,4 +98,12 @@ public abstract class EndCrystalMixin extends EntityMixin implements ExplosiveBr } } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/boss/enderdragon/EndCrystal;remove(Lnet/minecraft/world/entity/Entity$RemovalReason;)V")) + private void attackImpl$onAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); + } + } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java index ed065be71f8..494f43dd566 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java @@ -24,13 +24,13 @@ */ package org.spongepowered.common.mixin.core.world.entity.decoration; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity.RemovalReason; import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.level.gameevent.GameEvent; import org.objectweb.asm.Opcodes; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.DamageEntityEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -39,121 +39,133 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.core.world.entity.LivingEntityMixin; import org.spongepowered.common.util.DamageEventUtil; -import java.util.ArrayList; - @Mixin(ArmorStand.class) public abstract class ArmorStandMixin extends LivingEntityMixin { // @formatter:off - @Shadow protected abstract void shadow$causeDamage(DamageSource damageSource, float damage); // damageArmorStand + @Shadow protected abstract void shadow$causeDamage(ServerLevel level, DamageSource damageSource, float damage); // damageArmorStand // @formatter:on /** - * The return value is set to false if the entity should not be completely - * destroyed. + * The return value is set to false if the entity should not be completely destroyed. */ - private void impl$fireDestroyDamageEvent(final DamageSource source, final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - DamageEventUtil.generateCauseFor(source, frame); - final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(frame.currentCause(), - (Entity) this, new ArrayList<>(), Math.max(1000, this.shadow$getHealth())); - if (SpongeCommon.post(event)) { - cir.setReturnValue(false); - } - if (event.finalDamage() < this.shadow$getHealth()) { - this.shadow$causeDamage(source, (float) event.finalDamage()); - cir.setReturnValue(false); - } + private void impl$callDamageBeforeKill(final DamageSource source, final CallbackInfoReturnable cir) { + var event = DamageEventUtil.callSimpleDamageEntityEvent(source, (ArmorStand) (Object) this, Math.max(1000, this.shadow$getHealth())); + if (event.isCancelled()) { + cir.setReturnValue(false); + } + if (event.finalDamage() < this.shadow$getHealth()) { // Deal reduced damage? + this.shadow$causeDamage((ServerLevel) this.shadow$level(), source, (float) event.finalDamage()); + cir.setReturnValue(false); } + // else kill? } /** - * To avoid a loop between kill() and hurt(), we make sure that any killing - * within the hurt() method calls remove() directly, rather than using kill(), - * which is overridden by us to call back to hurt(). - * - * @param target the killed stand + * BYPASSES_INVULNERABILITY */ - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;kill()V")) - private void impl$actuallyKill(final ArmorStand target) { - target.remove(net.minecraft.world.entity.Entity.RemovalReason.KILLED); + @Inject(method = "hurt", cancellable = true, + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/tags/DamageTypeTags;BYPASSES_INVULNERABILITY:Lnet/minecraft/tags/TagKey;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;kill()V", ordinal = 0)) + private void impl$fireDamageEventOutOfWorld(final DamageSource source, final float $$1, final CallbackInfoReturnable cir) { + this.impl$callDamageBeforeKill(source, cir); } - @Inject(method = "hurt", - slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/damagesource/DamageSource;OUT_OF_WORLD:Lnet/minecraft/world/damagesource/DamageSource;")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;kill()V", ordinal = 0), - cancellable = true) - private void impl$fireDamageEventOutOfWorld(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - this.impl$fireDestroyDamageEvent(source, cir); - } - - @Inject(method = "hurt", - slice = @Slice(from = @At(value = "INVOKE", - target = "Lnet/minecraft/world/damagesource/DamageSource;isExplosion()Z") - ), - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/ArmorStand;causeDamage(Lnet/minecraft/world/damagesource/DamageSource;F)V"), - cancellable = true) + /** + * IS_EXPLOSION + */ + @Inject(method = "hurt", cancellable = true, + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/tags/DamageTypeTags;IS_EXPLOSION:Lnet/minecraft/tags/TagKey;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;brokenByAnything(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;)V")) private void impl$fireDamageEventExplosion(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - this.impl$fireDestroyDamageEvent(source, cir); + this.impl$callDamageBeforeKill(source, cir); } - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;causeDamage(Lnet/minecraft/world/damagesource/DamageSource;F)V")) - private void impl$fireDamageEventDamage(final ArmorStand self, final DamageSource source, final float amount) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - DamageEventUtil.generateCauseFor(source, frame); - final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(frame.currentCause(), - (Entity) this, new ArrayList<>(), amount); - if (!SpongeCommon.post(event)) { - this.shadow$causeDamage(source, (float) event.finalDamage()); - } + /** + * causeDamage with damage value + * IGNITES_ARMOR_STANDS + isOnFire + * BURNS_ARMOR_STANDS + health > 0.5 + */ + @Redirect(method = "hurt", + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/tags/DamageTypeTags;IGNITES_ARMOR_STANDS:Lnet/minecraft/tags/TagKey;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;causeDamage(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void impl$fireDamageEventDamage(final ArmorStand self, final ServerLevel level, final DamageSource source, final float amount) { + var event = DamageEventUtil.callSimpleDamageEntityEvent(source, self, amount); + if (!event.isCancelled()) { + this.shadow$causeDamage(level, source, (float) event.finalDamage()); } } - @Inject(method = "hurt", slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSource;isCreativePlayer()Z")), + /** + * {@link DamageSource#isCreativePlayer()} + */ + @Inject(method = "hurt", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSource;isCreativePlayer()Z")), at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;playBrokenSound()V"), cancellable = true) private void impl$fireDamageEventCreativePunch(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - this.impl$fireDestroyDamageEvent(source, cir); + this.impl$callDamageBeforeKill(source, cir); } - @Inject(method = "hurt", - slice = @Slice( - from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;lastHit:J", opcode = Opcodes.GETFIELD)), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;broadcastEntityEvent(Lnet/minecraft/world/entity/Entity;B)V"), - cancellable = true) + /** + * {@link ArmorStand#lastHit} was not recently + */ + @Inject(method = "hurt", cancellable = true, + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;lastHit:J", opcode = Opcodes.GETFIELD)), + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;broadcastEntityEvent(Lnet/minecraft/world/entity/Entity;B)V")) private void impl$fireDamageEventFirstPunch(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - // While this doesn't technically "damage" the armor stand, it feels - // like damage in other respects, so fire an event. - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - DamageEventUtil.generateCauseFor(source, frame); - final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(frame.currentCause(), - (Entity) this, new ArrayList<>(), 0); - if (SpongeCommon.post(event)) { - cir.setReturnValue(false); - } + // While this doesn't technically "damage" the armor stand, it feels like damage in other respects, so fire an event. + var event = DamageEventUtil.callSimpleDamageEntityEvent(source, (ArmorStand) (Object) this, 0); + if (event.isCancelled()) { + cir.setReturnValue(false); } } - @Inject(method = "hurt", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/ArmorStand;brokenByPlayer(Lnet/minecraft/world/damagesource/DamageSource;)V" - ), - cancellable = true) + /** + * {@link ArmorStand#lastHit} was recently + */ + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/ArmorStand;brokenByPlayer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;)V")) private void impl$fireDamageEventSecondPunch(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - this.impl$fireDestroyDamageEvent(source, cir); + this.impl$callDamageBeforeKill(source, cir); + } + + /** + * To avoid a loop between {@link #kill} and {@link ArmorStand#hurt}, + * we make sure that any killing within the {@link ArmorStand#hurt} + * method calls this instead of the {@link Overwrite} + * + * @param target the killed stand + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;kill()V")) + private void impl$actuallyKill(final ArmorStand target) { + target.remove(RemovalReason.KILLED); + target.gameEvent(GameEvent.ENTITY_DIE); + } + + /** + * To avoid a loop between {@link #kill} and {@link #shadow$causeDamage}, + * we make sure that any killing within the {@link #shadow$causeDamage} + * method calls this instead of the {@link Overwrite} + * + * @param target the killed stand + */ + @Redirect(method = "causeDamage", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/ArmorStand;kill()V")) + private void impl$actuallyKill2(final ArmorStand target) { + target.remove(RemovalReason.KILLED); + target.gameEvent(GameEvent.ENTITY_DIE); } /** * @author JBYoshi * @reason EntityArmorStand "simplifies" this method to simply call {@link - * #shadow$remove(net.minecraft.world.entity.Entity.RemovalReason)}. However, - * this ignores our custom event. Instead, delegate - * to the superclass and use {@link ArmorStand#hurt(DamageSource, float)}. + * #shadow$remove(RemovalReason)}. However, this ignores our custom event. + * Instead, delegate to the superclass causing it to use + * {@link ArmorStand#hurt(DamageSource, float)} with {@link DamageTypes#GENERIC_KILL} + * + * This needs to be reimplemented in {@link #impl$actuallyKill}! */ @Overwrite public void kill() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java index fa4982e871b..03a8ad46608 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/BlockAttachedEntityMixin.java @@ -25,22 +25,16 @@ package org.spongepowered.common.mixin.core.world.entity.decoration; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.decoration.BlockAttachedEntity; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.AttackEntityEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.core.world.entity.EntityMixin; - -import java.util.ArrayList; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(BlockAttachedEntity.class) public abstract class BlockAttachedEntityMixin extends EntityMixin { @@ -60,22 +54,11 @@ public abstract class BlockAttachedEntityMixin extends EntityMixin { return this.shadow$survives() && !this.impl$ignorePhysics; } - @Inject(method = "hurt", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/BlockAttachedEntity;kill()V" - ), - cancellable = true - ) - private void impl$postEventOnAttackEntityFrom(final DamageSource source, final float amount, - final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(source); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), - (Entity) this, new ArrayList<>(), 0, amount); - SpongeCommon.post(event); - if (event.isCancelled()) { - cir.setReturnValue(true); - } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/BlockAttachedEntity;kill()V")) + private void attackImpl$postEventOnAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ItemFrameMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ItemFrameMixin.java index e61214a1052..f84c4d54c9b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ItemFrameMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ItemFrameMixin.java @@ -25,37 +25,21 @@ package org.spongepowered.common.mixin.core.world.entity.decoration; import net.minecraft.world.damagesource.DamageSource; -import org.spongepowered.api.entity.hanging.ItemFrame; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.AttackEntityEvent; +import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseTracker; - -import java.util.ArrayList; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(net.minecraft.world.entity.decoration.ItemFrame.class) public abstract class ItemFrameMixin extends HangingEntityMixin { - @Inject(method = "hurt", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/decoration/ItemFrame;dropItem(Lnet/minecraft/world/entity/Entity;Z)V" - ), - cancellable = true) - private void onAttackEntityFrom(final DamageSource source, final float amount, - final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(source); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), (ItemFrame) this, new ArrayList<>(), 0, amount); - SpongeCommon.post(event); - if (event.isCancelled()) { - cir.setReturnValue(true); - } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/ItemFrame;dropItem(Lnet/minecraft/world/entity/Entity;Z)V")) + private void attackImpl$onAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/ItemEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/ItemEntityMixin.java index e1448b9af5f..e80443443f2 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/ItemEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/ItemEntityMixin.java @@ -24,6 +24,8 @@ */ package org.spongepowered.common.mixin.core.world.entity.item; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import org.spongepowered.api.Sponge; @@ -38,6 +40,7 @@ import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.data.SpongeDataHolderBridge; import org.spongepowered.common.bridge.world.entity.item.ItemEntityBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; @@ -47,6 +50,7 @@ import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.core.world.entity.EntityMixin; import org.spongepowered.common.util.Constants; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(ItemEntity.class) public abstract class ItemEntityMixin extends EntityMixin implements ItemEntityBridge { @@ -140,4 +144,12 @@ public abstract class ItemEntityMixin extends EntityMixin implements ItemEntityB } } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/item/ItemEntity;markHurt()V")) + private void attackImpl$onAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); + } + } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java deleted file mode 100644 index eb276bf6add..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.mixin.core.world.entity.player; - -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.stats.Stats; -import net.minecraft.tags.EntityTypeTags; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.entity.projectile.ProjectileDeflection; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.phys.Vec3; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.spongepowered.api.event.Cause; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.EventContext; -import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.cause.entity.damage.DamageFunction; -import org.spongepowered.api.event.cause.entity.damage.DamageModifier; -import org.spongepowered.api.event.cause.entity.damage.DamageModifierTypes; -import org.spongepowered.api.event.cause.entity.damage.DamageTypes; -import org.spongepowered.api.event.cause.entity.damage.ModifierFunction; -import org.spongepowered.api.event.entity.AttackEntityEvent; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseContext; -import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.hooks.EventHooks; -import org.spongepowered.common.hooks.PlatformHooks; -import org.spongepowered.common.item.util.ItemStackUtil; -import org.spongepowered.common.mixin.core.world.entity.LivingEntityMixin; -import org.spongepowered.common.util.DamageEventUtil; - -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings("ConstantConditions") -@Mixin(value = Player.class, priority = 900) -public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin { - - //@formatter:off - @Shadow @Final public InventoryMenu inventoryMenu; - @Shadow public abstract float shadow$getAttackStrengthScale(float p_184825_1_); - @Shadow public abstract void shadow$resetAttackStrengthTicker(); - @Shadow public abstract float shadow$getSpeed(); - @Shadow public abstract void shadow$sweepAttack(); - @Shadow public abstract void shadow$crit(Entity p_71009_1_); - @Shadow public abstract void shadow$magicCrit(Entity p_71047_1_); - @Shadow public abstract void shadow$awardStat(ResourceLocation stat, int amount); - @Shadow public abstract void shadow$causeFoodExhaustion(float p_71020_1_); - //@formatter:on - - /** - * @author gabizou - April 8th, 2016 - * @author gabizou - April 11th, 2016 - Update for 1.9 - This enitre method was rewritten - * @author i509VCB - February 15th, 2020 - Update for 1.14.4 - * @author gabizou - November 15th, 2020 - Update for 1.15.2 - * - * @reason Rewrites the attack to throw an {@link AttackEntityEvent} prior - * to the ensuing {@link org.spongepowered.api.event.entity.DamageEntityEvent}. This should cover all cases where players are - * attacking entities and those entities override {@link LivingEntity#hurt(DamageSource, float)} - * and effectively bypass our damage event hooks. - * - * LVT Rename Table: - * float f | damage | - * float f1 | enchantmentDamage | - * float f2 | attackStrength | - * boolean flag | isStrongAttack | - * boolean flag1 | isSprintingAttack | - * boolean flag2 | isCriticalAttack | Whether critical particles will spawn and of course, multiply the output damage - * boolean flag3 | isSweapingAttack | Whether the player is sweaping an attack and will deal AoE damage - * int i | knockbackModifier | The knockback modifier, must be set from the event after it has been thrown - * float f4 | targetOriginalHealth | This is initially set as the entity original health - * boolean flag4 | litEntityOnFire | This is an internal flag to where if the attack failed, the entity is no longer set on fire - * int j | fireAspectModifier | Literally just to check that the weapon used has fire aspect enchantments - * double d0 | distanceWalkedDelta | This checks that the distance walked delta is more than the normal walking speed to evaluate if you're making a sweaping attack - * double d1 | targetMotionX | Current target entity motion x vector - * double d2 | targetMotionY | Current target entity motion y vector - * double d3 | targetMotionZ | Current target entity motion z vector - * boolean flag5 | attackSucceeded | Whether the attack event succeeded - * - * @param targetEntity The target entity - */ - @Overwrite - public void attack(final Entity targetEntity) { - // Sponge Start - Add SpongeImpl hook to override in forge as necessary - if (!PlatformHooks.INSTANCE.getEntityHooks().checkAttackEntity((net.minecraft.world.entity.player.Player) (Object) this, targetEntity)) { - return; - } - // Sponge End - if (targetEntity.isAttackable()) { - if (!targetEntity.skipAttackInteraction((net.minecraft.world.entity.player.Player) (Object) this)) { - // Sponge Start - Prepare our event values - // float damage = (float) this.getEntityAttribute(Attributes.ATTACK_DAMAGE).getAttributeValue(); - final double originalBaseDamage = this.shadow$getAttribute(Attributes.ATTACK_DAMAGE).getValue(); - float damage = (float) originalBaseDamage; - // Sponge End - float enchantmentDamage = 0.0F; - - // Sponge Start - Redirect getting enchantments for our damage event handlers - // if (targetEntity instanceof LivingEntity) { - // enchantmentDamage = EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), ((LivingEntity) targetEntity).getCreatureAttribute()); - // } else { - // enchantmentDamage = EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), CreatureAttribute.UNDEFINED); - // } - if (targetEntity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && targetEntity instanceof Projectile proj) { - proj.deflect(ProjectileDeflection.AIM_DEFLECT, (Player) (Object) this, (Player) (Object) this, true); - // sponge - move the reset attack strength early to avoid resetting it from other events - this.shadow$resetAttackStrengthTicker(); - return; - } - final float attackStrength = this.shadow$getAttackStrengthScale(0.5F); - - final List originalFunctions = new ArrayList<>(); - - final List enchantmentModifierFunctions = DamageEventUtil - .createAttackEnchantmentFunction(this.shadow$getMainHandItem(), targetEntity.getType(), attackStrength); - // This is kept for the post-damage event handling - final List enchantmentModifiers = enchantmentModifierFunctions.stream() - .map(ModifierFunction::modifier) - .toList(); - - enchantmentDamage = (float) enchantmentModifierFunctions.stream() - .map(ModifierFunction::function) - .mapToDouble(function -> function.applyAsDouble(originalBaseDamage)) - .sum(); - originalFunctions.addAll(enchantmentModifierFunctions); - // Sponge End - - originalFunctions.add( - DamageEventUtil.provideCooldownAttackStrengthFunction((net.minecraft.world.entity.player.Player) (Object) this, attackStrength)); - damage = damage * (0.2F + attackStrength * attackStrength * 0.8F); - enchantmentDamage = enchantmentDamage * attackStrength; - this.shadow$resetAttackStrengthTicker(); - - if (damage > 0.0F || enchantmentDamage > 0.0F) { - final boolean isStrongAttack = attackStrength > 0.9F; - boolean isSprintingAttack = false; - boolean isCriticalAttack = false; - boolean isSweapingAttack = false; - int knockbackModifier = 0; - knockbackModifier = knockbackModifier + EnchantmentHelper.getKnockbackBonus((net.minecraft.world.entity.player.Player) (Object) this); - - if (this.shadow$isSprinting() && isStrongAttack) { - // Sponge - Only play sound after the event has be thrown and not cancelled. - // this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.entity_player_attack_knockback, this.getSoundCategory(), 1.0F, 1.0F); - ++knockbackModifier; - isSprintingAttack = true; - } - - isCriticalAttack = isStrongAttack && this.fallDistance > 0.0F && !this.shadow$onGround() && !this.shadow$onClimbable() && !this.shadow$isInWater() && !this.shadow$hasEffect( - MobEffects.BLINDNESS) && !this.shadow$isPassenger() && targetEntity instanceof LivingEntity; - isCriticalAttack = isCriticalAttack && !this.shadow$isSprinting(); - final EventHooks.CriticalHitResult criticalResult = PlatformHooks.INSTANCE.getEventHooks().callCriticalHitEvent((net.minecraft.world.entity.player.Player) (Object) this, targetEntity, isCriticalAttack, isCriticalAttack ? 0.5F : 0.0F); - isCriticalAttack = criticalResult.criticalHit; - if (isCriticalAttack) { - // Sponge Start - add critical attack tuple - // damage *= 1.5F; // Sponge - This is handled in the event - originalFunctions.add(DamageEventUtil.provideCriticalAttackTuple((net.minecraft.world.entity.player.Player) (Object) this, criticalResult.modifier)); - // Sponge End - } - - // damage = damage + enchantmentDamage; // Sponge - We don't need this since our event will re-assign the damage to deal - final double distanceWalkedDelta = (double) (this.walkDist - this.walkDistO); - - final ItemStack heldItem = this.shadow$getMainHandItem(); - if (isStrongAttack && !isCriticalAttack && !isSprintingAttack && this.shadow$onGround() && distanceWalkedDelta < (double) this.shadow$getSpeed()) { - if (PlatformHooks.INSTANCE.getItemHooks().canPerformSweepAttack(heldItem)) { - isSweapingAttack = true; - } - } - - // Sponge Start - Create the event and throw it - final DamageSource damageSource = this.shadow$level().damageSources().playerAttack((net.minecraft.world.entity.player.Player) (Object) this); - final boolean isMainthread = !this.shadow$level().isClientSide; - if (isMainthread) { - PhaseTracker.getInstance().pushCause(damageSource); - } - final Cause currentCause = isMainthread ? PhaseTracker.getInstance().currentCause() : Cause.of( - EventContext.empty(), damageSource); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(currentCause, (org.spongepowered.api.entity.Entity) targetEntity, - originalFunctions, knockbackModifier, originalBaseDamage); - SpongeCommon.post(event); - if (isMainthread) { - PhaseTracker.getInstance().popCause(); - } - if (event.isCancelled()) { - return; - } - - damage = (float) event.finalOutputDamage(); - // Sponge End - - // Sponge Start - need final for later events - final double attackDamage = damage; - knockbackModifier = (int) event.knockbackModifier(); - enchantmentDamage = (float) enchantmentModifiers.stream() - .mapToDouble(event::outputDamage) - .sum(); - // Sponge End - - float targetOriginalHealth = 0.0F; - boolean litEntityOnFire = false; - final int fireAspectModifier = EnchantmentHelper.getFireAspect((net.minecraft.world.entity.player.Player) (Object) this); - - if (targetEntity instanceof LivingEntity) { - targetOriginalHealth = ((LivingEntity) targetEntity).getHealth(); - - if (fireAspectModifier > 0 && !targetEntity.isOnFire()) { - litEntityOnFire = true; - targetEntity.igniteForSeconds(1); - } - } - - final Vec3 targetMotion = targetEntity.getDeltaMovement(); - final boolean attackSucceeded = targetEntity.hurt(this.shadow$level().damageSources().playerAttack((net.minecraft.world.entity.player.Player) (Object) this), damage); - - if (attackSucceeded) { - if (knockbackModifier > 0) { - if (targetEntity instanceof LivingEntity le) { - le.knockback( - (float) knockbackModifier * 0.5F, - Mth.sin(this.shadow$getYRot() * 0.017453292F), - -Mth.cos(this.shadow$getYRot() * 0.017453292F) - ); - } else { - targetEntity.push( - -Mth.sin(this.shadow$getYRot() * 0.017453292F) * (float) knockbackModifier * 0.5F, - 0.1D, - Mth.cos(this.shadow$getYRot() * 0.017453292F) * (float) knockbackModifier * 0.5F - ); - } - - this.shadow$setDeltaMovement(this.shadow$getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); - this.shadow$setSprinting(false); - } - - if (isSweapingAttack) { - // Sponge - add forge compatibility hook - final var hitbox = PlatformHooks.INSTANCE.getItemHooks().getSweepingHitBox(((Player) (Object) this), this.shadow$getItemInHand(InteractionHand.MAIN_HAND), targetEntity); - for (final LivingEntity livingEntity : this.shadow$level().getEntitiesOfClass(LivingEntity.class, hitbox)) { - if (livingEntity != (net.minecraft.world.entity.player.Player) (Object) this && livingEntity != targetEntity && !this.shadow$isAlliedTo(livingEntity) && (!(livingEntity instanceof ArmorStand) || !((ArmorStand)livingEntity).isMarker()) && this.shadow$distanceToSqr(livingEntity) < 9.0D) { - // Sponge Start - Do a small event for these entities - // livingEntity.knockBack(this, 0.4F, (double)MathHelper.sin(this.rotationYaw * 0.017453292F), (double)(-MathHelper.cos(this.rotationYaw * 0.017453292F))); - // livingEntity.attackEntityFrom(DamageSource.causePlayerDamage(this), 1.0F); - final var sweepingAttackSource = org.spongepowered.api.event.cause.entity.damage.source.DamageSource.builder().entity((org.spongepowered.api.entity.living.player.Player) this) - .type(DamageTypes.PLAYER_ATTACK).build(); - try (final CauseStackManager.StackFrame frame = isMainthread ? PhaseTracker.getInstance().pushCauseFrame() : null) { - if (isMainthread) { - frame.pushCause(sweepingAttackSource); - } - final ItemStackSnapshot heldSnapshot = ItemStackUtil.snapshotOf(heldItem); - if (isMainthread) { - frame.addContext(EventContextKeys.WEAPON, heldSnapshot); - } - final DamageFunction sweapingFunction = DamageFunction.of(DamageModifier.builder() - .cause(Cause.of(EventContext.empty(), heldSnapshot)) - .item(heldSnapshot) - .type(DamageModifierTypes.SWEEPING) - .build(), - incoming -> EnchantmentHelper.getSweepingDamageRatio((net.minecraft.world.entity.player.Player) (Object) this) * attackDamage); - final List sweapingFunctions = new ArrayList<>(); - sweapingFunctions.add(sweapingFunction); - final AttackEntityEvent sweepingAttackEvent = SpongeEventFactory.createAttackEntityEvent( - currentCause, (org.spongepowered.api.entity.Entity) livingEntity, - sweapingFunctions, 1, 1.0D); - SpongeCommon.post(sweepingAttackEvent); - if (!sweepingAttackEvent.isCancelled()) { - livingEntity.knockback(sweepingAttackEvent.knockbackModifier() * 0.4F, - (double) Mth.sin(this.shadow$getYRot() * ((float)Math.PI / 180F)), - (double) -Mth.cos(this.shadow$getYRot() * ((float)Math.PI / 180F))); - - livingEntity.hurt(this.shadow$level().damageSources().playerAttack((net.minecraft.world.entity.player.Player) (Object) this), - (float) sweepingAttackEvent.finalOutputDamage()); - } - } - // Sponge End - } - } - - if (this.bridge$vanishState().createsSounds()) { - this.shadow$level().playSound( - null, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), - SoundEvents.PLAYER_ATTACK_SWEEP, this.shadow$getSoundSource(), 1.0F, 1.0F - ); - } - this.shadow$sweepAttack(); - } - - if (targetEntity instanceof ServerPlayer sp && sp.hurtMarked) { - sp.connection.send(new ClientboundSetEntityMotionPacket(targetEntity)); - sp.hurtMarked = false; - sp.setDeltaMovement(targetMotion); - } - - if (isCriticalAttack) { - if (this.bridge$vanishState().createsSounds()) { - this.shadow$level().playSound(null, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.shadow$getSoundSource(), 1.0F, 1.0F); - } - this.shadow$crit(targetEntity); - } - - if (!isCriticalAttack && !isSweapingAttack && this.bridge$vanishState().createsSounds()) { - if (isStrongAttack) { - this.shadow$level().playSound(null, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.shadow$getSoundSource(), 1.0F, 1.0F); - } else { - this.shadow$level().playSound(null, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), SoundEvents.PLAYER_ATTACK_WEAK , this.shadow$getSoundSource(), 1.0F, 1.0F); - } - } - - if (enchantmentDamage > 0.0F) { - this.shadow$magicCrit(targetEntity); - } - - this.shadow$setLastHurtMob(targetEntity); - - if (targetEntity instanceof LivingEntity le) { - EnchantmentHelper.doPostHurtEffects(le, (net.minecraft.world.entity.player.Player) (Object) this); - } - - EnchantmentHelper.doPostDamageEffects((net.minecraft.world.entity.player.Player) (Object) this, targetEntity); - final ItemStack itemstack1 = this.shadow$getMainHandItem(); - Entity entity = targetEntity; - - // Sponge - Forge compatibility for multi-part entities - entity = PlatformHooks.INSTANCE.getEntityHooks().getParentPart(entity); - // if (targetEntity instanceof EnderDragonPart) { - // entity = ((EnderDragonPart) targetEntity).parentMob; - // } - - if(!this.shadow$level().isClientSide && !itemstack1.isEmpty() && entity instanceof LivingEntity le) { - itemstack1.hurtEnemy(le, (net.minecraft.world.entity.player.Player) (Object) this); - if(itemstack1.isEmpty()) { - // Sponge - platform hook for forge - PlatformHooks.INSTANCE.getEventHooks().callItemDestroyedEvent((net.minecraft.world.entity.player.Player) (Object) this, itemstack1, InteractionHand.MAIN_HAND); - this.shadow$setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); - } - // Sponge Start - final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); - final TransactionalCaptureSupplier transactor = context.getTransactor(); - transactor.logPlayerInventoryChange((net.minecraft.world.entity.player.Player) (Object) this, PlayerInventoryTransaction.EventCreator.STANDARD); - this.inventoryMenu.broadcastChanges(); // capture - // Spong End - } - - if (targetEntity instanceof LivingEntity le) { - final float f5 = targetOriginalHealth - le.getHealth(); - this.shadow$awardStat(Stats.DAMAGE_DEALT, Math.round(f5 * 10.0F)); - - if (fireAspectModifier > 0) { - targetEntity.igniteForSeconds(fireAspectModifier * 4); - } - - if (this.shadow$level() instanceof ServerLevel swe && f5 > 2.0F) { - final int k = (int) ((double) f5 * 0.5D); - swe.sendParticles(ParticleTypes.DAMAGE_INDICATOR, targetEntity.getX(), targetEntity.getY() + (double) (targetEntity.getBbHeight() * 0.5F), targetEntity.getZ(), k, 0.1D, 0.0D, 0.1D, 0.2D); - } - } - - this.shadow$causeFoodExhaustion(0.1F); - } else { - if (this.bridge$vanishState().createsSounds()) { - this.shadow$level().playSound(null, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.shadow$getSoundSource(), 1.0F, 1.0F); - } - - if (litEntityOnFire) { - targetEntity.clearFire(); - } - } - } - } - } - } - - /** - * @author gabizou - January 26th, 2022 - * @reason Add changes according to - */ - @Override - @Overwrite - protected void actuallyHurt(final DamageSource damageSource, final float damage) { - this.bridge$damageEntity(damageSource, damage); - } -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ShulkerBulletMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ShulkerBulletMixin.java index a68d84d7178..dc90ee08343 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ShulkerBulletMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ShulkerBulletMixin.java @@ -24,14 +24,18 @@ */ package org.spongepowered.common.mixin.core.world.entity.projectile; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.projectile.ShulkerBullet; import net.minecraft.world.phys.HitResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(ShulkerBullet.class) public abstract class ShulkerBulletMixin extends ProjectileMixin { @@ -45,4 +49,12 @@ private void onBulletHitBlock(final HitResult result, final CallbackInfo ci) { ci.cancel(); } } + + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/projectile/ShulkerBullet;playSound(Lnet/minecraft/sounds/SoundEvent;FF)V")) + private void attackImpl$onAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); + } + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/MinecartTNTMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/MinecartTNTMixin.java index 9a73dfd65c5..db569f5e383 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/MinecartTNTMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/MinecartTNTMixin.java @@ -32,9 +32,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.vehicle.minecart.TNTMinecart; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.AttackEntityEvent; import org.spongepowered.api.world.explosion.Explosion; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; @@ -45,15 +42,14 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.bridge.explosives.ExplosiveBridge; import org.spongepowered.common.bridge.explosives.FusedExplosiveBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.util.Constants; +import org.spongepowered.common.util.DamageEventUtil; -import java.util.ArrayList; import java.util.Optional; @Mixin(MinecartTNT.class) @@ -166,16 +162,11 @@ public abstract class MinecartTNTMixin extends AbstractMinecartMixin implements } } - @Inject(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/vehicle/MinecartTNT;explode(Lnet/minecraft/world/damagesource/DamageSource;D)V"), cancellable = true) - private void impl$postOnAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(source); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), - (TNTMinecart) this, new ArrayList<>(), 0, amount); - SpongeCommon.post(event); - if (event.isCancelled()) { - cir.setReturnValue(true); - } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/vehicle/MinecartTNT;explode(Lnet/minecraft/world/damagesource/DamageSource;D)V")) + private void attackImpl$postOnAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/VehicleEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/VehicleEntityMixin.java index 00a50c30f46..1fa0a765550 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/VehicleEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/VehicleEntityMixin.java @@ -26,37 +26,21 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.vehicle.VehicleEntity; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.entity.AttackEntityEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.core.world.entity.EntityMixin; - -import java.util.ArrayList; +import org.spongepowered.common.util.DamageEventUtil; @Mixin(VehicleEntity.class) public abstract class VehicleEntityMixin extends EntityMixin { - @Inject(method = "hurt", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/vehicle/VehicleEntity;shouldSourceDestroy(Lnet/minecraft/world/damagesource/DamageSource;)Z" - ), - cancellable = true) - private void impl$postOnAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(this); - frame.pushCause(source); - final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(frame.currentCause(), (Entity) this, new ArrayList<>(), 0, amount); - SpongeCommon.post(event); - if (event.isCancelled()) { - cir.setReturnValue(true); - } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/vehicle/VehicleEntity;shouldSourceDestroy(Lnet/minecraft/world/damagesource/DamageSource;)Z")) + private void attackImpl$postOnAttackEntityFrom(final DamageSource source, final float amount, final CallbackInfoReturnable cir) { + if (DamageEventUtil.callOtherAttackEvent((net.minecraft.world.entity.Entity) (Object) this, source, amount).isCancelled()) { + cir.setReturnValue(true); } } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/ExplosionMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/ExplosionMixin.java index 2b14f786fd6..688112d13eb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/ExplosionMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/ExplosionMixin.java @@ -34,8 +34,8 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.enchantment.ProtectionEnchantment; import net.minecraft.world.level.ExplosionDamageCalculator; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -257,8 +257,8 @@ public void explode() { final double d10 = (1.0D - d12) * d14; entity.hurt(this.damageSource, (float)((int)((d10 * d10 + d10) / 2.0D * 7.0D * (double)f3 + 1.0D))); double d11 = d10; - if (entity instanceof LivingEntity) { - d11 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity)entity, d10); + if (entity instanceof LivingEntity living) { + d11 = d10 * (1.0 - living.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE)); } // Sponge Start - Honor our knockback value from event diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 49c2ca4e607..d96b7cafbbc 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -117,7 +117,6 @@ "world.entity.LeashableMixin", "world.entity.LightningBoltMixin", "world.entity.LivingEntityMixin", - "world.entity.LivingEntityMixin_Attack_impl", "world.entity.MobMixin", "world.entity.ai.goal.BreakDoorGoalMixin", "world.entity.ai.goal.BreedGoalMixin", @@ -156,7 +155,6 @@ "world.entity.npc.VillagerMixin", "world.entity.npc.WanderingTraderMixin", "world.entity.player.PlayerMixin", - "world.entity.player.PlayerMixin_Attack_Impl", "world.entity.projectile.AbstractArrowMixin", "world.entity.projectile.AbstractHurtingProjectileMixin", "world.entity.projectile.EyeOfEnderMixin", diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java new file mode 100644 index 00000000000..a3d7ef6c3b7 --- /dev/null +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -0,0 +1,462 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.mixin.core.world.entity; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.stats.Stats; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.damagesource.CombatRules; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.TamableAnimal; +import net.minecraft.world.entity.animal.Wolf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import org.apache.logging.log4j.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Coerce; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.world.entity.LivingEntityBridge; +import org.spongepowered.common.bridge.world.entity.PlatformLivingEntityBridge; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.mixin.core.world.entity.EntityMixin; +import org.spongepowered.common.util.DamageEventUtil; +import org.spongepowered.common.util.PrettyPrinter; + +import java.util.ArrayList; + +@Mixin(value = LivingEntity.class, priority = 900) +public abstract class LivingEntityMixin_Attack_impl extends EntityMixin + implements LivingEntityBridge, PlatformLivingEntityBridge { + + //@formatter:off + @Shadow protected abstract void shadow$playHurtSound(DamageSource param0); + @Shadow protected abstract void shadow$hurtHelmet(final DamageSource $$0, final float $$1); + @Shadow protected abstract void shadow$hurtCurrentlyUsedShield(final float $$0); + @Shadow protected abstract void shadow$blockUsingShield(final LivingEntity $$0); + @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); + @Shadow protected abstract float shadow$getKnockback(final Entity $$0, final DamageSource $$1); + @Shadow public abstract ItemStack shadow$getItemInHand(final InteractionHand $$0); + @Shadow public abstract float shadow$getAbsorptionAmount(); + @Shadow public abstract void setAbsorptionAmount(final float $$0); + @Shadow protected int attackStrengthTicker; + @Shadow protected float lastHurt; + + + // @formatter:on + private float attackImpl$lastHurt; + private int attackImpl$InvulnerableTime; + + protected DamageEventUtil.Hurt attackImpl$hurt; + protected DamageEventUtil.ActuallyHurt attackImpl$actuallyHurt; + protected DamageEventUtil.DamageEventResult attackImpl$actuallyHurtResult; + protected float attackImpl$actuallyHurtFinalDamage; + protected boolean attackImpl$actuallyHurtCancelled; + protected float attackImpl$actuallyHurtBlockedDamage; + + /** + * Forge onLivingAttack Hook + */ + @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) + private void attackImpl$beforeHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { + if (source == null) { + new PrettyPrinter(60).centre().add("Null DamageSource").hr() + .addWrapped("Sponge has found a null damage source! This should NEVER happen " + + "as the DamageSource is used for all sorts of calculations. Usually" + + " this can be considered developer error. Please report the following" + + " stacktrace to the most appropriate mod/plugin available.") + .add() + .add(new IllegalArgumentException("Null DamageSource")) + .log(SpongeCommon.logger(), Level.WARN); + cir.setReturnValue(false); + } + // Sponge - This hook is for forge use mainly + if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, damageTaken)) { + cir.setReturnValue(false); + } + } + + /** + * Prepare {@link org.spongepowered.common.util.DamageEventUtil.Hurt} for damage event + */ + @Inject(method = "hurt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;noActionTime:I")) + private void attackImpl$preventEarlyBlock1(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + this.attackImpl$hurt = new DamageEventUtil.Hurt($$0, new ArrayList<>()); + } + + /** + * Prevents shield usage before event + * Captures the blocked damage as a function + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtCurrentlyUsedShield(F)V")) + private void attackImpl$preventEarlyBlock1(final LivingEntity instance, final float damageToShield) { + // this.hurtCurrentlyUsedShield(damageToShield); + this.attackImpl$hurt.functions().add(DamageEventUtil.createShieldFunction(instance)); + } + + /** + * Prevents shield usage before event + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;blockUsingShield(Lnet/minecraft/world/entity/LivingEntity;)V")) + private void attackImpl$preventEarlyBlock2(final LivingEntity instance, final LivingEntity livingDamageSource) { + // this.blockUsingShield(livingDamageSource); + } + + /** + * Capture the bonus freezing damage as a function + */ + @Inject(method = "hurt", at = @At(value = "CONSTANT", args = "floatValue=5.0F")) + private void attackImpl$freezingBonus(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + this.attackImpl$hurt.functions().add(DamageEventUtil.createFreezingBonus((LivingEntity) (Object) this, $$0, 5.0F)); + } + + /** + * Prevents {@link #shadow$hurtHelmet} before the event + * Captures the hard hat damage reduction as a function + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtHelmet(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$hardHat(final LivingEntity instance, final DamageSource $$0, final float $$1) { + // this.hurtHelmet($$0, $$1); + this.attackImpl$hurt.functions().add(DamageEventUtil.createHardHatModifier(instance.getItemBySlot(EquipmentSlot.HEAD), 0.75F)); + } + + /** + * Capture the old values to reset if we end up cancelling or blocking. + */ + @Inject(method = "hurt", at = @At(value = "FIELD", + target = "Lnet/minecraft/world/entity/LivingEntity;walkAnimation:Lnet/minecraft/world/entity/WalkAnimationState;")) + private void attackImpl$beforeActuallyHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { + // Save old values + this.attackImpl$lastHurt = this.lastHurt; + this.attackImpl$InvulnerableTime = this.invulnerableTime; + this.attackImpl$actuallyHurtCancelled = false; + } + + /** + * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable. + */ + @Redirect(method = "hurt", + at = @At(value = "FIELD", ordinal = 0, + target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) + private float attackImpl$afterActuallyHurt(final LivingEntity instance) { + return 0; + } + + /** + * After calling #actuallyHurt (even when invulnerable), if cancelled return early or is still invulnerable + * and reset {@link #lastHurt} and {@link #invulnerableTime} + */ + @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, + at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 0, + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$afterActuallyHurt1(final DamageSource $$0, + final float damageTaken, + final CallbackInfoReturnable cir, + final float dealtDamage, + final boolean isBlocked + ) { + if (this.attackImpl$actuallyHurtCancelled || damageTaken <= this.lastHurt) { + this.invulnerableTime = this.attackImpl$InvulnerableTime; + this.lastHurt = this.attackImpl$lastHurt; + cir.setReturnValue(false); + } + } + + /** + * After calling #actuallyHurt, if cancelled return early + * Also reset values + */ + @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, + at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 1, + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$afterActuallyHurt2(final DamageSource $$0, + final float damageTaken, + final CallbackInfoReturnable cir, + final float dealtDamage, + final boolean isBlocked + ) { + if (this.attackImpl$actuallyHurtCancelled) { + this.invulnerableTime = this.attackImpl$InvulnerableTime; + cir.setReturnValue(false); + } + } + + + /** + * Set final damage after #actuallyHurt + */ + @ModifyVariable(method = "hurt", argsOnly = true, + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", + shift = At.Shift.AFTER)) + private float attackImpl$modifyDamageTaken(float damageTaken) { + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Sets blocked damage after #actuallyHurt + */ + @ModifyVariable(method = "hurt", ordinal = 2, + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", + shift = At.Shift.AFTER)) + private float attackImpl$modifyBlockedDamage(float damageBlocked) { + return this.attackImpl$actuallyHurtBlockedDamage; + } + + @ModifyConstant(method = "hurt", constant = @Constant(classValue = Wolf.class, ordinal = 0)) + private Class attackImpl$onWolfCast(final Object entity, final Class wolf) { + // TODO for forge? check if this is actually working + return TamableAnimal.class; + } + + @Redirect(method = "hurt", + at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;isTame()Z")) + private boolean attackImpl$onWolfIsTame(@Coerce final Object instance) { + // TODO for forge? check if this is actually working + return ((TamableAnimal)instance).isTame(); + } + + @Redirect(method = "hurt", + at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;getOwner()Lnet/minecraft/world/entity/LivingEntity;")) + private LivingEntity attackImpl$onWolfGetOwner(@Coerce final Object instance) { + // TODO for forge? check if this is actually working + return ((TamableAnimal)instance).getOwner(); + } + + + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;playHurtSound(Lnet/minecraft/world/damagesource/DamageSource;)V")) + private void attackImpl$onHurtSound(final LivingEntity instance, final DamageSource $$0) { + if (this.bridge$vanishState().createsSounds()) { + this.shadow$playHurtSound($$0); + } + } + + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;makeSound(Lnet/minecraft/sounds/SoundEvent;)V")) + private void attackImpl$onMakeSound(final LivingEntity instance, final SoundEvent $$0) { + if (this.bridge$vanishState().createsSounds()) { + instance.makeSound($$0); + } + } + + @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) + public boolean attackImpl$startActuallyHurt(final LivingEntity instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { + if (instance.isInvulnerableTo(damageSource)) { + return true; + } + // Call platform hook for adjusting damage + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + // TODO check for direct call? + this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); + return false; + } + + /** + * Prevents LivingEntity#hurtArmor from running before event + * and capture the armor absorption as a function + */ + @Redirect(method = "getDamageAfterArmorAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtArmor(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + public void attackImpl$onDamageAfterArmorAbsorb(final LivingEntity instance, final DamageSource $$0, final float $$1) { + if (this.attackImpl$actuallyHurt != null) { + // prevents this.hurtArmor($$0, $$1); + // $$1 = CombatRules.getDamageAfterAbsorb(this, $$1, $$0, (float)this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); + var func = DamageEventUtil.createArmorModifiers(instance, this.attackImpl$actuallyHurt.dmgSource()); + this.attackImpl$actuallyHurt.functions().add(func); + } + } + + /** + * Captures the damage resistance as a function + */ + @Inject(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getEffect(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/effect/MobEffectInstance;")) + public void attackImpl$onDamageAfterMagicAbsorb(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + if (this.attackImpl$actuallyHurt != null) { + var func = DamageEventUtil.createResistanceModifier(this.attackImpl$actuallyHurt.entity()); + this.attackImpl$actuallyHurt.functions().add(func); + } + } + + /** + * Prevents {@link ServerPlayer#awardStat} from running before event + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/resources/ResourceLocation;I)V")) + public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final ResourceLocation resourceLocation, final int i) { + // do nothing + } + + /** + * Captures the damage protection as a function + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/CombatRules;getDamageAfterMagicAbsorb(FF)F")) + public float attackImpl$onDetDamageProtection(final float damage, final float protection) { + if (this.attackImpl$actuallyHurt != null) { + var func = DamageEventUtil.createEnchantmentModifiers(this.attackImpl$actuallyHurt.entity(), protection); + this.attackImpl$actuallyHurt.functions().add(func); + } + return CombatRules.getDamageAfterMagicAbsorb(damage, protection); + } + + /** + * Prevents setting absorption before event + * Captures the absorption amount as a functions + * Then calls the DamageEntityEvent + */ + @Inject(method = "setAbsorptionAmount", cancellable = true, at = @At("HEAD")) + public void attackImpl$onSetAbsorptionAmount(final float newAmount, final CallbackInfo ci) { + if (this.attackImpl$actuallyHurt != null) { + ci.cancel(); // Always cancel this + var oldAmount = this.shadow$getAbsorptionAmount(); + if (oldAmount > 0) { + var func = DamageEventUtil.createAbsorptionModifier(this.attackImpl$actuallyHurt.entity(), oldAmount); + this.attackImpl$actuallyHurt.functions().add(func); + } + + this.attackImpl$actuallyHurtResult = DamageEventUtil.callLivingDamageEntityEvent(this.attackImpl$hurt, this.attackImpl$actuallyHurt); + this.attackImpl$actuallyHurt = null; + + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + this.attackImpl$actuallyHurtCancelled = true; + this.attackImpl$actuallyHurtFinalDamage = 0; + this.attackImpl$actuallyHurtBlockedDamage = 0; + return; // Cancel vanilla behaviour by setting absorbed & finalDamage to 0 + } + + // TODO is this actually wrong? we are actually after functions + // (old comment was: Allow the platform to adjust damage before applying armor/etc) + this.attackImpl$actuallyHurtFinalDamage = this.bridge$applyModDamageBeforeFunctions( + (LivingEntity) (Object) (this), + this.attackImpl$actuallyHurtResult.source(), + (float) this.attackImpl$actuallyHurtResult.event().finalDamage()); + + this.attackImpl$actuallyHurtResult.damageAbsorbed().ifPresent(absorbed -> this.setAbsorptionAmount(oldAmount - absorbed)); + this.attackImpl$actuallyHurtBlockedDamage = this.attackImpl$actuallyHurtResult.damageBlockedByShield().orElse(0f); + } + } + + /** + * Set final damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 1, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0, shift = At.Shift.AFTER)) + public float attackImpl$setFinalDamage(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Set absorbed damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 2, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0)), + at = @At(value = "STORE", ordinal = 0)) + public float attackImpl$setAbsorbed(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); + } + + /** + * Replay prevented + * {@link #shadow$hurtCurrentlyUsedShield} and {@link #shadow$blockUsingShield} + * {@link #shadow$hurtHelmet} + * {@link #shadow$hurtArmor} + * {@link ServerPlayer#awardStat} for {@link Stats#DAMAGE_RESISTED} and {@link Stats#DAMAGE_DEALT} + * from {@link LivingEntity#hurt} and #actuallyHurt + * + * And capture inventory changes if needed + */ + @Inject(method = "setHealth", at = @At("HEAD")) + public void attackImpl$afterActuallyHurtEvent(final float $$0, final CallbackInfo ci) { + final var result = this.attackImpl$actuallyHurtResult; + if (result != null) { + final var damageSource = result.source(); + result.damageToShield().ifPresent(dmg -> { + this.shadow$hurtCurrentlyUsedShield(dmg); + if (!damageSource.is(DamageTypeTags.IS_PROJECTILE)) { + if (damageSource.getDirectEntity() instanceof LivingEntity livingSource) { + this.shadow$blockUsingShield(livingSource); + } + } + }); + result.damageToHelmet().ifPresent(dmg -> + this.shadow$hurtHelmet(damageSource, dmg)); + result.damageToArmor().ifPresent(dmg -> + this.shadow$hurtArmor(damageSource, dmg)); + result.damageResisted().ifPresent(dmg -> { + if ((Object) this instanceof ServerPlayer player) { + player.awardStat(Stats.DAMAGE_RESISTED, Math.round(dmg * 10.0F)); + } else if (damageSource.getEntity() instanceof ServerPlayer player) { + player.awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(dmg * 10.0F)); + } + }); + + // Capture inventory change if we modified stacks + if ((result.damageToShield().isPresent() || + result.damageToHelmet().isPresent() || + result.damageToArmor().isPresent()) + && (Object) this instanceof Player player) { + PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange(player, PlayerInventoryTransaction.EventCreator.STANDARD); + player.inventoryMenu.broadcastChanges(); // capture + } + } + } + + /** + * Cleanup + * also reverts {@link #attackImpl$beforeActuallyHurt} + */ + @Inject(method = "actuallyHurt", at = @At("RETURN")) + public void attackImpl$cleanupActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$actuallyHurt = null; + this.attackImpl$actuallyHurtResult = null; + this.lastHurt = this.attackImpl$lastHurt; + } + +} diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java new file mode 100644 index 00000000000..4944659bdae --- /dev/null +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java @@ -0,0 +1,77 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.mixin.core.world.entity; + +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attribute; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.common.util.DamageEventUtil; + +import java.util.ArrayList; + +@Mixin(Mob.class) +public abstract class MobMixin_Attack_Impl extends LivingEntityMixin_Attack_impl { + + private double impl$hurtTargetDamage; + private double impl$knockbackModifier; + + @Redirect(method = "doHurtTarget", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/Mob;getAttributeValue(Lnet/minecraft/core/Holder;)D")) + private double attackImpl$onCanGrief(final Mob instance, final Holder attackDamageAttribute) { + this.impl$hurtTargetDamage = instance.getAttributeValue(attackDamageAttribute); + return this.impl$hurtTargetDamage; + } + + @Redirect(method = "doHurtTarget", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")) + private boolean attackImpl$onCanGrief(final net.minecraft.world.entity.Entity targetEntity, final DamageSource damageSource, final float mcFinalDamage) { + final var thisEntity = (Mob) (Object) this; + + float knockbackModifier = this.shadow$getKnockback(targetEntity, damageSource); + + var attack = new DamageEventUtil.Attack<>(thisEntity, targetEntity, thisEntity.getWeaponItem(), damageSource, 1, (float) this.impl$hurtTargetDamage, new ArrayList<>()); + if (thisEntity.level() instanceof ServerLevel) { + // baseDamage = EnchantmentHelper.modifyDamage(level, thisEntity.getWeaponItem(), targetEntity, damageSource, baseDamage);// + attack.functions().addAll(DamageEventUtil.createAttackEnchantmentFunction(attack.weapon(), targetEntity, damageSource)); + } + + final var event = DamageEventUtil.callMobAttackEvent(attack, knockbackModifier); + this.impl$knockbackModifier = event.knockbackModifier(); + + return targetEntity.hurt(damageSource, (float) event.finalOutputDamage()); + } + + @Redirect(method = "doHurtTarget", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/Mob;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) + private float attackImpl$onCanGrief(final Mob instance, final net.minecraft.world.entity.Entity entity, final DamageSource damageSource) { + return (float) this.impl$knockbackModifier; + } + +} diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java new file mode 100644 index 00000000000..b828f962de7 --- /dev/null +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -0,0 +1,425 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.mixin.core.world.entity.player; + +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.objectweb.asm.Opcodes; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.event.entity.AttackEntityEvent; +import org.spongepowered.api.event.impl.entity.AbstractModifierEvent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.hooks.PlatformHooks; +import org.spongepowered.common.util.DamageEventUtil; +import org.spongepowered.vanilla.mixin.core.world.entity.LivingEntityMixin_Attack_impl; + +import java.util.ArrayList; +import java.util.Map; + +@SuppressWarnings("ConstantConditions") +@Mixin(value = Player.class, priority = 900) +public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_impl { + + //@formatter:off + @Shadow @Final public InventoryMenu inventoryMenu; + @Shadow public abstract float shadow$getAttackStrengthScale(final float $$0); + + //@formatter:on + + private void impl$playAttackSound(Player thisPlayer, SoundEvent sound) { + if (this.bridge$vanishState().createsSounds()) { + thisPlayer.level().playSound(null, thisPlayer.getX(), thisPlayer.getY(), thisPlayer.getZ(), sound, thisPlayer.getSoundSource()); + } + } + + private DamageEventUtil.Attack attackImpl$attack; + private AttackEntityEvent attackImpl$attackEvent; + private Map attackImpl$finalDamageAmounts; + + private int attackImpl$attackStrengthTicker; + private boolean attackImpl$isStrongSprintAttack; + + /** + * Cleanup + */ + @Inject(method = "attack", at = @At("RETURN")) + public void attackImpl$onReturnCleanup(final Entity $$0, final CallbackInfo ci) { + this.attackImpl$attack = null; + this.attackImpl$attackEvent = null; + this.attackImpl$finalDamageAmounts = null; + } + + /** + * checkAttackEntity Hook + */ + @Inject(method = "attack", cancellable = true, at = @At("HEAD")) + public void attackImpl$beforeAttackStart(final Entity target, final CallbackInfo ci){ + final var thisPlayer = (Player) (Object) this; + if (!PlatformHooks.INSTANCE.getEntityHooks().checkAttackEntity(thisPlayer, target)) { + ci.cancel(); + } + } + + /** + * Captures the base damage for the {@link AttackEntityEvent} in {@link #attackImpl$attack} + * and the {@link #attackStrengthTicker} in case we need to roll it back. + * Reset {@link #attackImpl$isStrongSprintAttack} + */ + @Inject(method = "attack", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F", shift = At.Shift.BEFORE)) + public void attackImpl$captureAttackStart(final Entity target, final CallbackInfo ci, final float baseDamage, final ItemStack weapon, final DamageSource source) { + final var strengthScale = this.shadow$getAttackStrengthScale(0.5F); + this.attackImpl$attack = new DamageEventUtil.Attack<>((Player) (Object) this, target, weapon, source, strengthScale, baseDamage, new ArrayList<>()); + this.attackImpl$attackStrengthTicker = this.attackStrengthTicker; + this.attackImpl$isStrongSprintAttack = false; + } + + /** + * Captures the enchantment damage calculations as functions + */ + @Inject(method = "attack", at = @At(value = "INVOKE", ordinal = 0, + target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public void attackImpl$enchanttDamageFunc(final Entity $$0, final CallbackInfo ci) { + final var weapon = this.attackImpl$attack.weapon(); + // this.getEnchantedDamage(targetEntity, damage, damageSource) - damage; + final var functions = DamageEventUtil.createAttackEnchantmentFunction(weapon, this.attackImpl$attack.target(), this.attackImpl$attack.dmgSource()); + final var separateFunc = DamageEventUtil.provideSeparateEnchantmentFromBaseDamageFunction(this.attackImpl$attack.baseDamage(), weapon); + // enchantmentDamage *= attackStrength; + final var strengthScaleFunc = DamageEventUtil.provideCooldownEnchantmentStrengthFunction(weapon, this.attackImpl$attack.strengthScale()); + + this.attackImpl$attack.functions().addAll(functions); + this.attackImpl$attack.functions().add(separateFunc); + this.attackImpl$attack.functions().add(strengthScaleFunc); + } + + + /** + * Captures the attack-strength damage scaling as a function + */ + @Inject(method = "attack", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;resetAttackStrengthTicker()V")) + public void attackImpl$attackStrengthScalingDamageFunc(final Entity $$0, final CallbackInfo ci) { + // damage *= 0.2F + attackStrength * attackStrength * 0.8F; + final var strengthScaleFunc = DamageEventUtil.provideCooldownAttackStrengthFunction((Player) (Object) this, this.attackImpl$attack.strengthScale()); + this.attackImpl$attack.functions().add(strengthScaleFunc); + } + + /** + * Prevents the {@link SoundEvents#PLAYER_ATTACK_KNOCKBACK} from playing before the event. + * Captures if {@link #attackImpl$isStrongSprintAttack} for later + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 0), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + public void attackImpl$preventSprintingAttackSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, final SoundEvent $$4, + final SoundSource $$5, final float $$6, final float $$7) { + // prevent sound + this.attackImpl$isStrongSprintAttack = true; + } + + /** + * Captures the weapon bonus damage as a function + */ + @Inject(method = "attack", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public void attackImpl$attackDamageFunc(final Entity $$0, final CallbackInfo ci) { + // damage += weaponItem.getItem().getAttackDamageBonus(targetEntity, damage, damageSource); + final var bonusDamageFunc = DamageEventUtil.provideWeaponAttackDamageBonusFunction( this.attackImpl$attack.target(), this.attackImpl$attack.weapon(), this.attackImpl$attack.dmgSource()); + this.attackImpl$attack.functions().add(bonusDamageFunc); + } + + /** + * Crit Hook - Before vanilla decides + * Also captures the crit multiplier as a function + */ + @ModifyVariable(method = "attack", ordinal = 2, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 1), + to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;walkDist:F")), + at = @At(value = "JUMP", opcode = Opcodes.IFEQ) + ) + public boolean attackImpl$critHook(final boolean isCrit) { + final var critResult = PlatformHooks.INSTANCE.getEventHooks().callCriticalHitEvent(this.attackImpl$attack.sourceEntity(), + this.attackImpl$attack.target(), isCrit, isCrit ? 1.5F : 1.0F); + + // if (isCrit) damage *= 1.5F; + if (critResult.criticalHit) { + final var bonusDamageFunc = DamageEventUtil.provideCriticalAttackFunction(this.attackImpl$attack.sourceEntity(), critResult.modifier); + this.attackImpl$attack.functions().add(bonusDamageFunc); + } + + return critResult.criticalHit; + } + + /** + * Sweep Hook - Redirects instanceOf SwordItem + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getHealth()F", ordinal = 0)), + at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/item/SwordItem")) + public boolean attackImpl$sweepHook(final Object instance, final Class type) { + var stack = this.shadow$getItemInHand(InteractionHand.MAIN_HAND); + return PlatformHooks.INSTANCE.getItemHooks().canPerformSweepAttack(stack); + } + + /** + * Capture damageSource for sweep attacks event later + * Calculate knockback earlier than vanilla for event + * call the AttackEntityEvent + * Play prevented sound from {@link #attackImpl$preventSprintingAttackSound} + * returns false if canceled, appearing for vanilla as an invulnerable target. {@link #attackImpl$onNoDamageSound} + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getDeltaMovement()Lnet/minecraft/world/phys/Vec3;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")) + public boolean attackImpl$onHurt(final Entity targetEntity, final DamageSource damageSource, final float mcDamage) { + + float knockbackModifier = this.shadow$getKnockback(targetEntity, damageSource) + (this.attackImpl$isStrongSprintAttack ? 1.0F : 0.0F); + this.attackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(this.attackImpl$attack, knockbackModifier); + + if (this.attackImpl$attackEvent.isCancelled()) { + // TODO this is actually not really doing anything because a ServerboundSwingPacket also resets it immediatly after + this.attackStrengthTicker = this.attackImpl$attackStrengthTicker; // Reset to old value + return false; + } + + this.attackImpl$finalDamageAmounts = AbstractModifierEvent.finalAmounts(this.attackImpl$attackEvent.originalDamage(), this.attackImpl$attackEvent.modifiers()); + + if (this.attackImpl$isStrongSprintAttack) { + // Play prevented sprint attack sound + this.impl$playAttackSound(this.attackImpl$attack.sourceEntity(), SoundEvents.PLAYER_ATTACK_KNOCKBACK); + } + + return targetEntity.hurt(damageSource, (float) this.attackImpl$attackEvent.finalOutputDamage()); + } + + /** + * Set enchantment damage with value from event + */ + @ModifyVariable(method = "attack", ordinal = 1, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V", ordinal = 0)), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$enchentmentDamageFromEvent(final float enchDmg) { + return this.attackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_enchantment"), 0.0).floatValue(); + } + + /** + * Redirects Player#getKnockback to the attack event value + */ + @Redirect(method = "attack", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$sweepHook(final Player instance, final Entity entity, final DamageSource damageSource) { + return this.attackImpl$attackEvent.knockbackModifier(); + } + + /** + * Prevents the {@link SoundEvents#PLAYER_ATTACK_NODAMAGE} when event was canceled + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;causeFoodExhaustion(F)V")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + public void attackImpl$onNoDamageSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, + final SoundEvent $$4, final SoundSource $$5, final float $$6, final float $$7) { + if (!this.attackImpl$attackEvent.isCancelled()) { + this.impl$playAttackSound($$0, SoundEvents.PLAYER_ATTACK_NODAMAGE); + } + } + + /** + * Sweep hit box Hook + */ + @Redirect(method = "attack", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/AABB;inflate(DDD)Lnet/minecraft/world/phys/AABB;")) + public AABB attackImpl$onSweepHitBox(final AABB instance, final double $$0, final double $$1, final double $$2) { + final var thisPlayer = (Player) (Object) this; + return PlatformHooks.INSTANCE.getItemHooks().getSweepingHitBox(thisPlayer, thisPlayer.getWeaponItem(), this.attackImpl$attack.target()); + } + + /** + * Call Sweep Attack Events + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;distanceToSqr(Lnet/minecraft/world/entity/Entity;)D")) + public double attackImpl$beforeSweepHurt(final Player instance, final Entity sweepTarget) { + final var distanceToSqr = instance.distanceToSqr(sweepTarget); + if (!(distanceToSqr < 9.0)) { + return distanceToSqr; // Too far - no event + } + + final var mainAttack = this.attackImpl$attack; + final var mainAttackDamage = this.attackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_damage"), 0.0).floatValue(); + + var sweepAttack = new DamageEventUtil.Attack<>(mainAttack.sourceEntity(), sweepTarget, mainAttack.weapon(), mainAttack.dmgSource(), mainAttack.strengthScale(), 1, new ArrayList<>()); + // float sweepBaseDamage = 1.0F + (float)this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * attackDamage; + sweepAttack.functions().add(DamageEventUtil.provideSweepingDamageRatioFunction(mainAttack.weapon(), mainAttack.sourceEntity(), mainAttackDamage)); + // float sweepFullDamage = this.getEnchantedDamage(sweepTarget, sweepBaseDamage, $$3) * strengthScale; + sweepAttack.functions().addAll(DamageEventUtil.createAttackEnchantmentFunction(mainAttack.weapon(), sweepTarget, mainAttack.dmgSource())); + sweepAttack.functions().add(DamageEventUtil.provideCooldownEnchantmentStrengthFunction(mainAttack.weapon(), mainAttack.strengthScale())); + + this.attackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(sweepAttack, 1.0F); + if (attackImpl$attackEvent.isCancelled()) { + return Double.MAX_VALUE; + } + + return distanceToSqr; + } + + /** + * Redirect Player#getEnchantedDamage to sweep event value + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$beforeSweepHurt(final Player instance, final Entity $$0, final float $$1, final DamageSource $$2) { + return (float) this.attackImpl$attackEvent.finalOutputDamage(); + } + + /** + * Redirect {@link LivingEntity#knockback} to use modified event knockback + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V")) + public void attackImpl$modifyKnockback(final LivingEntity instance, final double $$0, final double $$1, final double $$2) { + instance.knockback($$0 * this.attackImpl$attackEvent.knockbackModifier(), $$1, $$2); + } + + + /** + * Prevent vanilla {@link net.minecraft.world.entity.boss.EnderDragonPart#parentMob} resolution + * We use {@link #attackImpl$parentPartsHook} instead + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setLastHurtMob(Lnet/minecraft/world/entity/Entity;)V"), + to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;")), + at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/entity/boss/EnderDragonPart", ordinal = 0)) + public boolean attackImpl$parentPartsHookInstanceOf(final Object instance, final Class type) { + return false; + } + + /** + * Hook parent part resolution + */ + @ModifyVariable(method = "attack", ordinal = 1, + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;hurtEnemy(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/player/Player;)Z")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;level()Lnet/minecraft/world/level/Level;")) + public Entity attackImpl$parentPartsHook(final Entity entity) { + return PlatformHooks.INSTANCE.getEntityHooks().getParentPart(entity); + } + + /** + * Captures inventory changes + */ + @Redirect(method = "attack", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setItemInHand(Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;)V")) + public void attackImpl$causeInventoryCapture(final Player instance, final InteractionHand interactionHand, final ItemStack stack) { + instance.setItemInHand(interactionHand, stack); + + // Capture... + final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); + final TransactionalCaptureSupplier transactor = context.getTransactor(); + transactor.logPlayerInventoryChange(instance, PlayerInventoryTransaction.EventCreator.STANDARD); + this.inventoryMenu.broadcastChanges(); + } + + @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) + public boolean attackImpl$startActuallyHurt(final Player instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { + if (instance.isInvulnerableTo(damageSource)) { + return true; + } + // Call platform hook for adjusting damage + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + // TODO check for direct call? + this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); + return false; + } + + /** + * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 1, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", shift = At.Shift.AFTER)) + public float attackImpl$setFinalDamage(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Set absorbed damage after calling {@link Player#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 2, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V")), + at = @At(value = "STORE", ordinal = 0)) + public float attackImpl$setAbsorbed(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); + } + + /** + * Cleanup + */ + @Inject(method = "actuallyHurt", at = @At("RETURN")) + public void attackImpl$afterActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$actuallyHurt = null; + this.attackImpl$actuallyHurtResult = null; + } + + +} diff --git a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json index a6a307e820c..c732b3254c0 100644 --- a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json +++ b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json @@ -35,10 +35,13 @@ "server.packs.repository.PackRepositoryMixin_Vanilla", "world.entity.EntityMixin_Vanilla", "world.entity.EntityTypeMixin_Vanilla", + "world.entity.LivingEntityMixin_Attack_impl", "world.entity.LivingEntityMixin_Vanilla", + "world.entity.MobMixin_Attack_Impl", "world.entity.ai.attributes.DefaultAttributesMixin", "world.entity.item.ItemEntityMixin_Vanilla", "world.entity.projectile.ThrownEnderpearlMixin_Vanilla", + "world.entity.player.PlayerMixin_Attack_Impl", "world.entity.vehicle.BoatMixin_Vanilla", "world.level.block.FireBlockMixin_Vanilla", "world.level.block.entity.AbstractFurnaceBlockEntityMixin_Vanilla", From 17be50e9f1b798f3112ec35a24f3503387e30c84 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 7 Jun 2024 16:52:43 +0200 Subject: [PATCH 040/226] Bump MC to 1.21-pre4 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cc65ed2634c..c75c62774b2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21-pre3 +minecraftVersion=1.21-pre4 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose From 0ca8af44751410868af76b92aa4e7629c3d44caa Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 7 Jun 2024 17:13:41 +0200 Subject: [PATCH 041/226] fix PrimedTntMixin --- .../core/world/entity/item/PrimedTntMixin.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/PrimedTntMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/PrimedTntMixin.java index 7e3354ea434..8f239cc52af 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/PrimedTntMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/item/PrimedTntMixin.java @@ -24,10 +24,12 @@ */ package org.spongepowered.common.mixin.core.world.entity.item; +import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.item.PrimedTnt; import net.minecraft.world.level.Explosion.BlockInteraction; +import net.minecraft.world.level.ExplosionDamageCalculator; import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.data.Keys; @@ -108,12 +110,17 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri method = "explode", at = @At( value = "INVOKE", - target = "Lnet/minecraft/world/level/Level;explode(Lnet/minecraft/world/entity/Entity;DDDFLnet/minecraft/world/level/Level$ExplosionInteraction;)Lnet/minecraft/world/level/Explosion;" + target = "Lnet/minecraft/world/level/Level;explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Level$ExplosionInteraction;)Lnet/minecraft/world/level/Explosion;" ) ) private net.minecraft.world.level.@Nullable Explosion impl$useSpongeExplosion(final Level world, - final Entity entityIn, final double xIn, final double yIn, final double zIn, final float explosionRadius, - final Level.ExplosionInteraction modeIn) { + final Entity entityIn, + final DamageSource damageSource, + final ExplosionDamageCalculator explosionDamageCalculator, + final double xIn, final double yIn, final double zIn, final + float explosionRadius, + final boolean falseValue, + final Level.ExplosionInteraction modeIn) { return SpongeCommonEventFactory.detonateExplosive(this, Explosion.builder() .location(ServerLocation.of((ServerWorld) world, xIn, yIn, zIn)) .sourceExplosive((PrimedTNT) this) From 1e4b87b98311c463d02cd7a7495e48f2e32849e6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 7 Jun 2024 19:54:20 +0200 Subject: [PATCH 042/226] fix WorldGenRegionMixin_API --- .../server/level/WorldGenRegionMixin_API.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/WorldGenRegionMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/WorldGenRegionMixin_API.java index c90a924d7f6..5f48b94a501 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/WorldGenRegionMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/WorldGenRegionMixin_API.java @@ -26,11 +26,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.ChunkPos; +import net.minecraft.util.StaticCache2D; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ImposterProtoChunk; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.ResourceKey; @@ -49,27 +49,28 @@ import org.spongepowered.common.world.storage.SpongeChunkLayout; import org.spongepowered.math.vector.Vector3i; -import java.util.List; - @Mixin(WorldGenRegion.class) public abstract class WorldGenRegionMixin_API implements GenerationRegion { // @formatter:off - @Shadow @Final private ChunkPos firstPos; - @Shadow @Final private ChunkPos lastPos; + @Shadow @Final private ServerLevel level; + @Shadow @Final private ChunkAccess center; + @Shadow @Final private ChunkStep generatingStep; @Shadow public abstract ChunkAccess shadow$getChunk(int param0, int param1); // @formatter:on - @Shadow @Final private ServerLevel level; + private ResourceKey api$serverWorldKey; + private @MonotonicNonNull Vector3i api$minChunk; + private @MonotonicNonNull Vector3i api$maxChunk; private @MonotonicNonNull Vector3i api$minBlock; private @MonotonicNonNull Vector3i api$maxBlock; private @MonotonicNonNull Vector3i api$size; @Inject(method = "", at = @At("RETURN")) - private void api$getWorldKeyOnConstruction(final ServerLevel param0, final List param1, final ChunkStatus param2, final int param3, + private void api$getWorldKeyOnConstruction(final ServerLevel $$0, final StaticCache2D $$1, final ChunkStep $$2, final ChunkAccess $$3, final CallbackInfo ci) { - this.api$serverWorldKey = (ResourceKey) (Object) param0.dimension().location(); + this.api$serverWorldKey = (ResourceKey) (Object) $$0.dimension().location(); } @Override @@ -103,12 +104,22 @@ public abstract class WorldGenRegionMixin_API implements GenerationRegion { @Override public @NonNull Vector3i chunkMin() { - return VecHelper.toVector3i(this.firstPos).min(VecHelper.toVector3i(this.lastPos)); + if (this.api$minChunk == null) { + final var center = this.center.getPos(); + final var radius = this.generatingStep.directDependencies().size(); + this.api$minChunk = VecHelper.toVector3i(center).sub(radius, 0, radius); + } + return this.api$minChunk; } @Override public @NonNull Vector3i chunkMax() { - return VecHelper.toVector3i(this.firstPos).max(VecHelper.toVector3i(this.lastPos)); + if (this.api$maxChunk == null) { + final var center = this.center.getPos(); + final var radius = this.generatingStep.directDependencies().size(); + this.api$maxChunk = VecHelper.toVector3i(center).add(radius, 0, radius); + } + return this.api$maxChunk; } @Override From 7d4857452b18ab684e16cc453d0207a3864a5c74 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 15:37:11 +0200 Subject: [PATCH 043/226] portals & dimension changing --- SpongeAPI | 2 +- .../server/level/ServerPlayerMixin_Forge.java | 17 - .../accessor/world/entity/EntityAccessor.java | 26 - .../entity/PortalProcessorAccessor.java} | 25 +- .../resources/mixins.sponge.accessors.json | 135 +-- .../bridge/world/entity/EntityBridge.java | 5 +- .../world/entity/PortalProcessorBridge.java} | 11 +- .../world/level/block/PortalBlockBridge.java} | 24 +- .../data/provider/entity/EntityData.java | 14 + .../common/entity/EntityUtil.java | 91 -- .../context/transaction/TransactionSink.java | 11 + .../transaction/WrapperTransaction.java | 82 ++ .../phase/entity/TeleportPhaseState.java | 6 + .../registry/SpongeBuilderProvider.java | 3 + .../registry/SpongeFactoryProvider.java | 3 + .../common/registry/SpongeRegistries.java | 1 - .../registry/loader/SpongeRegistryLoader.java | 13 - .../common/world/portal/NetherPortalType.java | 204 ---- .../common/world/portal/PortalHelper.java | 192 ---- .../common/world/portal/PortalLogic.java | 53 - .../portal/SpongeCompositePortalLogic.java | 99 ++ .../world/portal/SpongeCustomPortalLogic.java | 110 ++ ...e.java => SpongeEndPlatformGenerator.java} | 30 +- .../SpongeNetherPortalExitCalculator.java | 75 ++ .../{VanillaPortal.java => SpongePortal.java} | 41 +- .../portal/SpongePortalLogicBuilder.java | 67 ++ .../portal/SpongePortalLogicFactory.java | 107 ++ .../world/portal/SpongeSpawnPortalFinder.java | 71 ++ ...tal.java => SpongeTargetPortalFinder.java} | 34 +- .../world/portal/VanillaPortalLogic.java | 80 -- .../entity/PortalProcessorMixin_API.java} | 53 +- .../minecraft/world/level/LevelMixin_API.java | 5 - .../world/level/block/PortalMixin_API.java | 70 ++ .../core/server/level/ServerPlayerMixin.java | 411 ++++---- .../core/server/players/PlayerListMixin.java | 45 +- .../mixin/core/world/entity/EntityMixin.java | 549 +++------- .../world/entity/PortalProcessorMixin.java | 166 +++ .../core/world/entity/player/PlayerMixin.java | 13 +- .../projectile/ThrowableProjectileMixin.java | 26 - .../projectile/ThrownEnderpearlMixin.java | 49 +- .../AbstractMinecartContainerMixin.java | 17 - .../level/block/EndPortalBlockMixin.java | 87 +- .../level/block/NetherPortalBlockMixin.java | 135 +++ .../entity/TheEndGatewayBlockEntityMixin.java | 68 -- .../entity/LivingEntityMixin_Tracker.java | 15 +- src/mixins/resources/mixins.sponge.api.json | 984 +++++++++--------- src/mixins/resources/mixins.sponge.core.json | 6 +- .../test/changeblock/ChangeBlockTest.java | 3 +- .../spongepowered/test/portal/PortalTest.java | 89 ++ .../test/portal/PortalTestListener.java | 53 - .../spongepowered/test/world/WorldTest.java | 20 +- .../level/ServerPlayerMixin_Vanilla.java | 24 - .../world/entity/EntityMixin_Vanilla.java | 16 - .../ThrownEnderpearlMixin_Vanilla.java | 44 - .../portal/PortalForcerMixin_Vanilla.java | 71 -- .../resources/mixins.spongevanilla.core.json | 2 - 56 files changed, 2240 insertions(+), 2413 deletions(-) rename src/{main/java/org/spongepowered/common/world/portal/SpongePortalInfo.java => accessors/java/org/spongepowered/common/accessor/world/entity/PortalProcessorAccessor.java} (69%) rename src/main/java/org/spongepowered/common/{world/portal/VanillaPortalType.java => bridge/world/entity/PortalProcessorBridge.java} (83%) rename src/main/java/org/spongepowered/common/{world/portal/UnknownPortalType.java => bridge/world/level/block/PortalBlockBridge.java} (71%) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/WrapperTransaction.java delete mode 100644 src/main/java/org/spongepowered/common/world/portal/NetherPortalType.java delete mode 100644 src/main/java/org/spongepowered/common/world/portal/PortalHelper.java delete mode 100644 src/main/java/org/spongepowered/common/world/portal/PortalLogic.java create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java rename src/main/java/org/spongepowered/common/world/portal/{EndPortalType.java => SpongeEndPlatformGenerator.java} (64%) create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java rename src/main/java/org/spongepowered/common/world/portal/{VanillaPortal.java => SpongePortal.java} (61%) create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongeSpawnPortalFinder.java rename src/main/java/org/spongepowered/common/world/portal/{VanillaTwoDimensionalPortal.java => SpongeTargetPortalFinder.java} (56%) delete mode 100644 src/main/java/org/spongepowered/common/world/portal/VanillaPortalLogic.java rename src/mixins/java/org/spongepowered/common/mixin/{core/world/level/portal/PortalShapeMixin.java => api/minecraft/world/entity/PortalProcessorMixin_API.java} (50%) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/entity/PortalProcessorMixin.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java delete mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/TheEndGatewayBlockEntityMixin.java delete mode 100644 testplugins/src/main/java/org/spongepowered/test/portal/PortalTestListener.java delete mode 100644 vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/projectile/ThrownEnderpearlMixin_Vanilla.java delete mode 100644 vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/portal/PortalForcerMixin_Vanilla.java diff --git a/SpongeAPI b/SpongeAPI index bd57cec8f88..c72f815e30d 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit bd57cec8f88f2ff1bf7aaf4cc594e64901b7c9d7 +Subproject commit c72f815e30dd3ac69f174a86ee5990c6579b9c4a diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java index 4ab735eb723..bf2ef7037c4 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java @@ -44,23 +44,6 @@ @Mixin(ServerPlayer.class) public abstract class ServerPlayerMixin_Forge extends LivingEntityMixin_Forge { - /** - * @author dualspiral - 18th December 2020 - 1.16.4 - * @reason Redirects the Forge changeDimension method to our own - * to support our event and other logic (see - * ServerPlayerEntityMixin on the common mixin sourceset for - * details). - * - * This will get called on the nether dimension changes, as the - * end portal teleport call itself has been redirected to provide - * the correct type. - */ - @Overwrite - @Nullable // should be javax.annotations.Nullable - public Entity changeDimension(final ServerLevel serverLevel, final ITeleporter teleporter) { - return ((EntityBridge) this).bridge$changeDimension(serverLevel, (PortalLogic) teleporter); - } - // override from LivingEntityMixin_Forge @Override protected void forge$onElytraUse(final CallbackInfo ci) { diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/EntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/EntityAccessor.java index 9317b5fe16f..538bfb02607 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/EntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/entity/EntityAccessor.java @@ -24,18 +24,11 @@ */ package org.spongepowered.common.accessor.world.entity; -import com.google.common.collect.ImmutableList; -import net.minecraft.BlockUtil; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.entity.EntityInLevelCallback; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -83,22 +76,9 @@ public interface EntityAccessor { @Accessor("random") RandomSource accessor$random(); - @Accessor("isInsidePortal") void accessor$isInsidePortal(final boolean isInsidePortal); - - @Accessor("portalTime") int accessor$portalTime(); - - @Accessor("portalTime") void accessor$portalTime(final int portalTime); - - @Accessor("portalEntrancePos") BlockPos accessor$portalEntrancePos(); - - @Accessor("portalEntrancePos") void accessor$portalEntrancePos(final BlockPos portalEntrancePos); - - @Accessor("passengers") ImmutableList accessor$passengers(); @Accessor("levelCallback") EntityInLevelCallback accessor$levelCallback(); - @Invoker("setRot") void invoker$setRot(final float yRot, final float xRot); - @Invoker("getEncodeId") @Nullable String invoker$getEncodeId(); @Invoker("removePassenger") void invoker$removePassenger(final Entity passenger); @@ -109,12 +89,6 @@ public interface EntityAccessor { @Invoker("getPermissionLevel") int invoker$getPermissionLevel(); - @Invoker("removeAfterChangingDimensions") void invoker$removeAfterChangingDimensions(); - - @Invoker("getRelativePortalPosition") Vec3 invoker$getRelativePortalPosition(Direction.Axis axis, BlockUtil.FoundRectangle result); - - @Invoker("findDimensionEntryPoint") PortalInfo invoker$findDimensionEntryPoint(ServerLevel targetWorld); - @Invoker("unsetRemoved") void invoker$unsetRemoved(); } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongePortalInfo.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/PortalProcessorAccessor.java similarity index 69% rename from src/main/java/org/spongepowered/common/world/portal/SpongePortalInfo.java rename to src/accessors/java/org/spongepowered/common/accessor/world/entity/PortalProcessorAccessor.java index 13f3d02ca33..6a2f283e939 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongePortalInfo.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/entity/PortalProcessorAccessor.java @@ -22,23 +22,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.world.portal; +package org.spongepowered.common.accessor.world.entity; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.api.world.portal.Portal; - -public final class SpongePortalInfo extends PortalInfo { - - private final Portal portal; - - public SpongePortalInfo(final Vec3 var1, final Vec3 var2, final float var3, final float var4, final Portal portal) { - super(var1, var2, var3, var4); - this.portal = portal; - } - - public Portal portal() { - return this.portal; - } +import net.minecraft.world.entity.PortalProcessor; +import net.minecraft.world.level.block.Portal; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +@Mixin(PortalProcessor.class) +public interface PortalProcessorAccessor { + @Accessor("portal") Portal accessor$portal(); } diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 053435c1c39..d3c3064e29a 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -68,6 +68,7 @@ "world.entity.LightningBoltAccessor", "world.entity.LivingEntityAccessor", "world.entity.MobAccessor", + "world.entity.PortalProcessorAccessor", "world.entity.ai.targeting.TargetingConditionsAccessor", "world.entity.animal.AnimalAccessor", "world.entity.animal.CatAccessor", @@ -135,72 +136,72 @@ "world.inventory.MerchantMenuAccessor", "world.inventory.ResultSlotAccessor", "world.inventory.SlotAccessor", - "world.item.AdventureModePredicateAccessor", - "world.item.ItemCooldowns_CooldownInstanceAccessor", - "world.item.component.CustomDataAccessor", - "world.item.enchantment.ItemEnchantmentsAccessor", - "world.item.trading.MerchantOfferAccessor", - "world.level.BaseCommandBlockAccessor", - "world.level.BaseSpawnerAccessor", - "world.level.ExplosionAccessor", - "world.level.GameRules_ValueAccessor", - "world.level.GameRulesAccessor", - "world.level.LevelAccessor", - "world.level.LevelSettingsAccessor", - "world.level.NaturalSpawner_SpawnStateAccessor", - "world.level.NaturalSpawnerAccessor", - "world.level.biome.Biome_ClimateSettingsAccessor", - "world.level.biome.BiomeAccessor", - "world.level.biome.MobSpawnSettingsAccessor", - "world.level.biome.MultiNoiseBiomeSourceAccessor", - "world.level.biome.OverworldBiomeBuilderAccessor", - "world.level.biome.TheEndBiomeSourceAccessor", - "world.level.block.AbstractSkullBlockAccessor", - "world.level.block.BaseFireBlockAccessor", - "world.level.block.BedBlockAccessor", - "world.level.block.CropBlockAccessor", - "world.level.block.DispenserBlockAccessor", - "world.level.block.EnderChestBlockAccessor", - "world.level.block.entity.AbstractFurnaceBlockEntityAccessor", - "world.level.block.entity.BaseContainerBlockEntityAccessor", - "world.level.block.entity.BeaconBlockEntityAccessor", - "world.level.block.entity.BlockEntityAccessor", - "world.level.block.entity.BrewingStandBlockEntityAccessor", - "world.level.block.entity.ConduitBlockEntityAccessor", - "world.level.block.entity.EnchantingTableBlockEntityAccessor", - "world.level.block.entity.HopperBlockEntityAccessor", - "world.level.block.entity.LecternBlockEntity_Accessor", - "world.level.block.entity.SkullBlockEntityAccessor", - "world.level.block.entity.SpawnerBlockEntityAccessor", - "world.level.block.entity.StructureBlockEntityAccessor", - "world.level.block.entity.TheEndGatewayBlockEntityAccessor", - "world.level.block.piston.PistonBaseBlockAccessor", - "world.level.block.state.BlockBehaviour_PropertiesAccessor", - "world.level.block.state.BlockBehaviourAccessor", - "world.level.block.state.StateHolderAccessor", - "world.level.border.WorldBorder_SettingsAccessor", - "world.level.border.WorldBorderAccessor", - "world.level.chunk.ChunkAccessAccessor", - "world.level.chunk.LevelChunk$BoundTickingBlockEntityAccessor", - "world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapperAccessor", - "world.level.chunk.LevelChunkAccessor", - "world.level.chunk.storage.ChunkStorageAccessor", - "world.level.chunk.storage.IOWorker$PendingStoreAccessor", - "world.level.chunk.storage.SimpleRegionStorageAccessor", - "world.level.dimension.DimensionTypeAccessor", - "world.level.entity.EntityTickListAccessor", - "world.level.entity.PersistentEntitySectionManagerAccessor", - "world.level.levelgen.NoiseSettingsAccessor", - "world.level.levelgen.flat.FlatLevelGeneratorSettingsAccessor", - "world.level.levelgen.structure.pools.StructureTemplatePoolAccessor", - "world.level.saveddata.maps.MapItemSavedDataAccessor", - "world.level.storage.LevelStorageSource_LevelStorageAccessAccessor", - "world.level.storage.PlayerDataStorageAccessor", - "world.phys.AABBAccessor", - "world.scores.PlayerTeamAccessor", - "world.scores.ScoreboardAccessor" - ], - "server": [ - "server.dedicated.DedicatedServerAccessor" + "world.item.AdventureModePredicateAccessor", + "world.item.ItemCooldowns_CooldownInstanceAccessor", + "world.item.component.CustomDataAccessor", + "world.item.enchantment.ItemEnchantmentsAccessor", + "world.item.trading.MerchantOfferAccessor", + "world.level.BaseCommandBlockAccessor", + "world.level.BaseSpawnerAccessor", + "world.level.ExplosionAccessor", + "world.level.GameRules_ValueAccessor", + "world.level.GameRulesAccessor", + "world.level.LevelAccessor", + "world.level.LevelSettingsAccessor", + "world.level.NaturalSpawner_SpawnStateAccessor", + "world.level.NaturalSpawnerAccessor", + "world.level.biome.Biome_ClimateSettingsAccessor", + "world.level.biome.BiomeAccessor", + "world.level.biome.MobSpawnSettingsAccessor", + "world.level.biome.MultiNoiseBiomeSourceAccessor", + "world.level.biome.OverworldBiomeBuilderAccessor", + "world.level.biome.TheEndBiomeSourceAccessor", + "world.level.block.AbstractSkullBlockAccessor", + "world.level.block.BaseFireBlockAccessor", + "world.level.block.BedBlockAccessor", + "world.level.block.CropBlockAccessor", + "world.level.block.DispenserBlockAccessor", + "world.level.block.EnderChestBlockAccessor", + "world.level.block.entity.AbstractFurnaceBlockEntityAccessor", + "world.level.block.entity.BaseContainerBlockEntityAccessor", + "world.level.block.entity.BeaconBlockEntityAccessor", + "world.level.block.entity.BlockEntityAccessor", + "world.level.block.entity.BrewingStandBlockEntityAccessor", + "world.level.block.entity.ConduitBlockEntityAccessor", + "world.level.block.entity.EnchantingTableBlockEntityAccessor", + "world.level.block.entity.HopperBlockEntityAccessor", + "world.level.block.entity.LecternBlockEntity_Accessor", + "world.level.block.entity.SkullBlockEntityAccessor", + "world.level.block.entity.SpawnerBlockEntityAccessor", + "world.level.block.entity.StructureBlockEntityAccessor", + "world.level.block.entity.TheEndGatewayBlockEntityAccessor", + "world.level.block.piston.PistonBaseBlockAccessor", + "world.level.block.state.BlockBehaviour_PropertiesAccessor", + "world.level.block.state.BlockBehaviourAccessor", + "world.level.block.state.StateHolderAccessor", + "world.level.border.WorldBorder_SettingsAccessor", + "world.level.border.WorldBorderAccessor", + "world.level.chunk.ChunkAccessAccessor", + "world.level.chunk.LevelChunk$BoundTickingBlockEntityAccessor", + "world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapperAccessor", + "world.level.chunk.LevelChunkAccessor", + "world.level.chunk.storage.ChunkStorageAccessor", + "world.level.chunk.storage.IOWorker$PendingStoreAccessor", + "world.level.chunk.storage.SimpleRegionStorageAccessor", + "world.level.dimension.DimensionTypeAccessor", + "world.level.entity.EntityTickListAccessor", + "world.level.entity.PersistentEntitySectionManagerAccessor", + "world.level.levelgen.NoiseSettingsAccessor", + "world.level.levelgen.flat.FlatLevelGeneratorSettingsAccessor", + "world.level.levelgen.structure.pools.StructureTemplatePoolAccessor", + "world.level.saveddata.maps.MapItemSavedDataAccessor", + "world.level.storage.LevelStorageSource_LevelStorageAccessAccessor", + "world.level.storage.PlayerDataStorageAccessor", + "world.phys.AABBAccessor", + "world.scores.PlayerTeamAccessor", + "world.scores.ScoreboardAccessor" + ], + "server": [ + "server.dedicated.DedicatedServerAccessor" ] } diff --git a/src/main/java/org/spongepowered/common/bridge/world/entity/EntityBridge.java b/src/main/java/org/spongepowered/common/bridge/world/entity/EntityBridge.java index 98481634d76..a8b41003978 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/entity/EntityBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/EntityBridge.java @@ -25,14 +25,13 @@ package org.spongepowered.common.bridge.world.entity; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.portal.DimensionTransition; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.event.cause.entity.DismountType; import org.spongepowered.api.event.entity.ChangeEntityWorldEvent; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.common.event.tracking.phase.tick.EntityTickContext; -import org.spongepowered.common.world.portal.PortalLogic; import org.spongepowered.math.vector.Vector3d; public interface EntityBridge { @@ -71,7 +70,7 @@ public interface EntityBridge { boolean bridge$dismountRidingEntity(DismountType type); - Entity bridge$changeDimension(ServerLevel targetWorld, PortalLogic teleporter); + Entity bridge$changeDimension(DimensionTransition transition); ChangeEntityWorldEvent.Reposition bridge$fireRepositionEvent(org.spongepowered.api.world.server.ServerWorld originalDestinationWorld, org.spongepowered.api.world.server.ServerWorld targetWorld, diff --git a/src/main/java/org/spongepowered/common/world/portal/VanillaPortalType.java b/src/main/java/org/spongepowered/common/bridge/world/entity/PortalProcessorBridge.java similarity index 83% rename from src/main/java/org/spongepowered/common/world/portal/VanillaPortalType.java rename to src/main/java/org/spongepowered/common/bridge/world/entity/PortalProcessorBridge.java index d0c2a377692..a79e25a76ea 100644 --- a/src/main/java/org/spongepowered/common/world/portal/VanillaPortalType.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/PortalProcessorBridge.java @@ -22,9 +22,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.world.portal; +package org.spongepowered.common.bridge.world.entity; -import org.spongepowered.api.world.portal.PortalType; +import net.minecraft.world.level.Level; -public abstract class VanillaPortalType implements PortalType { +public interface PortalProcessorBridge { + + void bridge$init(Level level); + Level bridge$level(); + + void bridge$setTransitionTime(Integer customTime); } diff --git a/src/main/java/org/spongepowered/common/world/portal/UnknownPortalType.java b/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java similarity index 71% rename from src/main/java/org/spongepowered/common/world/portal/UnknownPortalType.java rename to src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java index 860bdd01a8b..5a2e1182aae 100644 --- a/src/main/java/org/spongepowered/common/world/portal/UnknownPortalType.java +++ b/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java @@ -22,31 +22,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.world.portal; +package org.spongepowered.common.bridge.world.level.block; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.util.Axis; import org.spongepowered.api.world.portal.Portal; -import org.spongepowered.api.world.portal.PortalType; import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3i; import java.util.Optional; -public final class UnknownPortalType implements PortalType { +public interface PortalBlockBridge { - @Override - public boolean generatePortal(final ServerLocation location, final Axis axis) { - return false; - } - @Override - public Optional findPortal(final ServerLocation location) { - return Optional.empty(); - } + Optional bridge$calculatePortalExit(ServerWorld from, Vector3i fromPos, Entity entity); - @Override - public boolean teleport(final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { - return false; - } + Optional bridge$findPortal(ServerLocation at, int searchRange); + Optional bridge$generatePortal(ServerLocation location, Axis axis); + + boolean bridge$teleport(Entity entity, ServerLocation destination, boolean generateDestinationPortal); } diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index cc502984138..683eee50731 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -27,6 +27,7 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.entity.player.Player; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.data.DataTransactionResult; @@ -34,10 +35,14 @@ import org.spongepowered.api.data.type.PushReaction; import org.spongepowered.api.data.value.Value; import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.common.accessor.world.entity.EntityAccessor; +import org.spongepowered.common.accessor.world.entity.PortalProcessorAccessor; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.world.entity.EntityBridge; import org.spongepowered.common.bridge.world.entity.EntityMaxAirBridge; +import org.spongepowered.common.bridge.world.entity.PortalProcessorBridge; import org.spongepowered.common.data.provider.DataProviderRegistrator; import org.spongepowered.common.entity.SpongeEntityArchetype; import org.spongepowered.common.entity.SpongeEntitySnapshot; @@ -229,6 +234,15 @@ public static void register(final DataProviderRegistrator registrator) { m.hurtMarked = true; }) .supports(m -> m.getDeltaMovement().lengthSqr() > 0) + .create(Keys.PORTAL) + .get(h -> (Portal) h.portalProcess) + .create(Keys.PORTAL_LOGIC) + .get(h -> h.portalProcess == null ? null : (PortalLogic) ((PortalProcessorAccessor) h.portalProcess).accessor$portal()) + .set((h, v) -> { + h.portalProcess = new PortalProcessor((net.minecraft.world.level.block.Portal) v, h.blockPosition()); + ((PortalProcessorBridge)h.portalProcess).bridge$init(h.level()); + }) + .delete(h -> h.portalProcess = null) .asMutable(EntityMaxAirBridge.class) .create(Keys.MAX_AIR) .get(EntityMaxAirBridge::bridge$getMaxAir) diff --git a/src/main/java/org/spongepowered/common/entity/EntityUtil.java b/src/main/java/org/spongepowered/common/entity/EntityUtil.java index f88747561c6..fc2b54c7df8 100644 --- a/src/main/java/org/spongepowered/common/entity/EntityUtil.java +++ b/src/main/java/org/spongepowered/common/entity/EntityUtil.java @@ -24,36 +24,17 @@ */ package org.spongepowered.common.entity; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; -import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; -import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; -import net.minecraft.network.protocol.game.ClientboundRespawnPacket; -import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.players.PlayerList; import net.minecraft.util.Mth; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.storage.LevelData; import org.spongepowered.api.Sponge; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.entity.SpawnEntityEvent; -import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.common.accessor.server.level.ServerPlayerAccessor; -import org.spongepowered.common.accessor.server.network.ServerCommonPacketListenerImplAccessor; import org.spongepowered.common.accessor.world.entity.EntityAccessor; import org.spongepowered.common.bridge.CreatorTrackedBridge; import org.spongepowered.common.bridge.data.VanishableBridge; -import org.spongepowered.common.bridge.server.level.ServerLevelBridge; -import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; -import org.spongepowered.common.bridge.world.entity.PlatformEntityBridge; -import org.spongepowered.common.bridge.world.level.PlatformServerLevelBridge; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.math.vector.Vector3d; @@ -88,78 +69,6 @@ public static void despawnFilteredEntities(final Iterable orig } } - public static void performPostChangePlayerWorldLogic(final ServerPlayer player, final ServerLevel fromWorld, - final ServerLevel originalToWorld, final ServerLevel toWorld, final boolean isPortal) { - // Sponge Start - Send any platform dimension data - ((ServerPlayerBridge) player).bridge$sendDimensionData(((ServerCommonPacketListenerImplAccessor) player.connection).accessor$connection(), toWorld.dimensionType(), toWorld.dimension()); - // Sponge End - final LevelData worldinfo = toWorld.getLevelData(); - // We send dimension change for portals before loading chunks - if (!isPortal) { - // Sponge Start - Allow the platform to handle how dimension changes are sent down - ((ServerPlayerBridge) player).bridge$sendChangeDimension(toWorld.dimensionTypeRegistration(), toWorld.dimension(), BiomeManager.obfuscateSeed(toWorld.getSeed()), - player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), - toWorld.isDebug(), toWorld.isFlat(), ClientboundRespawnPacket.KEEP_ALL_DATA - ); - } - // Sponge End - player.connection.send(new ClientboundChangeDifficultyPacket(worldinfo.getDifficulty(), worldinfo.isDifficultyLocked())); - final PlayerList playerlist = player.getServer().getPlayerList(); - playerlist.sendPlayerPermissionLevel(player); - - // Sponge Start - Have the platform handle removing the entity from the world. Move this to after the event call so - // that we do not remove the player from the world unless we really have teleported.. - ((PlatformServerLevelBridge) fromWorld).bridge$removeEntity(player, Entity.RemovalReason.CHANGED_DIMENSION, true); - ((PlatformEntityBridge) player).bridge$revive(); - // Sponge End - - player.setServerLevel(toWorld); - toWorld.addDuringPortalTeleport(player); - if (isPortal) { - ((ServerPlayerAccessor) player).invoker$triggerDimensionChangeTriggers(toWorld); - } - player.gameMode.setLevel(toWorld); - player.connection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); - playerlist.sendLevelInfo(player, toWorld); - playerlist.sendAllPlayerInfo(player); - - for (final MobEffectInstance effectinstance : player.getActiveEffects()) { - player.connection.send(new ClientboundUpdateMobEffectPacket(player.getId(), effectinstance, false)); - } - - if (isPortal) { - player.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false)); - } - - ((ServerLevelBridge) fromWorld).bridge$getBossBarManager().onPlayerDisconnect(player); - ((ServerLevelBridge) toWorld).bridge$getBossBarManager().onPlayerDisconnect(player); - - ((ServerPlayerAccessor) player).accessor$lastSentExp(-1); - ((ServerPlayerAccessor) player).accessor$lastSentHealth(-1.0f); - ((ServerPlayerAccessor) player).accessor$lastSentFood(-1); - - if (!isPortal) { - player.connection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); - player.connection.resetPosition(); - } - - if (player.containerMenu != player.inventoryMenu) { - player.closeContainer(); - } - - // Sponge Start - Call event - Sponge.eventManager().post( - SpongeEventFactory.createChangeEntityWorldEventPost( - PhaseTracker.getCauseStackManager().currentCause(), - (org.spongepowered.api.entity.Entity) player, - (ServerWorld) fromWorld, - (ServerWorld) originalToWorld, - (ServerWorld) toWorld - ) - ); - // Sponge End - } - public static boolean processEntitySpawn(final org.spongepowered.api.entity.Entity entity, final Supplier> supplier, final Consumer spawner) { final Entity minecraftEntity = (Entity) entity; if (minecraftEntity instanceof ItemEntity) { diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java index baa4a79567a..da8863ac6b2 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java @@ -69,6 +69,7 @@ import org.spongepowered.common.event.tracking.context.transaction.block.RemoveBlockEntity; import org.spongepowered.common.event.tracking.context.transaction.block.ReplaceBlockEntity; import org.spongepowered.common.event.tracking.context.transaction.block.ScheduleUpdateTransaction; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockAddedEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.EntityPerformingDropsEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; @@ -218,6 +219,16 @@ default void logEntitySpawn( this.logTransaction(transaction); } + + @SuppressWarnings("ConstantConditions") + default WrapperTransaction logWrapper() { + final var transaction = new WrapperTransaction<>(); + this.logTransaction(transaction); + this.pushEffect(new ResultingTransactionBySideEffect(BlockAddedEffect.getInstance())); + return transaction; + } + + default boolean logTileReplacement( final BlockPos pos, final @Nullable BlockEntity existing, final @Nullable BlockEntity proposed, final Supplier worldSupplier diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/WrapperTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/WrapperTransaction.java new file mode 100644 index 00000000000..3bbf0101091 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/WrapperTransaction.java @@ -0,0 +1,82 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction; + +import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.spongepowered.api.event.Cancellable; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.Event; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.type.NoOpTransactionType; +import org.spongepowered.common.util.PrettyPrinter; + +import java.util.Optional; +import java.util.function.BiConsumer; + +@DefaultQualifier(NonNull.class) +public final class WrapperTransaction extends GameTransaction { + + public WrapperTransaction() { + super(new NoOpTransactionType<>(true, "wrapper")); + } + + @Override + public Optional, CauseStackManager.StackFrame>> getFrameMutator( + @Nullable final GameTransaction<@NonNull ?> parent) { + return Optional.empty(); + } + + @Override + public void addToPrinter(final PrettyPrinter printer) { + + } + + @Override + public Optional generateEvent(final PhaseContext<@NonNull ?> context, + @Nullable final GameTransaction<@NonNull ?> parent, + final ImmutableList> gameTransactions, final Cause currentCause) { + return Optional.empty(); + } + + @Override + public void restore(final PhaseContext<@NonNull ?> context, final T event) { + + } + + @Override + public boolean markCancelledTransactions(final T event, + final ImmutableList> gameTransactions) { + return true; + } + + @Override protected boolean shouldBuildEventAndRestartBatch(final GameTransaction<@NonNull ?> pointer, + final PhaseContext<@NonNull ?> context) { + return super.shouldBuildEventAndRestartBatch(pointer, context); + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/entity/TeleportPhaseState.java b/src/main/java/org/spongepowered/common/event/tracking/phase/entity/TeleportPhaseState.java index d2de230beef..995ec926675 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/entity/TeleportPhaseState.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/entity/TeleportPhaseState.java @@ -25,6 +25,7 @@ package org.spongepowered.common.event.tracking.phase.entity; import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.TrackingUtil; public final class TeleportPhaseState extends EntityPhaseState { @@ -33,4 +34,9 @@ protected TeleportContext createNewContext(PhaseTracker tracker) { return new TeleportContext(this, tracker); } + + @Override + public void unwind(final TeleportContext phaseContext) { + TrackingUtil.processBlockCaptures(phaseContext); + } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java index 8e8abd95466..c59958d6122 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java @@ -129,6 +129,7 @@ import org.spongepowered.api.world.generation.structure.StructureTemplate; import org.spongepowered.api.world.generation.structure.jigsaw.JigsawPoolTemplate; import org.spongepowered.api.world.generation.structure.jigsaw.ProcessorListTemplate; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.schematic.Schematic; import org.spongepowered.api.world.server.TicketType; @@ -233,6 +234,7 @@ import org.spongepowered.common.world.generation.structure.SpongeStructureTemplate; import org.spongepowered.common.world.generation.structure.jigsaw.SpongeJigsawPoolTemplate; import org.spongepowered.common.world.generation.structure.jigsaw.SpongeProcessorListTemplate; +import org.spongepowered.common.world.portal.SpongePortalLogicBuilder; import org.spongepowered.common.world.schematic.SpongePaletteTypeBuilder; import org.spongepowered.common.world.schematic.SpongeSchematicBuilder; import org.spongepowered.common.world.server.SpongeLocatableBlockBuilder; @@ -389,6 +391,7 @@ public void registerDefaultBuilders() { .register(ChatTypeTemplate.Builder.class, SpongeChatTypeTemplate.BuilderImpl::new) .register(DamageTypeTemplate.Builder.class, SpongeDamageTypeTemplate.BuilderImpl::new) .register(TicketType.Builder.class, SpongeTicketTypeBuilder::new) + .register(PortalLogic.Builder.class, SpongePortalLogicBuilder::new) ; } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java index 77e685ccdad..33d62e6a35f 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java @@ -93,6 +93,7 @@ import org.spongepowered.api.world.generation.config.SurfaceRule; import org.spongepowered.api.world.generation.config.flat.LayerConfig; import org.spongepowered.api.world.generation.structure.jigsaw.JigsawPoolElement; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.schematic.PaletteReference; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerLocationCreator; @@ -159,6 +160,7 @@ import org.spongepowered.common.world.generation.config.flat.SpongeLayerConfigFactory; import org.spongepowered.common.world.generation.config.noise.SpongeSurfaceRulesFactory; import org.spongepowered.common.world.generation.structure.jigsaw.SpongeJigsawFactory; +import org.spongepowered.common.world.portal.SpongePortalLogicFactory; import org.spongepowered.common.world.schematic.SpongePaletteReferenceFactory; import org.spongepowered.common.world.server.SpongeServerLocation; import org.spongepowered.common.world.server.SpongeServerLocationCreatorFactory; @@ -278,6 +280,7 @@ public void registerDefaultFactories() { .registerFactory(NaturalSpawner.Factory.class, new SpongeNaturalSpawnerFactory()) .registerFactory(ScoreFormat.Factory.class, new SpongeScoreFormatFactory()) .registerFactory(ToolRule.Factory.class, new SpongeToolRuleFactory()) + .registerFactory(PortalLogic.Factory.class, new SpongePortalLogicFactory()) ; } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java index 952d980de09..fcde5c162f6 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java @@ -72,7 +72,6 @@ public static void registerEarlyGlobalRegistries(final SpongeRegistryHolder hold holder.createFrozenRegistry(RegistryTypes.ORIENTATION, SpongeRegistryLoader.orientation()); holder.createFrozenRegistry(RegistryTypes.PALETTE_TYPE, SpongeRegistryLoader.paletteType()); holder.createFrozenRegistry(RegistryTypes.PARTICLE_OPTION, SpongeRegistryLoader.particleOption()); - holder.createFrozenRegistry(RegistryTypes.PORTAL_TYPE, SpongeRegistryLoader.portalType()); holder.createFrozenRegistry(RegistryTypes.QUERY_TYPE, SpongeRegistryLoader.queryType()); holder.createFrozenRegistry(RegistryTypes.RESOLVE_OPERATION, SpongeRegistryLoader.resolveOperation()); holder.createFrozenRegistry(RegistryTypes.SKIN_PART, SpongeRegistryLoader.skinPart()); diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index 07e4d25d1cd..fcc636dc77a 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -100,8 +100,6 @@ import org.spongepowered.api.world.generation.config.flat.FlatGeneratorConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfigs; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.PortalTypes; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.schematic.PaletteTypes; import org.spongepowered.api.world.weather.WeatherType; @@ -152,9 +150,6 @@ import org.spongepowered.common.registry.RegistryLoader; import org.spongepowered.common.util.SpongeOrientation; import org.spongepowered.common.world.SpongeChunkRegenerateFlag; -import org.spongepowered.common.world.portal.EndPortalType; -import org.spongepowered.common.world.portal.NetherPortalType; -import org.spongepowered.common.world.portal.UnknownPortalType; import org.spongepowered.common.world.schematic.SpongePaletteType; import org.spongepowered.common.world.weather.SpongeWeatherType; import org.spongepowered.math.vector.Vector3d; @@ -388,14 +383,6 @@ public static RegistryLoader> particleOption() { }); } - public static RegistryLoader portalType() { - return RegistryLoader.of(l -> { - l.add(PortalTypes.END, EndPortalType::new); - l.add(PortalTypes.NETHER, NetherPortalType::new); - l.add(PortalTypes.UNKNOWN, UnknownPortalType::new); - }); - } - public static RegistryLoader queryType() { return RegistryLoader.of(l -> { l.add(QueryTypes.GRID, k -> new SpongeTwoParamQueryType<>(GridQuery::new)); diff --git a/src/main/java/org/spongepowered/common/world/portal/NetherPortalType.java b/src/main/java/org/spongepowered/common/world/portal/NetherPortalType.java deleted file mode 100644 index 1aaf146aac2..00000000000 --- a/src/main/java/org/spongepowered/common/world/portal/NetherPortalType.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.world.portal; - -import net.minecraft.BlockUtil; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.level.portal.PortalShape; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.data.Keys; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.event.cause.entity.MovementType; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.event.entity.ChangeEntityWorldEvent; -import org.spongepowered.api.util.Axis; -import org.spongepowered.api.world.portal.Portal; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.PortalTypes; -import org.spongepowered.api.world.server.ServerLocation; -import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.common.accessor.world.entity.EntityAccessor; -import org.spongepowered.common.bridge.world.entity.EntityBridge; -import org.spongepowered.common.util.AxisUtil; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3d; - -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; - -public final class NetherPortalType extends VanillaPortalType { - - static Optional findPortalInternal(final ServerLocation location) { - final ServerLevel serverWorld = (ServerLevel) location.world(); - final BlockPos position = VecHelper.toBlockPos(location.blockPosition()); - return serverWorld.getPortalForcer() - .findPortalAround(position, serverWorld.dimension() == Level.NETHER, serverWorld.getWorldBorder()); - } - - public static Portal portalObjectFromRectangle(final ServerWorld world, final BlockUtil.FoundRectangle x) { - final Vector3d minCornerVec = VecHelper.toVector3d(x.minCorner); - final ServerLocation minCorner = world.location(minCornerVec); - final @Nullable Axis axis = minCorner.block().getOrNull(Keys.AXIS); - if (axis == null) { - return new VanillaPortal(PortalTypes.NETHER.get(), minCorner, null); - } - final ServerLocation maxCorner; - if (axis == Axis.X) { - maxCorner = minCorner.withPosition(minCornerVec.add(x.axis1Size, x.axis2Size, 0)); - } else { - // it's z - maxCorner = minCorner.withPosition(minCornerVec.add(0, x.axis2Size, x.axis1Size)); - } - return new VanillaTwoDimensionalPortal(PortalTypes.NETHER.get(), minCorner, maxCorner, null); - } - - @Override - public boolean generatePortal(final ServerLocation location, final Axis axis) { - Objects.requireNonNull(location); - Direction.Axis mcAxis = AxisUtil.getFor(axis); - if (mcAxis == Direction.Axis.Y) { - mcAxis = Direction.Axis.X; - } - PortalHelper.generateNetherPortal((ServerLevel) location.world(), location.blockX(), location.blockY(), location.blockZ(), mcAxis, true); - return true; - } - - @Override - public Optional findPortal(final ServerLocation location) { - Objects.requireNonNull(location); - return NetherPortalType.findPortalInternal(location).map(x -> NetherPortalType.portalObjectFromRectangle(location.world(), x)); - } - - @Override - public boolean teleport(final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { - Objects.requireNonNull(entity); - Objects.requireNonNull(destination); - - final net.minecraft.world.entity.Entity mEntity = (net.minecraft.world.entity.Entity) entity; - - // Nether Portal Block Collision Rules - if (mEntity.isPassenger() || mEntity.isVehicle() || !mEntity.canChangeDimensions()) { - return false; - } - - final PortalLogic teleporter = new Teleporter(destination, generateDestinationPortal, this); - - ((EntityAccessor) entity).accessor$portalEntrancePos(VecHelper.toBlockPos(entity.blockPosition())); - return ((EntityBridge) entity).bridge$changeDimension((ServerLevel) destination.world(), teleporter) != null; - - } - - static final class Teleporter implements PortalLogic { - - private final ServerLocation originalDestination; - private final boolean generateDestinationPortal; - private final PortalType portalType; - - public Teleporter(final ServerLocation originalDestination, final boolean generateDestinationPortal, final PortalType type) { - this.originalDestination = originalDestination; - this.generateDestinationPortal = generateDestinationPortal; - this.portalType = type; - } - - @Override - public @Nullable PortalInfo getPortalInfo(final net.minecraft.world.entity.Entity entity, - final ServerLevel targetWorld, - final Function defaultPortalInfo) { - Optional portal = NetherPortalType.findPortalInternal(this.originalDestination) - .map(x -> this.createNetherPortalInfo(entity, targetWorld, x.minCorner, x)); - - final Vector3d originalDestination = portal.map(x -> VecHelper.toVector3d(x.pos)).orElseGet(this.originalDestination::position); - final ChangeEntityWorldEvent.Reposition reposition = ((EntityBridge) entity).bridge$fireRepositionEvent( - this.originalDestination.world(), - (org.spongepowered.api.world.server.ServerWorld) targetWorld, - originalDestination - ); - if (!reposition.isCancelled() && reposition.destinationPosition() != originalDestination) { - // find another portal - portal = NetherPortalType.findPortalInternal(this.originalDestination.withPosition(reposition.destinationPosition())) - .map(x -> this.createNetherPortalInfo(entity, targetWorld, x.minCorner, x)); - } - - if (this.generateDestinationPortal && !portal.isPresent()) { - return targetWorld.getPortalForcer().createPortal(VecHelper.toBlockPos(this.originalDestination), - Direction.from2DDataValue(entity.getDirection().get2DDataValue()).getAxis()) - .map(x -> this.createNetherPortalInfo(entity, targetWorld, x.minCorner, x)) - .orElse(null); - } - - return portal.orElse(null); - } - - @Override - public net.minecraft.world.entity.Entity placeEntity(final net.minecraft.world.entity.Entity entity, final ServerLevel currentWorld, - final ServerLevel targetWorld, final float yRot, final Function teleportLogic) { - return teleportLogic.apply(false); - } - - @Override - public boolean isVanilla() { - return false; - } - - @Override - public MovementType getMovementType() { - return MovementTypes.PORTAL.get(); - } - - @Override - public PortalType getPortalType() { - return this.portalType; - } - - private PortalInfo createNetherPortalInfo( - final net.minecraft.world.entity.Entity entity, - final ServerLevel serverWorld, - final BlockPos portalLocation, - final BlockUtil.FoundRectangle result) { - final BlockState blockstate = serverWorld.getBlockState(portalLocation); - final Direction.Axis axis; - final net.minecraft.world.phys.Vec3 vector3d; - if (blockstate.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) { - axis = blockstate.getValue(BlockStateProperties.HORIZONTAL_AXIS); - final BlockUtil.FoundRectangle res = BlockUtil.getLargestRectangleAround(portalLocation, axis, 21, - Direction.Axis.Y, 21, (pos) -> serverWorld.getBlockState(pos) == blockstate); - vector3d = PortalShape.getRelativePosition(res, axis, entity.position(), entity.getDimensions(entity.getPose())); - } else { - axis = Direction.Axis.X; - vector3d = new net.minecraft.world.phys.Vec3(0.5D, 0.0D, 0.0D); - } - return PortalShape.createPortalInfo(serverWorld, result, axis, vector3d, entity, entity.getDeltaMovement(), entity.getYRot(), entity.getXRot()); - } - - } - -} diff --git a/src/main/java/org/spongepowered/common/world/portal/PortalHelper.java b/src/main/java/org/spongepowered/common/world/portal/PortalHelper.java deleted file mode 100644 index 50328c01f24..00000000000 --- a/src/main/java/org/spongepowered/common/world/portal/PortalHelper.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.world.portal; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.EndPortalFrameBlock; -import net.minecraft.world.level.block.NetherPortalBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.levelgen.Heightmap; - -// Because Vanilla doesn't move this stuff out... -public final class PortalHelper { - - private static final BlockState northEndFrame = Blocks.END_PORTAL_FRAME.defaultBlockState().setValue(EndPortalFrameBlock.FACING, Direction.NORTH); - private static final BlockState southEndFrame = Blocks.END_PORTAL_FRAME.defaultBlockState().setValue(EndPortalFrameBlock.FACING, Direction.SOUTH); - private static final BlockState eastEndFrame = Blocks.END_PORTAL_FRAME.defaultBlockState().setValue(EndPortalFrameBlock.FACING, Direction.EAST); - private static final BlockState westEndFrame = Blocks.END_PORTAL_FRAME.defaultBlockState().setValue(EndPortalFrameBlock.FACING, Direction.WEST); - private static final BlockState endPortal = Blocks.END_PORTAL.defaultBlockState(); - - public static void generateEndPortal(final ServerLevel world, final int x, final int y, final int z, final boolean placePortalBlocks) { - // Sponge Start - Recreate logic for making an end portal frame since Vanilla assumes you are in a stronghold - - final BlockPos.MutableBlockPos origin = new BlockPos.MutableBlockPos(x, y, z); // 2 - - for (int bx = 0; bx < 5; bx++) { - for (int by = 0; by < 5; by++) { - origin.set(x + bx, y, z + by); - - if (bx == 0 && (by > 0 && by < 4)) { - world.setBlock(origin, PortalHelper.southEndFrame.setValue(EndPortalFrameBlock.HAS_EYE, world.random.nextFloat() > 0.9F), 2); - continue; - } - - if (bx == 1 || bx == 2 || bx == 3) { - if (by == 0) { - world.setBlock(origin, PortalHelper.eastEndFrame.setValue(EndPortalFrameBlock.HAS_EYE, world.random.nextFloat() > 0.9F), 2); - } else if (by == 4) { - world.setBlock(origin, PortalHelper.westEndFrame.setValue(EndPortalFrameBlock.HAS_EYE, world.random.nextFloat() > 0.9F), 2); - } else if (placePortalBlocks) { - world.setBlock(origin, PortalHelper.endPortal, 2); - } - - continue; - } - - if (bx == 4 && (by > 0 && by < 4)) { - world.setBlock(origin, PortalHelper.northEndFrame.setValue(EndPortalFrameBlock.HAS_EYE, world.random.nextFloat() > 0.9F), 2); - } - } - } - } - - // see Teleporter#createPortal - public static void generateNetherPortal(final ServerLevel world, final int x, final int y, final int z, final Direction.Axis axis, final boolean placePortalBlocks) { - final BlockPos portalPos = new BlockPos(x, y, z); - final Direction direction = Direction.get(Direction.AxisDirection.POSITIVE, axis); - double d0 = -1.0D; - BlockPos blockpos = null; - double d1 = -1.0D; - BlockPos blockpos1 = null; - final WorldBorder worldborder = world.getWorldBorder(); - final int i = world.getHeight() - 1; - final BlockPos.MutableBlockPos blockpos$mutable = portalPos.mutable(); - - for(final BlockPos.MutableBlockPos blockpos$mutable1 : BlockPos.spiralAround(portalPos, 16, Direction.EAST, Direction.SOUTH)) { - final int j = Math.min(i, world.getHeight(Heightmap.Types.MOTION_BLOCKING, blockpos$mutable1.getX(), blockpos$mutable1.getZ())); - final int k = 1; - if (worldborder.isWithinBounds(blockpos$mutable1) && worldborder.isWithinBounds(blockpos$mutable1.move(direction, 1))) { - blockpos$mutable1.move(direction.getOpposite(), 1); - - for(int l = j; l >= 0; --l) { - blockpos$mutable1.setY(l); - if (world.isEmptyBlock(blockpos$mutable1)) { - final int i1; - for(i1 = l; l > 0 && world.isEmptyBlock(blockpos$mutable1.move(Direction.DOWN)); --l) { - } - - if (l + 4 <= i) { - final int j1 = i1 - l; - if (j1 <= 0 || j1 >= 3) { - blockpos$mutable1.setY(l); - if (PortalHelper.canHostFrame(world, blockpos$mutable1, blockpos$mutable, direction, 0)) { - final double d2 = portalPos.distSqr(blockpos$mutable1); - if (PortalHelper.canHostFrame(world, blockpos$mutable1, blockpos$mutable, direction, -1) && PortalHelper.canHostFrame(world, blockpos$mutable1, blockpos$mutable, direction, 1) && (d0 == -1.0D || d0 > d2)) { - d0 = d2; - blockpos = blockpos$mutable1.immutable(); - } - - if (d0 == -1.0D && (d1 == -1.0D || d1 > d2)) { - d1 = d2; - blockpos1 = blockpos$mutable1.immutable(); - } - } - } - } - } - } - } - } - - if (d0 == -1.0D && d1 != -1.0D) { - blockpos = blockpos1; - d0 = d1; - } - - if (d0 == -1.0D) { - blockpos = (new BlockPos(portalPos.getX(), Mth.clamp(portalPos.getY(), 70, world.getHeight() - 10), portalPos.getZ())).immutable(); - final Direction direction1 = direction.getClockWise(); - if (!worldborder.isWithinBounds(blockpos)) { - return; - } - - for(int l1 = -1; l1 < 2; ++l1) { - for(int k2 = 0; k2 < 2; ++k2) { - for(int i3 = -1; i3 < 3; ++i3) { - final BlockState blockstate1 = i3 < 0 ? Blocks.OBSIDIAN.defaultBlockState() : Blocks.AIR.defaultBlockState(); - blockpos$mutable.setWithOffset(blockpos, k2 * direction.getStepX() + l1 * direction1.getStepX(), i3, k2 * direction.getStepZ() + l1 * direction1.getStepZ()); - world.setBlockAndUpdate(blockpos$mutable, blockstate1); - } - } - } - } - - for(int k1 = -1; k1 < 3; ++k1) { - for(int i2 = -1; i2 < 4; ++i2) { - if (k1 == -1 || k1 == 2 || i2 == -1 || i2 == 3) { - blockpos$mutable.setWithOffset(blockpos, k1 * direction.getStepX(), i2, k1 * direction.getStepZ()); - world.setBlock(blockpos$mutable, Blocks.OBSIDIAN.defaultBlockState(), 3); - } - } - } - - if (placePortalBlocks) { - final BlockState blockstate = Blocks.NETHER_PORTAL.defaultBlockState().setValue(NetherPortalBlock.AXIS, axis); - - for(int j2 = 0; j2 < 2; ++j2) { - for(int l2 = 0; l2 < 3; ++l2) { - blockpos$mutable.setWithOffset(blockpos, j2 * direction.getStepX(), l2, j2 * direction.getStepZ()); - world.setBlock(blockpos$mutable, blockstate, 18); - } - } - } - - } - - private static boolean canHostFrame(final ServerLevel world, final BlockPos p_242955_1_, final BlockPos.MutableBlockPos p_242955_2_, final Direction p_242955_3_, final int p_242955_4_) { - final Direction direction = p_242955_3_.getClockWise(); - - for(int i = -1; i < 3; ++i) { - for(int j = -1; j < 4; ++j) { - p_242955_2_.setWithOffset(p_242955_1_, p_242955_3_.getStepX() * i + direction.getStepX() * p_242955_4_, j, p_242955_3_.getStepZ() * i + direction.getStepZ() * p_242955_4_); - if (j < 0 && !world.getBlockState(p_242955_2_).isSolid()) { - return false; - } - - if (j >= 0 && !world.isEmptyBlock(p_242955_2_)) { - return false; - } - } - } - - return true; - } - -} diff --git a/src/main/java/org/spongepowered/common/world/portal/PortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/PortalLogic.java deleted file mode 100644 index 77f5236ab0f..00000000000 --- a/src/main/java/org/spongepowered/common/world/portal/PortalLogic.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.world.portal; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.portal.PortalInfo; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.event.cause.entity.MovementType; -import org.spongepowered.api.world.portal.PortalType; - -import java.util.function.Function; - -public interface PortalLogic { - - // Matches Forge ITeleporter - @Nullable PortalInfo getPortalInfo(Entity entity, ServerLevel targetWorld, Function defaultPortalInfo); - - // Matches Forge ITeleporter - // Implementor note: the final function Boolean is true if a portal exists - @Nullable Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel targetWorld, float yRot, Function teleportLogic); - - // Matches Forge ITeleporter - // This isn't if it's a vanilla portal - it's if it's vanilla(ish) logic. - boolean isVanilla(); - - MovementType getMovementType(); - - PortalType getPortalType(); - -} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java new file mode 100644 index 00000000000..9e5f9112353 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java @@ -0,0 +1,99 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.portal.DimensionTransition; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * This is a custom portal type. + */ +public final class SpongeCompositePortalLogic implements net.minecraft.world.level.block.Portal, PortalLogic { + + private final List rules; + + public SpongeCompositePortalLogic(final List rules) { + this.rules = rules; + } + + @Nullable @Override + public DimensionTransition getPortalDestination(final ServerLevel sourceLevel, final Entity entity, final BlockPos portalPos) { + return this.rules.stream() + .map(p -> p.getPortalDestination(sourceLevel, entity, portalPos)) + .filter(Objects::nonNull) + .findFirst().orElse(null); + } + + @Override + public Optional exitCalculator() { + return Optional.of((from, fromPos, entity) -> this.rules.stream().map(PortalLogic.class::cast) + .map(PortalLogic::exitCalculator).flatMap(Optional::stream) + .flatMap(c -> c.calculatePortalExit(from, fromPos, entity).stream()) + .findFirst()); + } + + @Override + public Optional finder() { + return Optional.of((at, range) -> this.rules.stream().map(PortalLogic.class::cast) + .map(PortalLogic::finder).flatMap(Optional::stream) + .flatMap(c -> c.findPortal(at, range).stream()) + .findFirst()); + } + + @Override + public Optional generator() { + return Optional.of((at, axis) -> this.rules.stream().map(PortalLogic.class::cast) + .map(PortalLogic::generator).flatMap(Optional::stream) + .flatMap(c -> c.generatePortal(at, axis).stream()) + .findFirst()); + } + + @Override + public boolean teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + final var searchRange = 1; + final var axis = Axis.X; + + var foundPortal = this.finder().flatMap(finder -> finder.findPortal(destination, searchRange)); + if (foundPortal.isPresent()) { + return foundPortal.map(Portal::position).map(entity::setLocation).orElse(false); + } + if (generateDestinationPortal) { + var generatedPortal = this.generator().flatMap(generator -> generator.generatePortal(destination, axis)); + return generatedPortal.map(Portal::position).map(entity::setLocation).orElse(false); + } + return false; + } +} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java new file mode 100644 index 00000000000..65bf3c1c70d --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java @@ -0,0 +1,110 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.portal.DimensionTransition; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.common.util.VecHelper; + +import java.util.Optional; + +/** + * This is a custom portal type. + */ +public final class SpongeCustomPortalLogic implements net.minecraft.world.level.block.Portal, PortalLogic { + + private final PortalLogic.PortalExitCalculator exitCalculator; + private final PortalLogic.PortalFinder finder; + private final PortalLogic.PortalGenerator generator; + + private int searchRange = 16; + private Axis axis = Axis.X; + + public SpongeCustomPortalLogic(final PortalLogic.PortalExitCalculator calulator, + final PortalLogic.PortalFinder finder, + final PortalLogic.PortalGenerator generator) { + + this.exitCalculator = calulator; + this.finder = finder; + this.generator = generator; + } + + @Nullable @Override + public DimensionTransition getPortalDestination(final ServerLevel fromLevel, final Entity entity, final BlockPos fromPos) { + final var spongeEntity = (org.spongepowered.api.entity.Entity) entity; + // Calculate desired portal location + // Then find existing portal or generate if not found + return this.exitCalculator.calculatePortalExit((ServerWorld) fromLevel, VecHelper.toVector3i(fromPos), spongeEntity) + .flatMap(calcExit -> this.finder.findPortal(calcExit, this.searchRange).map(Portal::position).or(() -> this.generator.generatePortal(calcExit, this.axis).map(Portal::position)) + .map(realExit -> SpongeCustomPortalLogic.generateTransition(entity, realExit)) + ).orElse(null); + } + + private static DimensionTransition generateTransition(final Entity entity, final ServerLocation finalExit) { + return new DimensionTransition( + (ServerLevel) finalExit.world(), + VecHelper.toVanillaVector3d(finalExit.position()), + entity.getDeltaMovement(), + entity.getYRot(), + entity.getXRot(), + DimensionTransition.PLACE_PORTAL_TICKET); + } + + @Override + public Optional exitCalculator() { + return Optional.of(this.exitCalculator); + } + + @Override + public Optional finder() { + return Optional.of(this.finder); + } + + @Override + public Optional generator() { + return Optional.of(this.generator); + } + + @Override + public boolean teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + final var foundPortal = this.finder.findPortal(destination, this.searchRange); + if (foundPortal.isPresent()) { + return foundPortal.map(Portal::position).map(entity::setLocation).orElse(false); + } + if (generateDestinationPortal) { + var generatedPortal = this.generator.generatePortal(destination, this.axis); + return generatedPortal.map(Portal::position).map(entity::setLocation).orElse(false); + } + return false; + } +} diff --git a/src/main/java/org/spongepowered/common/world/portal/EndPortalType.java b/src/main/java/org/spongepowered/common/world/portal/SpongeEndPlatformGenerator.java similarity index 64% rename from src/main/java/org/spongepowered/common/world/portal/EndPortalType.java rename to src/main/java/org/spongepowered/common/world/portal/SpongeEndPlatformGenerator.java index 0a72ca2764c..778a2571374 100644 --- a/src/main/java/org/spongepowered/common/world/portal/EndPortalType.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeEndPlatformGenerator.java @@ -24,35 +24,27 @@ */ package org.spongepowered.common.world.portal; +import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; -import org.spongepowered.api.entity.Entity; +import net.minecraft.world.level.levelgen.feature.EndPlatformFeature; import org.spongepowered.api.util.Axis; import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.common.util.VecHelper; -import java.util.Objects; import java.util.Optional; -public final class EndPortalType extends VanillaPortalType { - @Override - public boolean generatePortal(final ServerLocation location, final Axis axis) { - Objects.requireNonNull(location); - PortalHelper.generateEndPortal((ServerLevel) location.world(), location.blockX(), location.blockY(), location.blockZ(), true); - return true; - } +public final class SpongeEndPlatformGenerator implements PortalLogic.PortalGenerator { - @Override - public Optional findPortal(final ServerLocation location) { - Objects.requireNonNull(location); - return Optional.empty(); - } + public static final SpongeEndPlatformGenerator INSTANCE = new SpongeEndPlatformGenerator(); @Override - public boolean teleport(final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { - Objects.requireNonNull(entity); - Objects.requireNonNull(destination); - - return false; + public Optional generatePortal(final ServerLocation location, final Axis axis) { + final var level = (ServerLevel) location.world(); + final var bottomCenter = VecHelper.toBlockPos(location.blockPosition()).getBottomCenter(); + EndPlatformFeature.createEndPlatform(level, BlockPos.containing(bottomCenter).below(), true); + return Optional.of(new SpongePortal(location, null)); // TODO set portallogic? } } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java new file mode 100644 index 00000000000..a8c7b17eb8b --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java @@ -0,0 +1,75 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.common.world.server.SpongeWorldManager; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Optional; + + +public final class SpongeNetherPortalExitCalculator implements PortalLogic.PortalExitCalculator { + + private final ResourceKey origin; + private final ResourceKey target; + @Nullable private final Double scale; + + public SpongeNetherPortalExitCalculator(final org.spongepowered.api.ResourceKey origin, final org.spongepowered.api.ResourceKey target, @Nullable final Double scale) { + this.origin = SpongeWorldManager.createRegistryKey(origin); + this.target = SpongeWorldManager.createRegistryKey(target); + this.scale = scale; + } + + @Override + public Optional calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final org.spongepowered.api.entity.Entity entity) { + final var fromLevel = (ServerLevel) from.world(); + if (!fromLevel.dimension().equals(this.origin)) { + return Optional.empty(); // configured Portals go only in one direction + } + final var toLevel = fromLevel.getServer().getLevel(this.target); + if (toLevel == null) { + return Optional.empty(); + } + final var scale = this.calculateScale(fromLevel, toLevel); + final var exitPosition = toLevel.getWorldBorder().clampToBounds(fromPos.x() * scale, fromPos.y(), fromPos.z() * scale); + return Optional.of(ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3i(exitPosition))); + } + + private double calculateScale(final ServerLevel fromLevel, final ServerLevel toLevel) { + if (this.scale != null) { + return this.scale; + } + return DimensionType.getTeleportationScale(fromLevel.dimensionType(), toLevel.dimensionType()); + } +} diff --git a/src/main/java/org/spongepowered/common/world/portal/VanillaPortal.java b/src/main/java/org/spongepowered/common/world/portal/SpongePortal.java similarity index 61% rename from src/main/java/org/spongepowered/common/world/portal/VanillaPortal.java rename to src/main/java/org/spongepowered/common/world/portal/SpongePortal.java index 7d217054496..61f7c3fd828 100644 --- a/src/main/java/org/spongepowered/common/world/portal/VanillaPortal.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongePortal.java @@ -25,37 +25,46 @@ package org.spongepowered.common.world.portal; import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.util.AABB; import org.spongepowered.api.world.portal.Portal; -import org.spongepowered.api.world.portal.PortalType; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.ServerLocation; import java.util.Optional; -public class VanillaPortal implements Portal { +public class SpongePortal implements Portal { - private final PortalType type; - private final ServerLocation minCorner; - private final @Nullable ServerLocation destination; + private final ServerLocation position; + @Nullable private final PortalLogic portalLogic; + @Nullable private final AABB aabb; - public VanillaPortal(final PortalType type, final ServerLocation minCorner, final @Nullable ServerLocation destination) { - this.type = type; - this.minCorner = minCorner; - this.destination = destination; + public SpongePortal(final ServerLocation position, @Nullable final PortalLogic portalLogic, @Nullable final AABB aabb) { + this.position = position; + this.portalLogic = portalLogic; + this.aabb = aabb; + } + + public SpongePortal(final ServerLocation position, final PortalLogic portalLogic) { + this(position, portalLogic, null); + } + + + public SpongePortal(final ServerLocation position) { + this(position, null, null); } @Override - public PortalType type() { - return this.type; + public Optional logic() { + return Optional.ofNullable(this.portalLogic); } @Override - public ServerLocation origin() { - return this.minCorner; + public ServerLocation position() { + return this.position; } - // Vanilla has no knowledge of where portals go to until you try, best we can do... @Override - public Optional destination() { - return Optional.ofNullable(this.destination); + public Optional boundingBox() { + return Optional.ofNullable(this.aabb); } } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java new file mode 100644 index 00000000000..5796681178a --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java @@ -0,0 +1,67 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import net.minecraft.world.level.block.Portal; +import org.spongepowered.api.world.portal.PortalLogic; + +import java.util.ArrayList; +import java.util.List; + +public final class SpongePortalLogicBuilder implements PortalLogic.Builder { + + private List rules = new ArrayList<>(); + + + @Override + public PortalLogic.Builder reset() { + this.rules.clear(); + return this; + } + + + @Override + public PortalLogic.Builder addPortal(final PortalLogic.PortalExitCalculator calulator, + final PortalLogic.PortalFinder finder, + final PortalLogic.PortalGenerator generator) { + var portal = new SpongeCustomPortalLogic(calulator, finder, generator); + this.rules.add(portal); + return this; + } + + @Override + public PortalLogic.Builder addPortal(final T logic) { + var portal = new SpongeCustomPortalLogic(logic, logic, logic); + this.rules.add(portal); + return this; + } + + @Override + public PortalLogic build() { + return new SpongeCompositePortalLogic(this.rules); + } + + +} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java new file mode 100644 index 00000000000..821a9d20ed5 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java @@ -0,0 +1,107 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import net.minecraft.world.level.block.Blocks; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.util.AABB; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.math.vector.Vector3d; + +import java.util.Optional; + +public class SpongePortalLogicFactory implements PortalLogic.Factory { + + public static final PortalLogic.PortalFinder NO_OP_PORTALFINDER = (at, range) -> Optional.of(new SpongePortal(at)); + + @Override + public PortalLogic endPortal() { + return (PortalLogic) Blocks.END_PORTAL; + } + + @Override + public PortalLogic endGateway() { + return (PortalLogic) Blocks.END_GATEWAY; + } + + @Override + public PortalLogic netherPortal() { + return (PortalLogic) Blocks.NETHER_PORTAL; + } + + @Override + public PortalLogic.PortalExitCalculator netherPortalExitCalculator(final ResourceKey origin, final ResourceKey target) { + return new SpongeNetherPortalExitCalculator(origin, target, null); + } + + @Override + public PortalLogic.PortalExitCalculator netherPortalExitCalculator(final ResourceKey origin, final ResourceKey target, final double scale) { + return new SpongeNetherPortalExitCalculator(origin, target, scale); + } + + @Override + public PortalLogic.PortalExitCalculator targetCalculator(final ResourceKey origin, final ResourceKey target, final Vector3d targetPos) { + return new SpongeTargetPortalFinder(origin, target, targetPos); + } + + @Override + public PortalLogic.PortalExitCalculator spawnCalculator(final ResourceKey origin, final ResourceKey target) { + return new SpongeSpawnPortalFinder(origin, target); + } + + @Override + public PortalLogic.PortalFinder netherPortalFinder() { + return this.netherPortal().finder().get(); + } + + @Override + public PortalLogic.PortalGenerator netherPortalGenerator() { + return this.netherPortal().generator().get(); + } + + @Override + public PortalLogic.PortalGenerator endPlatformGenerator() { + return SpongeEndPlatformGenerator.INSTANCE; + } + + @Override + public PortalLogic.PortalFinder noOpFinder() { + return NO_OP_PORTALFINDER; + } + + @Override + public Portal portalOf(final PortalLogic logic, final ServerLocation position) { + return new SpongePortal(position, logic); + } + + @Override + public Portal portalOf(final PortalLogic logic, final ServerLocation position, final AABB aabb) { + return new SpongePortal(position, logic, aabb); + } + + +} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeSpawnPortalFinder.java b/src/main/java/org/spongepowered/common/world/portal/SpongeSpawnPortalFinder.java new file mode 100644 index 00000000000..5c2c3a32ce2 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeSpawnPortalFinder.java @@ -0,0 +1,71 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.portal; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Optional; + +/** + * This is a portal type teleporting to the world/player spawn + */ +public final class SpongeSpawnPortalFinder implements PortalLogic.PortalExitCalculator { + + + private final ResourceKey origin; + private final ResourceKey target; + + public SpongeSpawnPortalFinder(final org.spongepowered.api.ResourceKey origin, final org.spongepowered.api.ResourceKey target) { + this.origin = origin; + this.target = target; + } + + @Override + public Optional calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final org.spongepowered.api.entity.Entity entity) { + if (!from.key().equals(this.origin)) { + return Optional.empty(); + } + + // TODO bed spawn and adjusted spawn location? + /* + if (entity instanceof ServerPlayer player) { + var transition = player.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); + return Optional.of(ServerLocation.of((ServerWorld) transition.newLevel(), VecHelper.toVector3d(transition.pos()))); + } + + final var sharedSpawnPos = toLevel.getSharedSpawnPos(); + final var spawnPos = ((net.minecraft.world.entity.Entity) entity).adjustSpawnLocation(toLevel, sharedSpawnPos).getBottomCenter(); + return ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3d(spawnPos)); + */ + return Sponge.server().worldManager().world(this.target).map(world -> world.location(world.properties().spawnPosition())); + } + + +} diff --git a/src/main/java/org/spongepowered/common/world/portal/VanillaTwoDimensionalPortal.java b/src/main/java/org/spongepowered/common/world/portal/SpongeTargetPortalFinder.java similarity index 56% rename from src/main/java/org/spongepowered/common/world/portal/VanillaTwoDimensionalPortal.java rename to src/main/java/org/spongepowered/common/world/portal/SpongeTargetPortalFinder.java index 88ccdd84433..433bb67a201 100644 --- a/src/main/java/org/spongepowered/common/world/portal/VanillaTwoDimensionalPortal.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeTargetPortalFinder.java @@ -24,23 +24,35 @@ */ package org.spongepowered.common.world.portal; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.TwoDimensionalPortal; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; -public final class VanillaTwoDimensionalPortal extends VanillaPortal implements TwoDimensionalPortal { +import java.util.Optional; - private final ServerLocation maxCorner; +public final class SpongeTargetPortalFinder implements PortalLogic.PortalExitCalculator { - public VanillaTwoDimensionalPortal( - final PortalType type, final ServerLocation minCorner, final ServerLocation maxCorner, @Nullable final ServerLocation destination) { - super(type, minCorner, destination); - this.maxCorner = maxCorner; + + private final ResourceKey origin; + private final ResourceKey target; + private final Vector3d targetPos; + + public SpongeTargetPortalFinder(final ResourceKey origin, final ResourceKey target, final Vector3d targetPos) { + this.origin = origin; + this.target = target; + this.targetPos = targetPos; } @Override - public ServerLocation maxCorner() { - return this.maxCorner; + public Optional calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final org.spongepowered.api.entity.Entity entity) { + if (!from.key().equals(this.origin)) { + return Optional.empty(); + } + return Sponge.server().worldManager().world(target).map(world -> world.location(this.targetPos)); } + } diff --git a/src/main/java/org/spongepowered/common/world/portal/VanillaPortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/VanillaPortalLogic.java deleted file mode 100644 index b8a5e069cb1..00000000000 --- a/src/main/java/org/spongepowered/common/world/portal/VanillaPortalLogic.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.world.portal; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.portal.PortalInfo; -import org.spongepowered.api.event.cause.entity.MovementType; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.PortalTypes; - -import java.util.function.Function; - -public abstract class VanillaPortalLogic implements PortalLogic { - - public static VanillaPortalLogic getEndInstance() { - return Holder.END_INSTANCE; - } - - final static class Holder { - static final VanillaPortalLogic END_INSTANCE = new VanillaPortalLogic.End(); - } - - private VanillaPortalLogic() { - } - - @Override - public PortalInfo getPortalInfo(final Entity entity, final ServerLevel targetWorld, final Function defaultPortalInfo) { - return defaultPortalInfo.apply(targetWorld); - } - - @Override - public Entity placeEntity(final Entity entity, final ServerLevel currentWorld, final ServerLevel targetWorld, final float yRot, - final Function entityRepositioner) { - return entityRepositioner.apply(true); - } - - @Override - public boolean isVanilla() { - return true; - } - - @Override - public MovementType getMovementType() { - return MovementTypes.PORTAL.get(); - } - - public final static class End extends VanillaPortalLogic { - - @Override - public PortalType getPortalType() { - return PortalTypes.END.get(); - } - - } - -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/portal/PortalShapeMixin.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PortalProcessorMixin_API.java similarity index 50% rename from src/mixins/java/org/spongepowered/common/mixin/core/world/level/portal/PortalShapeMixin.java rename to src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PortalProcessorMixin_API.java index aab98eaf68e..8968941c48d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/portal/PortalShapeMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PortalProcessorMixin_API.java @@ -22,32 +22,45 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.mixin.core.world.level.portal; +package org.spongepowered.common.mixin.api.minecraft.world.entity; -import net.minecraft.BlockUtil; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.level.portal.PortalShape; -import net.minecraft.world.phys.Vec3; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.PortalProcessor; +import org.spongepowered.api.util.AABB; import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.common.world.portal.NetherPortalType; -import org.spongepowered.common.world.portal.SpongePortalInfo; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.bridge.world.entity.PortalProcessorBridge; +import org.spongepowered.common.util.VecHelper; -@Mixin(PortalShape.class) -public abstract class PortalShapeMixin { +import java.util.Optional; - @Redirect(method = "createPortalInfo", at = @At(value = "NEW", target = "net/minecraft/world/level/portal/PortalInfo")) - private static PortalInfo impl$createSpongePortalInfo(final Vec3 var1, final Vec3 var2, final float var3, final float var4, - final ServerLevel $$0, final BlockUtil.FoundRectangle $$1, final Direction.Axis $$2, - final Vec3 $$3, final Entity $$4, final Vec3 $$5, final float $$6, final float $$7) { - final Portal portal = NetherPortalType.portalObjectFromRectangle((ServerWorld) $$0, $$1); - return new SpongePortalInfo(var1, var2, var3, var4, portal); +@Mixin(PortalProcessor.class) +public abstract class PortalProcessorMixin_API implements Portal, PortalProcessorBridge { + + // @formatter:off + @Shadow private net.minecraft.world.level.block.Portal portal; + @Shadow private BlockPos entryPosition; + // @formatter:on + + @Override + public Optional logic() { + return Optional.of((PortalLogic) this.portal); } + @Override + public ServerLocation position() { + if (this.bridge$level() instanceof ServerWorld world) { + return ServerLocation.of(world, VecHelper.toVector3i(this.entryPosition)); + } + throw new IllegalStateException("PortalProcessor was not initialized for sponge usage."); + } + + @Override + public Optional boundingBox() { + return Optional.empty(); // not known without potentially generating blocks + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java index 6fb2c57038a..76c5132f397 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java @@ -27,7 +27,6 @@ import net.kyori.adventure.sound.Sound; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; -import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; @@ -47,7 +46,6 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; @@ -119,13 +117,10 @@ public abstract class LevelMixin_API, L extends Location blockEntityTickers; @Shadow @Nullable public abstract MinecraftServer shadow$getServer(); - @Shadow public abstract BlockState shadow$getBlockState(BlockPos p_180495_1_); @Shadow public abstract void shadow$playSound(net.minecraft.world.entity.player.@Nullable Player p_184148_1_, double p_184148_2_, double p_184148_4_, double p_184148_6_, SoundEvent p_184148_8_, SoundSource p_184148_9_, float p_184148_10_, float p_184148_11_); @Shadow public abstract LevelData shadow$getLevelData(); - @Shadow public abstract void shadow$removeBlockEntity(BlockPos pos); @Shadow public abstract ResourceKey shadow$dimension(); @Shadow public abstract void shadow$setBlockEntity(net.minecraft.world.level.block.entity.BlockEntity var1); @Shadow public abstract LevelChunk shadow$getChunkAt(BlockPos param0); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java new file mode 100644 index 00000000000..eaa293c8d57 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java @@ -0,0 +1,70 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.level.block; + +import net.minecraft.world.level.block.Portal; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.bridge.world.level.block.PortalBlockBridge; + +import java.util.Optional; + +@Mixin(Portal.class) +public interface PortalMixin_API extends PortalLogic { + + @Override + default Optional exitCalculator() { + if (this instanceof PortalBlockBridge pbb) { + return Optional.of(pbb::bridge$calculatePortalExit); + } + return Optional.empty(); + } + + @Override + default Optional finder() { + if (this instanceof PortalBlockBridge pbb) { + return Optional.of(pbb::bridge$findPortal); + } + return Optional.empty(); + } + + @Override + default Optional generator() { + if (this instanceof PortalBlockBridge pbb) { + return Optional.of(pbb::bridge$generatePortal); + } + return Optional.empty(); + } + + @Override + default boolean teleport(final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + if (this instanceof PortalBlockBridge pbb) { + return pbb.bridge$teleport(entity, destination, generateDestinationPortal); + } + return false; + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index 672221e2228..f28680c4acc 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -40,13 +40,11 @@ import net.minecraft.network.protocol.game.ClientboundBossEventPacket; import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; import net.minecraft.network.protocol.game.ClientboundGameEventPacket; -import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; import net.minecraft.network.protocol.game.ClientboundPlayerCombatKillPacket; import net.minecraft.network.protocol.game.ClientboundRespawnPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; -import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket; -import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; @@ -60,7 +58,6 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; @@ -72,10 +69,10 @@ import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.portal.PortalInfo; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import net.minecraft.world.scores.criteria.ObjectiveCriteria; @@ -105,6 +102,7 @@ import org.spongepowered.api.event.entity.RotateEntityEvent; import org.spongepowered.api.event.entity.living.player.KickPlayerEvent; import org.spongepowered.api.event.entity.living.player.PlayerChangeClientSettingsEvent; +import org.spongepowered.api.event.entity.living.player.RespawnPlayerEvent; import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.scoreboard.Scoreboard; import org.spongepowered.api.service.permission.PermissionService; @@ -119,7 +117,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.SpongeCommon; @@ -136,22 +133,21 @@ import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; import org.spongepowered.common.data.DataUtil; import org.spongepowered.common.data.type.SpongeSkinPart; -import org.spongepowered.common.entity.EntityUtil; import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.phase.entity.EntityPhase; +import org.spongepowered.common.event.tracking.phase.entity.TeleportContext; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.mixin.core.world.entity.player.PlayerMixin; import org.spongepowered.common.util.LocaleCache; import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.border.PlayerOwnBorderListener; -import org.spongepowered.common.world.portal.PortalLogic; import org.spongepowered.math.vector.Vector3d; import java.util.HashSet; import java.util.Locale; import java.util.Objects; -import java.util.Optional; import java.util.Set; // See also: SubjectMixin_API and SubjectMixin @@ -165,22 +161,16 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr @Shadow @Final public MinecraftServer server; @Shadow private int lastRecordedExperience; @Shadow private boolean isChangingDimension; - @Shadow public boolean wonGame; - @Shadow private boolean seenCredits; @Shadow private net.minecraft.world.phys.Vec3 enteredNetherPosition; @Shadow private int lastSentExp; @Shadow private float lastSentHealth; @Shadow private int lastSentFood; @Shadow public abstract ServerLevel shadow$serverLevel(); - @Shadow public abstract void shadow$setCamera(final Entity entity); - @Shadow public abstract void shadow$closeContainer(); @Shadow public abstract void shadow$resetStat(final Stat statistic); @Shadow protected abstract void shadow$tellNeutralMobsThatIDied(); - @Shadow protected abstract void shadow$createEndPlatform(ServerLevel p_241206_1_, BlockPos blockPos); @Shadow protected abstract void shadow$triggerDimensionChangeTriggers(ServerLevel serverworld); @Shadow public abstract void shadow$doCloseContainer(); - @Shadow public abstract void shadow$setServerLevel(ServerLevel serverLevel); @Shadow public abstract boolean shadow$setGameMode(GameType param0); // @formatter:on @@ -221,28 +211,26 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr } @Override - protected final boolean impl$setLocation(final boolean isChangeOfWorld, final ServerLevel originalDestination, - final ServerLevel destinationWorld, final Vector3d destinationPosition) { + protected final boolean impl$setLocation(final boolean isChangeOfWorld, final ServerLevel level, final Vector3d pos) { if (this.shadow$isRemoved()) { return false; } + final var thisPlayer = ((net.minecraft.server.level.ServerPlayer) (Object) this); - final net.minecraft.server.level.ServerPlayer player = ((net.minecraft.server.level.ServerPlayer) (Object) this); - player.stopRiding(); - if (player.isSleeping()) { - player.stopSleepInBed(true, true); - } + final ChunkPos chunkPos = new ChunkPos(VecHelper.toBlockPos(pos)); + level.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkPos, 1, thisPlayer.getId()); - final ChunkPos chunkPos = VecHelper.toChunkPos(Sponge.server().chunkLayout().forceToChunk(destinationPosition.toInt())); - destinationWorld.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkPos, 1, player.getId()); + thisPlayer.stopRiding(); + if (thisPlayer.isSleeping()) { + thisPlayer.stopSleepInBed(true, true); + } - if (isChangeOfWorld) { - this.shadow$absMoveTo(destinationPosition.x(), destinationPosition.y(), destinationPosition.z(), this.shadow$getYRot(), this.shadow$getXRot()); - EntityUtil.performPostChangePlayerWorldLogic(player, this.shadow$serverLevel(), destinationWorld, destinationWorld, false); - } else { - this.connection.teleport(destinationPosition.x(), destinationPosition.y(), destinationPosition.z(), this.shadow$getYRot(), this.shadow$getXRot(), - new HashSet<>()); + if (!isChangeOfWorld) { + this.connection.teleport(pos.x(), pos.y(), pos.z(), this.shadow$getYRot(), this.shadow$getXRot(), new HashSet<>()); this.connection.resetPosition(); + } else { + this.bridge$changeDimension(new DimensionTransition(level, VecHelper.toVanillaVector3d(pos), thisPlayer.getKnownMovement(), + this.shadow$getYRot(), this.shadow$getXRot(), DimensionTransition.DO_NOTHING)); } return true; } @@ -392,216 +380,199 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr */ /** - * @author zidane - November 21st, 2020 - Minecraft 1.15 - * @reason Ensure that the teleport hook honors our events + * @author faithcaio - 2024-05-30 - MC 1.21 + * @reason Redirect all teleports through {@link #bridge$changeDimension} to fire our move/rotate/teleport events */ @Overwrite - public void teleportTo( - final ServerLevel world, final double x, final double y, final double z, final float yaw, final float pitch) { - final net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer) (Object) this; - double actualX = x; - double actualY = y; - double actualZ = z; - double actualYaw = yaw; - double actualPitch = pitch; - + public void teleportTo(final ServerLevel world, final double x, final double y, final double z, final float yaw, final float pitch) { final boolean hasMovementContext = PhaseTracker.getCauseStackManager().currentContext().containsKey(EventContextKeys.MOVEMENT_TYPE); - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { if (!hasMovementContext) { frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN); } - if (world == player.level()) { - final @Nullable Vector3d destination = this.impl$fireMoveEvent(PhaseTracker.SERVER, new Vector3d(x, y, z)); - if (destination == null) { - return; - } - actualX = destination.x(); - actualY = destination.y(); - actualZ = destination.z(); + final var thisPlayer = (net.minecraft.server.level.ServerPlayer) (Object) this; + this.bridge$changeDimension(new DimensionTransition(world, new Vec3(x, y, z), Vec3.ZERO, yaw, pitch, + e -> world.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, e.chunkPosition(), 1, thisPlayer.getId()))); + } + } - if (ShouldFire.ROTATE_ENTITY_EVENT) { - final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), - (org.spongepowered.api.entity.Entity) player, new Vector3d(actualPitch, actualYaw, 0), - new Vector3d(pitch, yaw, 0)); + /** + * This is effectively an overwrite of changeDimension and teleportTo. + * Handles {@link MoveEntityEvent} -> {@link RotateEntityEvent} for in dimension teleport + * Handles {@link ChangeEntityWorldEvent.Reposition} -> rotate -> {@link ChangeEntityWorldEvent.Post} + * {@link ChangeEntityWorldEvent.Pre} is handled at call sites. TODO only for known portals? + * For known portals {@link ChangeEntityWorldEvent.Reposition} is handled before at {@link Entity#handlePortal()} + * + * @return The {@link Entity} that is either this one, or replaces this one + */ + @Override + public @Nullable Entity bridge$changeDimension(final DimensionTransition originalTransition) { + if (this.shadow$isRemoved()) { + return null; + } - SpongeCommon.post(rotateEvent); + final var thisPlayer = (net.minecraft.server.level.ServerPlayer) (Object) this; - actualYaw = rotateEvent.isCancelled() ? player.getYRot() : rotateEvent.toRotation().y(); - actualPitch = rotateEvent.isCancelled() ? player.getXRot() : rotateEvent.toRotation().x(); - } + if (originalTransition.missingRespawnBlock()) { // Player only code + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); + } - this.shadow$setCamera(player); - this.shadow$stopRiding(); + final var originalNewLevel = originalTransition.newLevel(); + final var oldLevel = this.shadow$serverLevel(); - if (player.isSleeping()) { - player.stopSleepInBed(true, true); - } + // SpongeStart + final var transition = this.impl$fireDimensionTransitionEvents(originalTransition, thisPlayer); + if (transition == null) { + return null; + } + final var newLevel = transition.newLevel(); + // Sponge End - player.connection.teleport(actualX, actualY, actualZ, (float) actualYaw, (float) actualPitch); + if (newLevel.dimension() == oldLevel.dimension()) { // actually no dimension change + this.connection.teleport(transition.pos().x, transition.pos().y, transition.pos().z, transition.yRot(), transition.xRot()); + this.connection.resetPosition(); + transition.postDimensionTransition().onTransition(thisPlayer); + // TODO setYHeadRot after would rotate event result + return thisPlayer; + } + this.isChangingDimension = true; + LevelData lvlData = newLevel.getLevelData(); + this.connection.send(new ClientboundRespawnPacket(thisPlayer.createCommonSpawnInfo(newLevel), ClientboundRespawnPacket.KEEP_ALL_DATA)); + this.connection.send(new ClientboundChangeDifficultyPacket(lvlData.getDifficulty(), lvlData.isDifficultyLocked())); + PlayerList playerList = this.server.getPlayerList(); + playerList.sendPlayerPermissionLevel(thisPlayer); + oldLevel.removePlayerImmediately(thisPlayer, Entity.RemovalReason.CHANGED_DIMENSION); + this.shadow$unsetRemoved(); - player.setYHeadRot((float) actualYaw); + oldLevel.getProfiler().push("moving"); + if (oldLevel.dimension() == Level.OVERWORLD && newLevel.dimension() == Level.NETHER) { + this.enteredNetherPosition = thisPlayer.position(); + } + oldLevel.getProfiler().pop(); - final ChunkPos chunkpos = new ChunkPos(new BlockPos((int) actualX, (int) actualY, (int) actualZ)); - world.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 1, player.getId()); - } else { - final ChangeEntityWorldEvent.Pre preEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre(player, world); - if (SpongeCommon.post(preEvent)) { - return; + oldLevel.getProfiler().push("placing"); + thisPlayer.setServerLevel(newLevel); + this.connection.teleport(transition.pos().x, transition.pos().y, transition.pos().z, transition.yRot(), transition.xRot()); + this.connection.resetPosition(); + newLevel.addDuringTeleport(thisPlayer); + oldLevel.getProfiler().pop(); + + this.shadow$triggerDimensionChangeTriggers(oldLevel); // TODO old sponge EntityUtil#performPostChangePlayerWorldLogic this was only done when using a portal + this.connection.send(new ClientboundPlayerAbilitiesPacket(thisPlayer.getAbilities())); + playerList.sendLevelInfo(thisPlayer, newLevel); + playerList.sendAllPlayerInfo(thisPlayer); + playerList.sendActivePlayerEffects(thisPlayer); + transition.postDimensionTransition().onTransition(thisPlayer); + // TODO old sponge EntityUtil#performPostChangePlayerWorldLogic called bridge$getBossBarManager().onPlayerDisconnect(player); on both worlds + // TODO old sponge EntityUtil#performPostChangePlayerWorldLogic closed player.closeContainer(); when open + this.lastSentExp = -1; + this.lastSentHealth = -1.0F; + this.lastSentFood = -1; + // Sponge Start TODO cause/context like in impl$fireDimensionTransitionEvents + Sponge.eventManager().post( + SpongeEventFactory.createChangeEntityWorldEventPost( + PhaseTracker.getCauseStackManager().currentCause(), + (org.spongepowered.api.entity.Entity) this, + (ServerWorld) oldLevel, + (ServerWorld) newLevel, + (ServerWorld) originalNewLevel + ) + ); + // Sponge End + return thisPlayer; + } + + @Nullable + private DimensionTransition impl$fireDimensionTransitionEvents(final DimensionTransition originalTransition, + final net.minecraft.server.level.ServerPlayer thisPlayer) { + var transition = originalTransition; + var isDimensionChange = transition.newLevel() != thisPlayer.serverLevel(); + + if (!this.impl$moveEventsFired) { + final var contextToSwitchTo = EntityPhase.State.PORTAL_DIMENSION_CHANGE.createPhaseContext(PhaseTracker.getInstance()).worldChange() + .player(); + final boolean hasMovementContext = PhaseTracker.SERVER.currentContext().containsKey(EventContextKeys.MOVEMENT_TYPE); + try (final TeleportContext context = contextToSwitchTo.buildAndSwitch(); + final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(thisPlayer); + if (!hasMovementContext) { + // TODO we should be able to detect normal plugin code though + // add an unknown movement type? + frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN); } - final MoveEntityEvent posEvent = SpongeEventFactory.createChangeEntityWorldEventReposition(frame.currentCause(), - (org.spongepowered.api.entity.Entity) player, preEvent.originalWorld(), VecHelper.toVector3d(player.position()), - new Vector3d(x, y, z), preEvent.originalDestinationWorld(), new Vector3d(x, y, z), preEvent.destinationWorld()); + final var originalDest = VecHelper.toVector3d(transition.pos()); + final @Nullable Vector3d newDest; + + if (isDimensionChange) { + if (transition.newLevel() != thisPlayer.level()) { + final ChangeEntityWorldEvent.Pre preEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre(thisPlayer, transition.newLevel()); + if (SpongeCommon.post(preEvent)) { + return null; + } + if (preEvent.destinationWorld() != preEvent.originalDestinationWorld()) { + transition = new DimensionTransition((ServerLevel) preEvent.destinationWorld(), + transition.pos(), + transition.speed(), + transition.yRot(), transition.xRot(), + transition.missingRespawnBlock(), + transition.postDimensionTransition()); + } + } - if (SpongeCommon.post(posEvent)) { - return; + final var reposition = this.bridge$fireRepositionEvent((ServerWorld) thisPlayer.serverLevel(), (ServerWorld) transition.newLevel(), originalDest); + if (reposition.isCancelled()) { + return null; // we did not move yet so just return + } + newDest = reposition.destinationPosition(); + } else { + if (ShouldFire.MOVE_ENTITY_EVENT) { // TODO move into impl$fireMoveEvent? + newDest = this.impl$fireMoveEvent(PhaseTracker.SERVER, originalDest); + if (newDest == null) { + return null; + } + } else { + newDest = originalDest; + } + } + if (newDest != originalDest) { + // if changed override the DimensionTransition + transition = new DimensionTransition(transition.newLevel(), + VecHelper.toVanillaVector3d(newDest), + transition.speed(), + transition.yRot(), transition.xRot(), + transition.missingRespawnBlock(), + transition.postDimensionTransition()); } - actualX = posEvent.destinationPosition().x(); - actualY = posEvent.destinationPosition().y(); - actualZ = posEvent.destinationPosition().z(); - this.shadow$setPos(actualX, actualY, actualZ); - - if (ShouldFire.ROTATE_ENTITY_EVENT) { - final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent(frame.currentCause(), - (org.spongepowered.api.entity.Entity) player, new Vector3d(actualYaw, actualPitch, 0), - new Vector3d(yaw, pitch, 0)); - - if (!SpongeCommon.post(rotateEvent)) { - actualYaw = (float) rotateEvent.toRotation().x(); - actualPitch = (float) rotateEvent.toRotation().y(); - } + final Vector3d toRot = new Vector3d(transition.xRot(), transition.yRot(), 0); + final Vector3d fromRot = new Vector3d(thisPlayer.getXRot(), thisPlayer.getYRot(), 0); + // TODO this skips with fuzzy rotation change check. Do we want this? + var newToRot = SpongeCommonEventFactory.callRotateEvent((org.spongepowered.api.entity.Entity) thisPlayer, fromRot, toRot); + if (newToRot == null) { + newToRot = fromRot; // Cancelled Rotate - Reset to original rotation + } + if (toRot != newToRot) { + transition = new DimensionTransition(transition.newLevel(), + transition.pos(), + transition.speed(), + (float) newToRot.y(), (float) newToRot.x(), + transition.missingRespawnBlock(), + transition.postDimensionTransition()); } - this.shadow$setYRot((float) actualYaw); - this.shadow$setXRot((float) actualPitch); - EntityUtil.performPostChangePlayerWorldLogic(player, (ServerLevel) preEvent.originalWorld(), - (ServerLevel) preEvent.originalDestinationWorld(), - (ServerLevel) preEvent.destinationWorld(), false); } - } - } - @Override - protected final void impl$onChangingDimension(final ServerLevel target) { - if (this.shadow$level() != target) { - this.isChangingDimension = true; - } - } - - @SuppressWarnings("ConstantConditions") - @Override - protected final Entity impl$performGameWinLogic() { - this.shadow$unRide(); - this.shadow$serverLevel().removePlayerImmediately((net.minecraft.server.level.ServerPlayer) (Object) this, Entity.RemovalReason.CHANGED_DIMENSION); - if (!this.wonGame) { - this.wonGame = true; - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F)); - this.seenCredits = true; - } - - return (Entity) (Object) this; - } - - @Override - protected final void impl$prepareForPortalTeleport(final ServerLevel currentWorld, final ServerLevel targetWorld) { - final LevelData levelData = targetWorld.getLevelData(); - this.connection.send(new ClientboundRespawnPacket(new CommonPlayerSpawnInfo(targetWorld.dimensionTypeRegistration(), targetWorld.dimension(), - BiomeManager.obfuscateSeed(targetWorld.getSeed()), this.gameMode.getGameModeForPlayer(), - this.gameMode.getPreviousGameModeForPlayer(), targetWorld.isDebug(), targetWorld.isFlat(), this.shadow$getLastDeathLocation(), this.shadow$getPortalCooldown()), - ClientboundRespawnPacket.KEEP_ALL_DATA)); - this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); - final PlayerList playerlist = this.server.getPlayerList(); - playerlist.sendPlayerPermissionLevel((net.minecraft.server.level.ServerPlayer) (Object) this); - currentWorld.removePlayerImmediately((net.minecraft.server.level.ServerPlayer) (Object) this, - Entity.RemovalReason.CHANGED_DIMENSION); - this.shadow$unsetRemoved(); - } - - @SuppressWarnings("ConstantConditions") - @Override - protected final void impl$validateEntityAfterTeleport(final Entity e, final PortalLogic portalLogic) { - if (e != (Object) this) { - throw new IllegalArgumentException(String.format("Teleporter %s " - + "did not return the expected player entity: got %s, expected PlayerEntity %s", portalLogic, e, this)); } - } - - @SuppressWarnings("ConstantConditions") - @Override - protected final Entity impl$portalRepositioning(final boolean createEndPlatform, - final ServerLevel serverworld, - final ServerLevel targetWorld, - final PortalInfo portalinfo) { - serverworld.getProfiler().push("moving"); - if (serverworld.dimension() == Level.OVERWORLD && targetWorld.dimension() == Level.NETHER) { - this.enteredNetherPosition = this.shadow$position(); - // Sponge: From Forge - only enter this branch if the teleporter indicated that we should - // create end platforms and we're in the end (vanilla only has the second condition) - } else if (createEndPlatform && targetWorld.dimension() == Level.END) { - this.shadow$createEndPlatform(targetWorld, new BlockPos((int) portalinfo.pos.x, (int) portalinfo.pos.y, (int) portalinfo.pos.z)); - } - - // This is standard vanilla processing - serverworld.getProfiler().pop(); - serverworld.getProfiler().push("placing"); - this.shadow$setServerLevel(targetWorld); - targetWorld.addDuringPortalTeleport((net.minecraft.server.level.ServerPlayer) (Object) this); - this.shadow$setRot(portalinfo.yRot, portalinfo.xRot); - // Sponge Start: prevent sending the teleport packet here, we'll do so later. - // this.shadow$moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z); - this.shadow$absMoveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z); - // Sponge End - serverworld.getProfiler().pop(); - return (Entity) (Object) this; - } - - @Override - protected final void impl$postPortalForceChangeTasks(final Entity entity, final ServerLevel targetWorld, - final boolean isNetherPortal) { - // Standard vanilla processing - this.gameMode.setLevel(targetWorld); - this.connection.send(new ClientboundPlayerAbilitiesPacket(this.shadow$getAbilities())); - final PlayerList playerlist = this.server.getPlayerList(); - playerlist.sendLevelInfo((net.minecraft.server.level.ServerPlayer) (Object) this, targetWorld); - playerlist.sendAllPlayerInfo((net.minecraft.server.level.ServerPlayer) (Object) this); - - // Sponge Start: teleport here after all data is sent to avoid any potential "stuttering" due to slow packets. - final net.minecraft.world.phys.Vec3 finalPos = this.shadow$position(); - this.shadow$teleportTo(finalPos.x, finalPos.y, finalPos.z); - this.connection.resetPosition(); - // Sponge End - - for (final MobEffectInstance effectinstance : this.shadow$getActiveEffects()) { - this.connection.send(new ClientboundUpdateMobEffectPacket(this.shadow$getId(), effectinstance, false)); + thisPlayer.setCamera(thisPlayer); + thisPlayer.stopRiding(); + if (thisPlayer.isSleeping()) { + thisPlayer.stopSleepInBed(true, true); } - if (isNetherPortal) { // Sponge: only play the sound if we've got a vanilla teleporter that reports a nether portal - this.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false)); - } // Sponge: end if - this.lastSentExp = -1; - this.lastSentHealth = -1.0F; - this.lastSentFood = -1; - } - - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - @Redirect(method = "getExitPortal", - slice = @Slice( - from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getExitPortal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/level/border/WorldBorder;)Ljava/util/Optional;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;level()Lnet/minecraft/world/level/Level;") - ), - at = @At(value = "INVOKE", remap = false, target = "Ljava/util/Optional;isPresent()Z")) - private boolean impl$dontCreatePortalIfItsAlreadyBeenAttempted(final Optional optional) { - // This prevents a second attempt at a portal creation if the portal - // creation attempt due to a reposition event failed (this would put it - // in the original position, and we don't want that to happen!). - // - // In this case, we just force it to return the empty optional by - // claiming the optional is "present". - return this.impl$dontCreateExitPortal || optional.isPresent(); + return transition; } @Redirect( @@ -921,4 +892,20 @@ public void sendMessage(final OutgoingChatMessage $$0, final boolean $$1, final private boolean isPvpAllowed() { return ((ServerWorld) this.shadow$serverLevel()).properties().pvp(); } + + @Overwrite + public Entity changeDimension(final DimensionTransition transition) { + return this.bridge$changeDimension(transition); + } + + @Redirect(method = "findRespawnPositionAndUseSpawnBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getRespawnDimension()Lnet/minecraft/resources/ResourceKey;")) + private ResourceKey impl$callRespawnPlayerSelectWorld(final net.minecraft.server.level.ServerPlayer player) { + final var playerRespawnDestination = this.server.getLevel(player.getRespawnDimension()); + + final RespawnPlayerEvent.SelectWorld event = SpongeEventFactory.createRespawnPlayerEventSelectWorld(PhaseTracker.getCauseStackManager().currentCause(), + (ServerWorld) playerRespawnDestination, (ServerWorld) player.serverLevel(), (ServerWorld) playerRespawnDestination, (ServerPlayer) player); + SpongeCommon.post(event); + + return ((ServerLevel) event.destinationWorld()).dimension(); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java index 490e8aeaea6..4d6fee0b67b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java @@ -50,11 +50,11 @@ import net.minecraft.server.players.PlayerList; import net.minecraft.server.players.UserBanList; import net.minecraft.server.players.UserWhiteList; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.level.border.BorderChangeListener; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.storage.PlayerDataStorage; -import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.Nullable; import org.objectweb.asm.Opcodes; import org.slf4j.Logger; @@ -155,7 +155,7 @@ public abstract class PlayerListMixin implements PlayerListBridge { final net.minecraft.server.level.@Nullable ServerPlayer $$2, final ChatType.Bound $$4); // @formatter:on - private boolean impl$isGameMechanicRespawn = false; + private boolean impl$isRespawnWithPosition = false; private boolean impl$isDuringSystemMessageEvent = false; private ResourceKey impl$originalRespawnDestination = null; @@ -481,34 +481,20 @@ public abstract class PlayerListMixin implements PlayerListBridge { } @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - @Redirect( - method = "respawn", - at = @At( - value = "INVOKE", - target = "Ljava/util/Optional;isPresent()Z", - remap = false - ), - slice = @Slice( - from = @At(value = "INVOKE", target = "Ljava/util/Optional;empty()Ljava/util/Optional;", remap = false), - to = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;overworld()Lnet/minecraft/server/level/ServerLevel;") + @Inject(method = "respawn", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/server/level/ServerPlayer;findRespawnPositionAndUseSpawnBlock(ZLnet/minecraft/world/level/portal/DimensionTransition$PostDimensionTransition;)Lnet/minecraft/world/level/portal/DimensionTransition;" ) ) - private boolean impl$flagIfRespawnPositionIsGameMechanic(final Optional respawnPosition) { - this.impl$isGameMechanicRespawn = respawnPosition.isPresent(); - return false; // force call of MinecraftServer#overworld which is redirected into impl$callRespawnPlayerSelectWorld + private void impl$flagIfRespawnPositionIsGameMechanic(final net.minecraft.server.level.ServerPlayer $$0, final boolean $$1, + final Entity.RemovalReason $$2, final CallbackInfoReturnable cir) { + this.impl$isRespawnWithPosition = $$0.getRespawnPosition() != null; } - @Redirect(method = "respawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;overworld()Lnet/minecraft/server/level/ServerLevel;")) - private ServerLevel impl$callRespawnPlayerSelectWorld(final MinecraftServer server, final net.minecraft.server.level.ServerPlayer player) { - final ServerLevel playerRespawnDestination = server.getLevel(player.getRespawnDimension()); - final ServerLevel originalDestination = playerRespawnDestination != null && this.impl$isGameMechanicRespawn ? playerRespawnDestination : server.overworld(); - this.impl$originalRespawnDestination = originalDestination.dimension(); - - final RespawnPlayerEvent.SelectWorld event = SpongeEventFactory.createRespawnPlayerEventSelectWorld(PhaseTracker.getCauseStackManager().currentCause(), - (ServerWorld) originalDestination, (ServerWorld) player.serverLevel(), (ServerWorld) originalDestination, (ServerPlayer) player); - SpongeCommon.post(event); - - return (ServerLevel) event.destinationWorld(); + @Inject(method = "respawn", at = @At(value = "HEAD")) + private void impl$callRespawnPlayerSelectWorld(final net.minecraft.server.level.ServerPlayer player, final boolean $$1, + final Entity.RemovalReason $$2, final CallbackInfoReturnable cir) { + this.impl$originalRespawnDestination = player.getRespawnDimension(); } @Redirect( @@ -532,17 +518,18 @@ public abstract class PlayerListMixin implements PlayerListBridge { final RespawnPlayerEvent.Recreate event = SpongeEventFactory.createRespawnPlayerEventRecreate(PhaseTracker.getCauseStackManager().currentCause(), destinationPosition, originalWorld, originalPosition, destinationWorld, (ServerWorld) this.server.getLevel(this.impl$originalRespawnDestination), - destinationPosition, originalPlayer, recreatedPlayer, this.impl$isGameMechanicRespawn, !keepAllPlayerData); + destinationPosition, originalPlayer, recreatedPlayer, this.impl$isRespawnWithPosition, !keepAllPlayerData); SpongeCommon.post(event); - this.impl$isGameMechanicRespawn = false; + this.impl$isRespawnWithPosition = false; newPlayer.setPos(event.destinationPosition().x(), event.destinationPosition().y(), event.destinationPosition().z()); return newPlayer.getX(); } @Inject(method = "respawn", at = @At("RETURN")) - private void impl$callRespawnPlayerPostEvent(final net.minecraft.server.level.ServerPlayer player, final boolean keepAllPlayerData, final CallbackInfoReturnable cir) { + private void impl$callRespawnPlayerPostEvent(final net.minecraft.server.level.ServerPlayer player, final boolean $$1, final Entity.RemovalReason $$2, + final CallbackInfoReturnable cir) { final ServerPlayer recreatedPlayer = (ServerPlayer) cir.getReturnValue(); final ServerWorld originalWorld = (ServerWorld) player.serverLevel(); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java index a26ac2e7835..04cb9b268c3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java @@ -33,11 +33,8 @@ import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.RandomSource; @@ -46,19 +43,17 @@ import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LightningBolt; -import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.LavaCauldronBlock; +import net.minecraft.world.level.block.Portal; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.GameEvent; -import net.minecraft.world.level.portal.PortalInfo; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; @@ -84,8 +79,7 @@ import org.spongepowered.api.event.entity.MoveEntityEvent; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.util.Ticks; -import org.spongepowered.api.world.portal.Portal; -import org.spongepowered.api.world.portal.PortalTypes; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Final; @@ -101,6 +95,7 @@ import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; import org.spongepowered.common.accessor.server.level.ChunkMap_TrackedEntityAccessor; import org.spongepowered.common.accessor.world.entity.EntityAccessor; +import org.spongepowered.common.accessor.world.entity.PortalProcessorAccessor; import org.spongepowered.common.bridge.commands.CommandSourceProviderBridge; import org.spongepowered.common.bridge.data.DataCompoundHolder; import org.spongepowered.common.bridge.data.SpongeDataHolderBridge; @@ -108,8 +103,8 @@ import org.spongepowered.common.bridge.data.VanishableBridge; import org.spongepowered.common.bridge.world.entity.EntityBridge; import org.spongepowered.common.bridge.world.entity.PlatformEntityBridge; +import org.spongepowered.common.bridge.world.entity.PortalProcessorBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; -import org.spongepowered.common.bridge.world.level.PlatformServerLevelBridge; import org.spongepowered.common.data.DataUtil; import org.spongepowered.common.data.provider.nbt.NBTDataType; import org.spongepowered.common.data.provider.nbt.NBTDataTypes; @@ -117,24 +112,18 @@ import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.phase.entity.EntityPhase; -import org.spongepowered.common.event.tracking.phase.entity.TeleportContext; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.common.util.Constants; import org.spongepowered.common.util.DamageEventUtil; import org.spongepowered.common.util.ReflectionUtil; import org.spongepowered.common.util.VecHelper; -import org.spongepowered.common.world.portal.NetherPortalType; -import org.spongepowered.common.world.portal.PortalLogic; -import org.spongepowered.common.world.portal.SpongePortalInfo; -import org.spongepowered.common.world.portal.VanillaPortal; import org.spongepowered.math.vector.Vector3d; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; @Mixin(Entity.class) @@ -143,24 +132,13 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, // @formatter:off @Shadow public abstract Level shadow$level(); - @Shadow private float yRot; - @Shadow private float xRot; @Shadow public int invulnerableTime; - @Shadow public float walkDistO; - @Shadow public float walkDist; @Shadow @Final protected RandomSource random; @Shadow @Final protected SynchedEntityData entityData; @Shadow public float yRotO; - @Shadow protected int portalTime; @Shadow @Nullable private Entity vehicle; @Shadow private ImmutableList passengers; - @Shadow public float fallDistance; - @Shadow protected BlockPos portalEntrancePos; @Shadow private net.minecraft.world.phys.Vec3 position; - @Shadow private BlockPos blockPosition; - @Shadow public double xo; - @Shadow public double yo; - @Shadow public double zo; @Shadow private int remainingFireTicks; @Shadow protected UUID uuid; @Shadow private EntityDimensions dimensions; @@ -180,9 +158,6 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow public abstract boolean shadow$isInvisible(); @Shadow public abstract void shadow$setInvisible(boolean invisible); @Shadow public abstract EntityType shadow$getType(); - @Shadow public abstract boolean shadow$isInWater(); - @Shadow public abstract boolean shadow$isPassenger(); - @Shadow public abstract void shadow$teleportToWithTicket(double x, double y, double z); @Shadow public abstract void shadow$teleportTo(double x, double y, double z); @Shadow public abstract CommandSourceStack shadow$createCommandSourceStack(); @Shadow public abstract net.minecraft.world.phys.Vec3 shadow$position(); @@ -196,10 +171,6 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow public abstract net.minecraft.world.phys.Vec3 shadow$getDeltaMovement(); @Shadow public abstract void shadow$setDeltaMovement(net.minecraft.world.phys.Vec3 motion); @Shadow public abstract void shadow$unRide(); - @Shadow protected abstract Optional shadow$getExitPortal( - net.minecraft.server.level.ServerLevel targetWorld, BlockPos targetPosition, boolean isNether, WorldBorder $$3); - @Shadow protected abstract net.minecraft.world.phys.Vec3 shadow$getRelativePortalPosition(Direction.Axis direction$axis, - BlockUtil.FoundRectangle teleportationrepositioner$result); @Shadow protected abstract void shadow$removeAfterChangingDimensions(); @Shadow protected abstract int shadow$getPermissionLevel(); @Shadow public abstract float shadow$getYRot(); @@ -207,25 +178,17 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow public abstract void shadow$setYRot(final float param0); @Shadow protected abstract Vec3 shadow$collide(Vec3 param0); @Shadow public abstract boolean shadow$fireImmune(); - @Shadow protected abstract void shadow$markHurt(); - - @Shadow protected String stringUUID; - @Shadow @Nullable protected abstract PortalInfo shadow$findDimensionEntryPoint(ServerLevel param0); - - @Shadow public abstract int shadow$getPortalCooldown(); - @Shadow public abstract boolean shadow$onGround(); @Shadow @Nullable protected abstract String shadow$getEncodeId(); + @Shadow @javax.annotation.Nullable public PortalProcessor portalProcess; + // @formatter:on private boolean impl$isConstructing = true; private VanishState impl$vanishState = VanishState.unvanished(); protected boolean impl$transient = false; - private boolean impl$shouldFireRepositionEvent = true; - private WeakReference impl$originalDestinationWorld = null; - private boolean impl$customPortal = false; + protected boolean impl$moveEventsFired = false; protected boolean impl$hasCustomFireImmuneTicks = false; - protected boolean impl$dontCreateExitPortal = false; protected short impl$fireImmuneTicks = 0; private BlockPos impl$lastCollidedBlockPos; private Boolean impl$playerTouchDeclared; @@ -256,19 +219,7 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Override public boolean bridge$setPosition(final Vector3d position) { - if (this.shadow$isRemoved()) { - return false; - } - - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN); - final Vector3d destinationPosition = this.impl$fireMoveEvent(PhaseTracker.SERVER, position); - if (destinationPosition == null) { - return false; - } - final ServerLevel level = (ServerLevel) this.shadow$level(); - return this.impl$setLocation(false, level, level, destinationPosition); - } + return this.bridge$setLocation(ServerLocation.of((ServerWorld) this.shadow$level(), position)); } @Override @@ -280,12 +231,12 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN); - final net.minecraft.server.level.ServerLevel originalWorld = (ServerLevel) this.shadow$getCommandSenderWorld(); - final net.minecraft.server.level.ServerLevel originalDestinationWorld = (net.minecraft.server.level.ServerLevel) location.world(); - final net.minecraft.server.level.ServerLevel destinationWorld; + final ServerLevel originalWorld = (ServerLevel) this.shadow$level(); + final ServerLevel originalDestinationWorld = (ServerLevel) location.world(); + final ServerLevel destinationWorld; final @org.checkerframework.checker.nullness.qual.Nullable Vector3d destinationPosition; - final boolean isChangeOfWorld = this.shadow$getCommandSenderWorld() != originalDestinationWorld; + final boolean isChangeOfWorld = this.shadow$level() != originalDestinationWorld; if (isChangeOfWorld) { final ChangeEntityWorldEvent.Pre event = PlatformHooks.INSTANCE.getEventHooks() .callChangeEntityWorldEventPre((Entity) (Object) this, originalDestinationWorld); @@ -308,7 +259,8 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, } } - final boolean completed = this.impl$setLocation(isChangeOfWorld, originalDestinationWorld, destinationWorld, destinationPosition); + final boolean completed = this.impl$setLocation(isChangeOfWorld, destinationWorld, destinationPosition); + if (isChangeOfWorld) { Sponge.eventManager().post(SpongeEventFactory.createChangeEntityWorldEventPost( PhaseTracker.getCauseStackManager().currentCause(), @@ -322,22 +274,34 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, } } - protected boolean impl$setLocation(final boolean isChangeOfWorld, final ServerLevel originalDestinationWorld, final ServerLevel destinationWorld, - final Vector3d destinationPosition) { - ((Entity) (Object) this).unRide(); - if (isChangeOfWorld) { - final net.minecraft.server.level.ServerLevel originalWorld = (net.minecraft.server.level.ServerLevel) this.shadow$getCommandSenderWorld(); - ((PlatformServerLevelBridge) this.shadow$getCommandSenderWorld()).bridge$removeEntity((Entity) (Object) this, Entity.RemovalReason.CHANGED_DIMENSION, true); - this.bridge$revive(); - // TODO - Zidane, you want to take a look at this. -// this.shadow$setLevel(destinationWorld); - destinationWorld.addDuringTeleport((Entity) (Object) this); - - originalWorld.resetEmptyTime(); - destinationWorld.resetEmptyTime(); + /** + * {@link Entity#teleportTo(double, double, double)} + * {@link Entity#teleportTo(ServerLevel, double, double, double, Set, float, float)} + */ + protected boolean impl$setLocation(final boolean isChangeOfWorld, final ServerLevel level, final Vector3d pos) { + // TODO post teleport ticket needed? + + if (!isChangeOfWorld) { + this.shadow$teleportTo(pos.x(), pos.y(), pos.z()); + return true; } - return this.impl$teleportToWithTicket(destinationPosition.x(), destinationPosition.y(), destinationPosition.z(), false); + this.shadow$unRide(); + /*TODO old code had: + this.bridge$remove(Entity.RemovalReason.CHANGED_DIMENSION, true); // but via PlatformServerLevelBridge#bridge$removeEntity + this.bridge$revive(); + level.addDuringTeleport((Entity) (Object) this); + */ + var entity = this.shadow$getType().create(level); + if (entity == null) { + return false; + } + entity.restoreFrom((Entity) (Object) this); + entity.moveTo(pos.x(), pos.y(), pos.z()); + this.shadow$setRemoved(Entity.RemovalReason.CHANGED_DIMENSION); + level.addDuringTeleport(entity); + // TODO old code had reset empty time? on original/new world + return true; } @Override @@ -446,333 +410,126 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, return this.shadow$createCommandSourceStack(); } - @Redirect(method = "findDimensionEntryPoint", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/Entity;getExitPortal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/level/border/WorldBorder;)Ljava/util/Optional;")) - private Optional impl$redirectGetExitPortal( - final Entity thisEntity, - final net.minecraft.server.level.ServerLevel targetWorld, - final BlockPos targetPosition, - final boolean targetIsNether, - final WorldBorder $$3) { - try { - return this.shadow$getExitPortal(targetWorld, targetPosition, targetIsNether, $$3); - } finally { - // Reset for the next attempt. - this.impl$dontCreateExitPortal = false; - } - } - - @Redirect(method = "findDimensionEntryPoint", - at = @At(value = "FIELD", opcode = Opcodes.GETSTATIC, - target = "Lnet/minecraft/world/level/Level;END:Lnet/minecraft/resources/ResourceKey;")) - private ResourceKey impl$getNullInsteadOfEndIfCreatingCustomPortal() { - if (this.impl$customPortal) { - // This will cause the first two conditions to be false, meaning that the - // standard portal checks will be disabled an a nether portal can go - // in any dimension - return null; - } - return Level.END; + /** + * @author faithcaio + * @reason handle dimension change events see {@link #bridge$changeDimension(DimensionTransition)} + * + * TODO we may need to separate into Vanilla and Forge again + */ + @Overwrite + public Entity changeDimension(final DimensionTransition transition) { + return this.bridge$changeDimension(transition); } - @Redirect(method = "findDimensionEntryPoint", - at = @At(value = "FIELD", opcode = Opcodes.GETSTATIC, - target = "Lnet/minecraft/world/level/Level;NETHER:Lnet/minecraft/resources/ResourceKey;")) - private ResourceKey impl$forceCheckToBeTrueIfCreatingCustomPortal(final ServerLevel targetDimension) { - if (this.impl$customPortal) { - // This will cause "var4" to be true in the second if check, - // meaning that the portal finding logic will always fire - // - // This also has the side effect of setting the other Level.NETHER - // access too, but that's okay as long as var4 is true. - return targetDimension.dimension(); + @Inject(method = "setAsInsidePortal", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER, + target = "Lnet/minecraft/world/entity/Entity;portalProcess:Lnet/minecraft/world/entity/PortalProcessor;")) + public void impl$onCreatePortalProcessor(final Portal $$0, final BlockPos $$1, final CallbackInfo ci) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()){ + var be = this.shadow$level().getBlockEntity(this.portalProcess.getEntryPosition()); + if (be != null) { + frame.pushCause(be); + } + frame.pushCause(this); + var portal = ((PortalProcessorAccessor)this.portalProcess).accessor$portal(); + ((PortalProcessorBridge)this.portalProcess).bridge$init(this.shadow$level()); + frame.pushCause(portal); + + final int portalTransitionTime = $$0.getPortalTransitionTime((ServerLevel) this.shadow$level(), (Entity) (Object) this); + var event = SpongeEventFactory.createInvokePortalEventEnter(frame.currentCause(), + (org.spongepowered.api.entity.Entity) this, + Optional.empty(), + (PortalLogic) $$0, + portalTransitionTime); + if (SpongeCommon.post(event)) { + this.portalProcess = null; + } else { + event.customPortalTransitionTime().ifPresent(customTime -> { + ((PortalProcessorBridge)this.portalProcess).bridge$setTransitionTime(customTime); + }); + } } - return Level.NETHER; - } - - @Redirect(method = "findDimensionEntryPoint", at = @At(value = "NEW", target = "net/minecraft/world/level/portal/PortalInfo")) - private PortalInfo impl$addPortalToPortalInfoForEnd(final Vec3 var1, final Vec3 var2, final float var3, final float var4, final ServerLevel serverLevel) { - final Portal portal = new VanillaPortal(PortalTypes.END.get(), ((ServerWorld) serverLevel).location(VecHelper.toVector3d(var1)), null); - return new SpongePortalInfo(var1, var2, var3, var4, portal); } - /* - * Used in bridge$changeDimension + /** + * See {@link PortalProcessorMixin#impl$onGetPortalDestination} for portal events */ - protected Entity impl$portalRepositioning(final boolean createEndPlatform, - final net.minecraft.server.level.ServerLevel serverworld, - final net.minecraft.server.level.ServerLevel targetWorld, - final PortalInfo portalinfo) { - serverworld.getProfiler().popPush("reloading"); - final Entity entity = this.shadow$getType().create(targetWorld); - if (entity != null) { - entity.restoreFrom((Entity) (Object) this); - entity.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z, portalinfo.yRot, entity.getXRot()); - entity.setDeltaMovement(portalinfo.speed); - targetWorld.addDuringTeleport(entity); - if (createEndPlatform && targetWorld.dimension() == Level.END) { - net.minecraft.server.level.ServerLevel.makeObsidianPlatform(targetWorld); + @Redirect(method = "handlePortal", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;changeDimension(Lnet/minecraft/world/level/portal/DimensionTransition;)Lnet/minecraft/world/entity/Entity;")) + public Entity impl$onChangeDimension(final Entity instance, final DimensionTransition transition) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(this); + var be = this.shadow$level().getBlockEntity(this.portalProcess.getEntryPosition()); + if (be != null) { + frame.pushCause(be); } + final var portal = ((PortalProcessorAccessor) this.portalProcess).accessor$portal(); + frame.pushCause(portal); + var movementType = portal == Blocks.END_GATEWAY ? MovementTypes.END_GATEWAY : MovementTypes.PORTAL; + frame.addContext(EventContextKeys.MOVEMENT_TYPE, movementType); + frame.addContext(EventContextKeys.PORTAL_LOGIC, (PortalLogic) portal); + // TODO frame.addContext(EventContextKeys.PORTAL, transition); + // TODO 2-dim portal? + this.impl$moveEventsFired = true; + return instance.changeDimension(transition); + } finally { + this.impl$moveEventsFired = false; } - return entity; - } - - /* - * Used in bridge$changeDimension - */ - protected void impl$postPortalForceChangeTasks(final Entity entity, final net.minecraft.server.level.ServerLevel targetWorld, - final boolean isVanilla) { - this.shadow$removeAfterChangingDimensions(); - this.shadow$level().getProfiler().pop(); - ((net.minecraft.server.level.ServerLevel) this.shadow$level()).resetEmptyTime(); - targetWorld.resetEmptyTime(); - this.shadow$level().getProfiler().pop(); - } - - /* - * Used in classes that add to the changeDimension behaviour - */ - protected @org.checkerframework.checker.nullness.qual.Nullable Entity impl$postProcessChangeDimension(final Entity entity) { - return entity; } /** - * This is effectively an overwrite of changeDimension: required due to - * Forge changing the signature. - * - * @author dualspiral - 18th December 2020 - 1.16.4 - * @author dualspiral - 8th August 2021 - 1.16.5 (adjusted for SpongeForge) + * This is effectively an overwrite of changeDimension. * - * @param originalDestinationWorld The original target world - * @param originalPortalLogic performs additional teleportation logic, as required. * @return The {@link Entity} that is either this one, or replaces this one */ @SuppressWarnings("ConstantConditions") - @org.checkerframework.checker.nullness.qual.Nullable - public Entity bridge$changeDimension(final net.minecraft.server.level.ServerLevel originalDestinationWorld, final PortalLogic originalPortalLogic) { - // Sponge Start - if (this.shadow$getCommandSenderWorld().isClientSide || this.shadow$isRemoved()) { + @Nullable + public Entity bridge$changeDimension(final DimensionTransition transition) { + final Entity thisEntity = (Entity) (Object) this; + if (!(thisEntity.level() instanceof ServerLevel oldLevel) || this.shadow$isRemoved()) { // Sponge inverted check return null; } - final boolean isPlayer = ((Object) this) instanceof ServerPlayer; - - final TeleportContext contextToSwitchTo = - EntityPhase.State.PORTAL_DIMENSION_CHANGE.createPhaseContext(PhaseTracker.getInstance()).worldChange(); - if (isPlayer) { - contextToSwitchTo.player(); + // TODO context/events for non-players + var newLevel = transition.newLevel(); + var passengers = thisEntity.getPassengers(); + List recreatedPassengers = new ArrayList<>(); + this.shadow$unRide(); + for (final Entity passenger : passengers) { + var recreatedPassenger = passenger.changeDimension(transition); + if (recreatedPassenger != null) { + recreatedPassengers.add(recreatedPassenger); + } } - try (final TeleportContext context = contextToSwitchTo.buildAndSwitch(); - final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(this); - frame.pushCause(originalPortalLogic.getPortalType()); - frame.addContext(EventContextKeys.MOVEMENT_TYPE, originalPortalLogic.getMovementType()); - this.impl$originalDestinationWorld = new WeakReference<>((ServerWorld) originalDestinationWorld); + oldLevel.getProfiler().push("changeDimension"); - final ChangeEntityWorldEvent.Pre preChangeEvent = - PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre((Entity) (Object) this, originalDestinationWorld); - if (preChangeEvent.isCancelled()) { - this.impl$onPreWorldChangeCanceled(); - return null; - } - this.impl$customPortal = preChangeEvent.originalDestinationWorld() != preChangeEvent.destinationWorld(); - final PortalLogic finalPortalLogic; - if (this.impl$customPortal && originalPortalLogic == originalDestinationWorld.getPortalForcer()) { - finalPortalLogic = (PortalLogic) ((ServerLevel) preChangeEvent.destinationWorld()).getPortalForcer(); - } else { - finalPortalLogic = originalPortalLogic; + var newEntity = oldLevel.dimension() == newLevel.dimension() ? thisEntity : thisEntity.getType().create(newLevel); + if (newEntity != null) { + if (thisEntity != newEntity) { + newEntity.restoreFrom(thisEntity); + this.shadow$removeAfterChangingDimensions(); } - final net.minecraft.server.level.ServerLevel targetWorld = (net.minecraft.server.level.ServerLevel) preChangeEvent.destinationWorld(); - final Vector3d currentPosition = VecHelper.toVector3d(this.shadow$position()); - // If a player, set the fact they are changing dimensions - this.impl$onChangingDimension(targetWorld); - - final net.minecraft.server.level.ServerLevel serverworld = (net.minecraft.server.level.ServerLevel) this.shadow$level(); - final ResourceKey registrykey = serverworld.dimension(); - if (isPlayer && registrykey == Level.END && targetWorld.dimension() == Level.OVERWORLD && finalPortalLogic.isVanilla()) { // avoids modded dimensions - return this.impl$postProcessChangeDimension(this.impl$performGameWinLogic()); - } else { - // Sponge Start: Redirect the find portal call to the teleporter. - - // If this is vanilla, this will house our Reposition Event and return an appropriate - // portal info - final PortalInfo portalinfo = originalPortalLogic.getPortalInfo((Entity) (Object) this, targetWorld, - x -> this.shadow$findDimensionEntryPoint(x)); // don't make this a method reference, it'll crash vanilla. - // Sponge End - if (portalinfo != null) { - if (portalinfo instanceof SpongePortalInfo) { - frame.addContext(EventContextKeys.PORTAL, ((SpongePortalInfo) portalinfo).portal()); - } - // Only start teleporting if we have somewhere to go. - this.impl$prepareForPortalTeleport(serverworld, targetWorld); - try { - // Sponge Start: wrap the teleportation logic within a function to allow for modification - // of the teleporter - final Vector3d originalDestination = new Vector3d(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z); - - // Note that impl$portalRepositioning is the lambda. As this will be different in ServerPlayer, - // we transfer it to a method instead so we can override it. - final Entity transportedEntity = - originalPortalLogic.placeEntity((Entity) (Object) this, serverworld, targetWorld, this.yRot, - createEndPlatform -> - this.impl$portalRepositioning(createEndPlatform, serverworld, targetWorld, portalinfo)); - // Make sure the right object was returned - this.impl$validateEntityAfterTeleport(transportedEntity, originalPortalLogic); - - // If we need to reposition: well... reposition. - // Downside: portals won't come with us, but with how it's implemented in Forge, - // not sure how we'd do this. - // - // If this is vanilla, we've already fired and dealt with the event - final Cause cause = PhaseTracker.getCauseStackManager().currentCause(); - if (transportedEntity != null && this.impl$shouldFireRepositionEvent) { - final Vector3d destination = VecHelper.toVector3d(this.shadow$position()); - final ChangeEntityWorldEvent.Reposition reposition = SpongeEventFactory.createChangeEntityWorldEventReposition( - cause, - (org.spongepowered.api.entity.Entity) transportedEntity, - (org.spongepowered.api.world.server.ServerWorld) serverworld, - currentPosition, - destination, - (org.spongepowered.api.world.server.ServerWorld) originalDestinationWorld, - originalDestination, - (org.spongepowered.api.world.server.ServerWorld) targetWorld - ); - final Vector3d finalPosition; - if (SpongeCommon.post(reposition)) { - // send them back to the original destination - finalPosition = originalDestination; - } else if (reposition.destinationPosition() != destination) { - finalPosition = reposition.destinationPosition(); - } else { - finalPosition = null; - } - - if (finalPosition != null) { - // TODO: Rollback captures during phase - anything generated needs to vanish here - // Issue chunk ticket of type Portal, even if a portal isn't being created here. - final BlockPos ticketPos = VecHelper.toBlockPos(finalPosition); - targetWorld.getChunkSource().addRegionTicket(TicketType.PORTAL, new ChunkPos(ticketPos), 3, ticketPos); - - this.shadow$absMoveTo(finalPosition.x(), finalPosition.y(), finalPosition.z()); - } - } - - // Used to perform player specific tasks. - this.impl$postPortalForceChangeTasks(transportedEntity, targetWorld, originalPortalLogic.getPortalType() instanceof NetherPortalType); - // Call post event - Sponge.eventManager().post( - SpongeEventFactory.createChangeEntityWorldEventPost( - cause, - (org.spongepowered.api.entity.Entity) this, - (ServerWorld) serverworld, - (ServerWorld) originalDestinationWorld, - (ServerWorld) targetWorld - ) - ); - } catch (final RuntimeException e) { - // nothing throws a checked exception in this block, but we want to catch unchecked stuff and try to recover - // just in case a mod does something less than clever. - if ((Object) this instanceof ServerPlayer) { - this.impl$postPortalForceChangeTasks((Entity) (Object) this, (net.minecraft.server.level.ServerLevel) this.shadow$level(), false); - } - throw e; - } - // Sponge End - } else { - // Didn't work out. - return null; - } + newEntity.moveTo(transition.pos().x, transition.pos().y, transition.pos().z, transition.yRot(), newEntity.getXRot()); + newEntity.setDeltaMovement(transition.speed()); + if (thisEntity != newEntity) { + newLevel.addDuringTeleport(newEntity); } - return this.impl$postProcessChangeDimension((Entity) (Object) this); - } finally { - // Reset for the next attempt. - this.impl$shouldFireRepositionEvent = true; - this.impl$originalDestinationWorld = null; - this.impl$customPortal = false; - } - } - - protected void impl$onPreWorldChangeCanceled() { - // intentional no-op - } - - protected void impl$onChangingDimension(final ServerLevel target) { - // intentional no-op - } - - protected void impl$prepareForPortalTeleport(final ServerLevel currentWorld, final ServerLevel targetWorld) { - // intentional no-op - } - - protected void impl$validateEntityAfterTeleport(final Entity e, final PortalLogic teleporter) { - // intentional no-op - } + for (Entity recreatedPassenger : recreatedPassengers) { + recreatedPassenger.startRiding(newEntity, true); + } - protected Entity impl$performGameWinLogic() { - return (Entity) (Object) this; - } + oldLevel.resetEmptyTime(); + newLevel.resetEmptyTime(); + transition.postDimensionTransition().onTransition(newEntity); - /** - * This is from Entity#findDimensionEntryPoint, for determining the destination position before - * a portal is created (lambda in the return statement after getExitPortal) - * - * This is only fired if a portal exists, thus the blockstate checks are okay. - */ - private Vector3d impl$getEntityPositionInPotentialExitPortal(final BlockUtil.FoundRectangle result) { - final BlockState blockstate = this.shadow$level().getBlockState(this.portalEntrancePos); - final Direction.Axis direction$axis; - final net.minecraft.world.phys.Vec3 vector3d; - if (blockstate.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) { - direction$axis = blockstate.getValue(BlockStateProperties.HORIZONTAL_AXIS); - final BlockUtil.FoundRectangle teleportationrepositioner$result = BlockUtil.getLargestRectangleAround(this.portalEntrancePos, direction$axis, 21, Direction.Axis.Y, 21, (p_242276_2_) -> { - return this.shadow$level().getBlockState(p_242276_2_) == blockstate; - }); - vector3d = this.shadow$getRelativePortalPosition(direction$axis, teleportationrepositioner$result); - } else { - vector3d = new net.minecraft.world.phys.Vec3(0.5D, 0.0D, 0.0D); } - return VecHelper.toVector3d(vector3d); - } - - @Inject(method = "getExitPortal", cancellable = true, at = @At("RETURN")) - private void impl$fireRepositionEventWhenFindingAPortal(final net.minecraft.server.level.ServerLevel targetWorld, - final BlockPos targetPosition, - final boolean targetIsNether, - final WorldBorder $$3, - final CallbackInfoReturnable> cir) { - if (this.impl$shouldFireRepositionEvent) { - // This exists as we're injecting at return - final Optional result = cir.getReturnValue(); - final Vector3d destinationPosition = result.map(this::impl$getEntityPositionInPotentialExitPortal) - .orElseGet(() -> VecHelper.toVector3d(targetPosition)); - final ServerWorld originalDestinationWorld; - if (this.impl$originalDestinationWorld != null && this.impl$originalDestinationWorld.get() != null) { - originalDestinationWorld = this.impl$originalDestinationWorld.get(); - } else { - originalDestinationWorld = (ServerWorld) targetWorld; - } - final ChangeEntityWorldEvent.Reposition reposition = this.bridge$fireRepositionEvent( - originalDestinationWorld, - (ServerWorld) targetWorld, - destinationPosition - ); + // TODO impl$fireMoveEvent when not changing dimensions (e.g. EndGateways) - if (reposition.isCancelled()) { - cir.setReturnValue(Optional.empty()); - this.impl$dontCreateExitPortal = true; - } - else if (reposition.destinationPosition() != destinationPosition) { - // Something changed so we want to re-rerun this loop. - // TODO: There is an open question here about whether we want to force the creation of a portal in this - // scenario, or whether we're happy if the repositioning will put someone in a nearby portal. - cir.setReturnValue(this.shadow$getExitPortal(targetWorld, VecHelper.toBlockPos(reposition.destinationPosition()), targetIsNether, $$3)); - this.impl$dontCreateExitPortal = true; - } - } + oldLevel.getProfiler().pop(); + return newEntity; } @Override @@ -780,7 +537,7 @@ else if (reposition.destinationPosition() != destinationPosition) { final ServerWorld targetWorld, final Vector3d destinationPosition) { - this.impl$shouldFireRepositionEvent = false; + this.impl$moveEventsFired = true; final ChangeEntityWorldEvent.Reposition reposition = SpongeEventFactory.createChangeEntityWorldEventReposition( PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.entity.Entity) this, @@ -811,44 +568,6 @@ else if (reposition.destinationPosition() != destinationPosition) { return NBTDataTypes.ENTITY; } - /** - * @author Zidane - * @reason This is a catch-all method to ensure MoveEntityEvent is fired with - * useful information. We redirect to impl$teleportToWithTicket to - * be able to return whether or not a teleport happened. - */ - @Overwrite - public final void teleportToWithTicket(final double x, final double y, final double z) { - this.impl$teleportToWithTicket(x, y, z, true); - } - - /* - * (non-Javadoc) - * - * This is a modified version of teleportToWithTicket, treat this as an overwrite - * see above. - */ - public final boolean impl$teleportToWithTicket(final double x, final double y, final double z, final boolean fireMoveEvent) { - if (this.shadow$level() instanceof net.minecraft.server.level.ServerLevel) { - // Sponge start - final Vector3d destinationPosition; - if (ShouldFire.MOVE_ENTITY_EVENT && fireMoveEvent) { - destinationPosition = this.impl$fireMoveEvent(PhaseTracker.SERVER, new Vector3d(x, y, z)); - } else { - destinationPosition = new Vector3d(x, y, z); - } - // Sponge end - final ChunkPos chunkpos = new ChunkPos(new BlockPos(destinationPosition.floorX(), destinationPosition.floorY(), destinationPosition.floorZ())); - ((net.minecraft.server.level.ServerLevel) this.shadow$level()).getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 0, - this.shadow$getId()); - this.shadow$level().getChunk(chunkpos.x, chunkpos.z); - this.shadow$teleportTo(destinationPosition.x(), destinationPosition.y(), destinationPosition.z()); - // Sponge: return success - return true; - } - // Sponge: return failure - return false; - } protected final @org.checkerframework.checker.nullness.qual.Nullable Vector3d impl$fireMoveEvent( final PhaseTracker phaseTracker, final Vector3d originalDestinationPosition) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/PortalProcessorMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/PortalProcessorMixin.java new file mode 100644 index 00000000000..ba4e8190e87 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/PortalProcessorMixin.java @@ -0,0 +1,166 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Portal; +import net.minecraft.world.level.portal.DimensionTransition; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.EventContextKeys; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.cause.entity.MovementTypes; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.world.entity.PortalProcessorBridge; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.phase.entity.EntityPhase; +import org.spongepowered.common.event.tracking.phase.entity.TeleportContext; +import org.spongepowered.common.hooks.PlatformHooks; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.math.vector.Vector3d; + +@Mixin(PortalProcessor.class) +public abstract class PortalProcessorMixin implements PortalProcessorBridge { + // @formatter:off + @Shadow private Portal portal; + @Shadow private BlockPos entryPosition; + // @formatter:on + + private Level impl$level; + private Integer impl$customPortalTransitionTime; + + @Redirect(method = "processPortalTeleportation", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Portal;getPortalTransitionTime(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;)I")) + public int impl$onGetPortalDestination(final Portal instance, final ServerLevel $$0, final Entity $$1) { + if (this.impl$customPortalTransitionTime != null) { + return this.impl$customPortalTransitionTime; + } + return instance.getPortalTransitionTime($$0, $$1); + } + + + @Redirect(method = "getPortalDestination", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Portal;getPortalDestination(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/portal/DimensionTransition;")) + public DimensionTransition impl$onGetPortalDestination(final Portal instance, final ServerLevel serverLevel, final Entity entity, final BlockPos blockPos) { + final var spongEntity = (org.spongepowered.api.entity.Entity) entity; + + var finalPortal = instance; + final var contextToSwitchTo = EntityPhase.State.PORTAL_DIMENSION_CHANGE.createPhaseContext(PhaseTracker.getInstance()).worldChange(); + if (entity instanceof ServerPlayer) { + contextToSwitchTo.player(); + } + + try (final TeleportContext context = contextToSwitchTo.buildAndSwitch(); + final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(entity); + var be = serverLevel.getBlockEntity(this.entryPosition); + if (be != null) { + frame.pushCause(be); + } + frame.pushCause(this.portal); // portal type + + var wrapperTransaction = context.getTransactor().logWrapper(); + + var movementType = this.portal == Blocks.END_GATEWAY ? MovementTypes.END_GATEWAY : MovementTypes.PORTAL; + frame.addContext(EventContextKeys.MOVEMENT_TYPE, movementType); + frame.addContext(EventContextKeys.PORTAL_LOGIC, (PortalLogic) portal); + + var preEvent = SpongeEventFactory.createInvokePortalEventPrepare(frame.currentCause(), spongEntity, (PortalLogic) this.portal); + if (SpongeCommon.post(preEvent)) { + return null; + } + finalPortal = (Portal) preEvent.portalLogic(); + + final var transition = finalPortal.getPortalDestination(serverLevel, entity, blockPos); + + frame.popCause(); + + if (transition == null) { + return null; + } + + frame.pushCause(finalPortal); + frame.addContext(EventContextKeys.PORTAL, (org.spongepowered.api.world.portal.Portal) this); + + var preWorldChangeEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre(entity, transition.newLevel()); + if (preWorldChangeEvent.isCancelled()) { + wrapperTransaction.markCancelled(); + return null; + } + + var tpEvent = SpongeEventFactory.createInvokePortalEventExecute(frame.currentCause(), + spongEntity, + (ServerWorld) entity.level(), + new Vector3d(transition.xRot(), transition.yRot(), 0), + spongEntity.position(), + spongEntity.rotation(), + (ServerWorld) transition.newLevel(), + VecHelper.toVector3d(transition.pos()), + VecHelper.toVector3d(transition.pos()), + preWorldChangeEvent.destinationWorld(), // with modified preWorldChangeEvent destination world + VecHelper.toVector3d(transition.speed()), + (PortalLogic) finalPortal); + if (SpongeCommon.post(tpEvent)) { + wrapperTransaction.markCancelled(); + return null; + } + + // modify transition after event + return new DimensionTransition((ServerLevel) tpEvent.destinationWorld(), + VecHelper.toVanillaVector3d(tpEvent.destinationPosition()), + VecHelper.toVanillaVector3d(tpEvent.exitSpeed()), + (float) tpEvent.toRotation().x(), + (float) tpEvent.toRotation().y(), + transition.missingRespawnBlock(), + transition.postDimensionTransition()); + } + } + + @Override + public void bridge$init(final Level level) { + this.impl$level = level; + } + + @Override + public void bridge$setTransitionTime(final Integer customTime) { + this.impl$customPortalTransitionTime = customTime; + } + + @Override + public Level bridge$level() { + return this.impl$level; + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java index 08cc82ebe88..9878b73d664 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java @@ -27,7 +27,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; import net.minecraft.core.BlockPos; -import net.minecraft.core.GlobalPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.syncher.EntityDataAccessor; @@ -41,7 +40,6 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Abilities; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player.BedSleepingProblem; import net.minecraft.world.food.FoodData; @@ -74,7 +72,6 @@ import org.spongepowered.common.bridge.authlib.GameProfileHolderBridge; import org.spongepowered.common.bridge.server.level.ServerLevelBridge; import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; -import org.spongepowered.common.bridge.world.entity.PlatformEntityBridge; import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; import org.spongepowered.common.bridge.world.food.FoodDataBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; @@ -88,7 +85,6 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; @Mixin(net.minecraft.world.entity.player.Player.class) public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBridge, GameProfileHolderBridge { @@ -98,12 +94,9 @@ public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBri @Shadow public int experienceLevel; @Shadow public int totalExperience; @Shadow public float experienceProgress; - @Shadow @Final private Abilities abilities; - @Shadow @Final private net.minecraft.world.entity.player.Inventory inventory; @Shadow public AbstractContainerMenu containerMenu; @Shadow @Final public InventoryMenu inventoryMenu; @Shadow @Final private GameProfile gameProfile; - @Shadow public abstract boolean shadow$isSpectator(); @Shadow public abstract int shadow$getXpNeededForNextLevel(); @Shadow @Nullable public abstract ItemEntity shadow$drop(final ItemStack droppedItem, final boolean dropAround, final boolean traceItem); @@ -115,19 +108,15 @@ public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBri @Shadow public abstract Component shadow$getDisplayName(); @Shadow protected abstract void shadow$removeEntitiesOnShoulder(); @Shadow public abstract void shadow$awardStat(ResourceLocation stat); - @Shadow public abstract Abilities shadow$getAbilities(); @Shadow public abstract Inventory shadow$getInventory(); @Shadow public Either shadow$startSleepInBed(final BlockPos param0) { return null; // Shadowed } @Shadow protected abstract void shadow$playShoulderEntityAmbientSound(CompoundTag p_192028_1_); - @Shadow public abstract Optional shadow$getLastDeathLocation(); // @formatter: on - - private boolean impl$affectsSpawning = true; - protected final boolean impl$isFake = ((PlatformEntityBridge) (net.minecraft.world.entity.player.Player) (Object) this).bridge$isFakePlayer(); + protected final boolean impl$isFake = this.bridge$isFakePlayer(); @Override public boolean bridge$affectsSpawning() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrowableProjectileMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrowableProjectileMixin.java index d8cfebbe9ea..5a511885484 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrowableProjectileMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrowableProjectileMixin.java @@ -24,21 +24,14 @@ */ package org.spongepowered.common.mixin.core.world.entity.projectile; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.projectile.ProjectileDeflection; import net.minecraft.world.entity.projectile.ThrowableProjectile; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.HitResult; -import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; -import org.spongepowered.common.event.tracking.PhaseTracker; @Mixin(ThrowableProjectile.class) public abstract class ThrowableProjectileMixin extends ProjectileMixin { @@ -61,23 +54,4 @@ public abstract class ThrowableProjectileMixin extends ProjectileMixin { } } - @Redirect(method = "tick", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/level/block/entity/TheEndGatewayBlockEntity;teleportEntity(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/level/block/entity/TheEndGatewayBlockEntity;)V" - ) - ) - private void impl$createCauseFrameForGatewayTeleport( - final Level level, final BlockPos pos, final BlockState state, final Entity self, final TheEndGatewayBlockEntity gateway - ) { - if (this.shadow$getCommandSenderWorld().isClientSide) { - return; - } - - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(gateway); - frame.pushCause(self); - TheEndGatewayBlockEntity.teleportEntity(level, pos, state, self, gateway); - } - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrownEnderpearlMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrownEnderpearlMixin.java index 94ac18ebc52..878e79e0b9e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrownEnderpearlMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/ThrownEnderpearlMixin.java @@ -26,23 +26,15 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.projectile.ThrownEnderpearl; -import net.minecraft.world.phys.HitResult; -import org.checkerframework.checker.nullness.qual.Nullable; +import net.minecraft.world.level.portal.DimensionTransition; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.event.entity.MoveEntityEvent; 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.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.ShouldFire; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3d; @Mixin(ThrownEnderpearl.class) public abstract class ThrownEnderpearlMixin extends ThrowableProjectileMixin { @@ -57,46 +49,17 @@ public abstract class ThrownEnderpearlMixin extends ThrowableProjectileMixin { return (float) this.impl$damageAmount; } - @Inject( - method = "onHit", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;teleportTo(DDD)V"), - cancellable = true + @Redirect(method = "onHit", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;changeDimension(Lnet/minecraft/world/level/portal/DimensionTransition;)Lnet/minecraft/world/entity/Entity;") ) - private void impl$callMoveEntityEventForThrower(final HitResult result, final CallbackInfo ci) { - if (this.shadow$getCommandSenderWorld().isClientSide || !ShouldFire.MOVE_ENTITY_EVENT) { - return; - } + private Entity impl$callMoveEntityEventForThrower(final Entity instance, final DimensionTransition $$0) { final Entity entity = this.shadow$getOwner(); - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { frame.pushCause(entity); frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.ENDER_PEARL); - final MoveEntityEvent event = SpongeEventFactory.createMoveEntityEvent(frame.currentCause(), - (org.spongepowered.api.entity.Entity) entity, VecHelper.toVector3d(entity.position()), - VecHelper.toVector3d(this.shadow$position()), VecHelper.toVector3d(this.shadow$position())); - if (SpongeCommon.post(event)) { - // Eventhough the event is made, the pearl was still created so remove it anyways - this.shadow$discard(); - ci.cancel(); - return; - } - - // This seems odd but we move the pearl so that the pearl's logic will move the living entity later in the impact method - final Vector3d destinationPosition = event.destinationPosition(); - this.shadow$setPos(destinationPosition.x(), destinationPosition.y(), destinationPosition.z()); + return instance.changeDimension($$0); } } - @Override - @Nullable - public Entity impl$postProcessChangeDimension(final Entity entity) { - if (entity instanceof ThrownEnderpearl) { - // We actually teleported so... - this.shadow$setOwner(null); - } - - return entity; - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/AbstractMinecartContainerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/AbstractMinecartContainerMixin.java index f19f01d48fe..5cee1271dad 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/AbstractMinecartContainerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/vehicle/AbstractMinecartContainerMixin.java @@ -24,27 +24,10 @@ */ package org.spongepowered.common.mixin.core.world.entity.vehicle; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.vehicle.AbstractMinecartContainer; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.asm.mixin.Mixin; @Mixin(AbstractMinecartContainer.class) public abstract class AbstractMinecartContainerMixin extends AbstractMinecartMixin { - /** - * @author Zidane - June 2019 - 1.12.2 - * @author i509VCB - Feb 2020 - 1.14.4 - * @author dualspiral - 24th July 2021 - 1.16.5 - * @author dualspiral - 27th July 2021 - 1.17.1 - * @reason Only have this Minecart not drop contents if we actually changed dimension - * TODO: This is a no-op but left here for the moment - check to see if this - * is still needed - */ - @Override - @Nullable - protected Entity impl$postProcessChangeDimension(final Entity entity) { - return entity; - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java index ecb96f324c8..74e5aca88c8 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java @@ -24,21 +24,90 @@ */ package org.spongepowered.common.mixin.core.world.level.block; +import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EndPortalBlock; +import net.minecraft.world.level.levelgen.feature.EndPlatformFeature; +import net.minecraft.world.level.portal.DimensionTransition; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.common.bridge.world.entity.EntityBridge; -import org.spongepowered.common.world.portal.VanillaPortalLogic; +import org.spongepowered.common.bridge.world.level.block.PortalBlockBridge; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.common.world.portal.SpongePortal; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Optional; @Mixin(EndPortalBlock.class) -public abstract class EndPortalBlockMixin { +public abstract class EndPortalBlockMixin implements PortalBlockBridge { + + @Override + public Optional bridge$calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final Entity entity) { + final var fromLevel = (ServerLevel) from.world(); + final var toLevelKey = fromLevel.dimension() == Level.END ? Level.OVERWORLD : Level.END; + final var toLevel = fromLevel.getServer().getLevel(toLevelKey); + if (toLevel == null) { + return Optional.empty(); + } + return Optional.of(EndPortalBlockMixin.impl$calculateVanillaPortalExit(entity, toLevel)); + } + + private static ServerLocation impl$calculateVanillaPortalExit(final Entity entity, final ServerLevel toLevel) { + final var toEnd = toLevel.dimension() == Level.END; + if (toEnd) { + return ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3i(ServerLevel.END_SPAWN_POINT)); + } + + if (entity instanceof ServerPlayer player) { + var transition = player.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); + return ServerLocation.of((ServerWorld) transition.newLevel(), VecHelper.toVector3d(transition.pos())); + } + + final var sharedSpawnPos = toLevel.getSharedSpawnPos(); + final var spawnPos = ((net.minecraft.world.entity.Entity) entity).adjustSpawnLocation(toLevel, sharedSpawnPos).getBottomCenter(); + return ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3d(spawnPos)); + } + + + @Override + public Optional bridge$findPortal(final ServerLocation at, final int searchRange) { + final var level = (ServerLevel) at.world(); + if (level.dimension() == Level.END) { + return Optional.empty(); // End platform always generates + } + return Optional.of(new SpongePortal(at, (PortalLogic) this)); // this should be spawn - but the parameter takes precedence + } + + @Override + public Optional bridge$generatePortal(final ServerLocation at, final Axis axis) { + final var level = (ServerLevel) at.world(); + // If a target dimension is set assume we always want to generate a portal otherwise we could have used a spawn teleporter + if (level.dimension() == Level.END) { + final var bottomCenter = VecHelper.toBlockPos(at.blockPosition()).getBottomCenter(); + EndPlatformFeature.createEndPlatform(level, BlockPos.containing(bottomCenter).below(), true); + return Optional.of(new SpongePortal(at, (PortalLogic) this)); + } + return Optional.empty(); + } + + @Override + public boolean bridge$teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + final var toLevel = (ServerLevel) destination.world(); + if (toLevel.dimension() == Level.END) { + if (generateDestinationPortal) { + this.bridge$generatePortal(destination, Axis.X); + } + } - @Redirect(method = "entityInside", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;changeDimension(Lnet/minecraft/server/level/ServerLevel;)Lnet/minecraft/world/entity/Entity;")) - private Entity impl$useEndPortalTeleporterWhenTeleporting(final Entity entity, final ServerLevel p_241206_1_) { - return ((EntityBridge) entity).bridge$changeDimension(p_241206_1_, VanillaPortalLogic.getEndInstance()); + var exit = EndPortalBlockMixin.impl$calculateVanillaPortalExit(entity, toLevel); + return entity.setLocation(exit); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java new file mode 100644 index 00000000000..8a39171148b --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java @@ -0,0 +1,135 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.level.block; + +import net.minecraft.BlockUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.ai.village.poi.PoiManager; +import net.minecraft.world.entity.ai.village.poi.PoiRecord; +import net.minecraft.world.entity.ai.village.poi.PoiTypes; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.NetherPortalBlock; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.dimension.DimensionType; +import org.spongepowered.api.util.AABB; +import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.bridge.world.level.block.PortalBlockBridge; +import org.spongepowered.common.util.AxisUtil; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.common.world.portal.SpongePortal; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Comparator; +import java.util.Optional; + +@Mixin(NetherPortalBlock.class) +public abstract class NetherPortalBlockMixin implements PortalBlockBridge { + + @Override + public Optional bridge$calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final org.spongepowered.api.entity.Entity entity) { + final var fromLevel = (ServerLevel) from.world(); + final var toLevelKey = fromLevel.dimension() == Level.NETHER ? Level.OVERWORLD : Level.NETHER; + final var toLevel = fromLevel.getServer().getLevel(toLevelKey); + if (toLevel == null) { + return Optional.empty(); + } + final var scale = DimensionType.getTeleportationScale(fromLevel.dimensionType(), toLevel.dimensionType()); + final var exitPosition = toLevel.getWorldBorder().clampToBounds(fromPos.x() * scale, fromPos.y(), fromPos.z() * scale); + return Optional.of(ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3i(exitPosition))); + } + + @Override + public Optional bridge$findPortal(final ServerLocation at, final int searchRange) { + final var level = ((ServerLevel) at.world()); + final var worldBorder = level.getWorldBorder(); + final var blockPos = VecHelper.toBlockPos(at.position()); + final var poiManager = level.getPoiManager(); + final int range = Math.clamp(searchRange, 1, 128); + + poiManager.ensureLoadedAndValid(level, blockPos, range); + final var foundPortalPos = poiManager.getInSquare(poi -> poi.is(PoiTypes.NETHER_PORTAL), blockPos, range, PoiManager.Occupancy.ANY) + .map(PoiRecord::getPos) + .filter(worldBorder::isWithinBounds) + .filter(pos -> level.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) + .min(Comparator.comparingDouble($$1x -> $$1x.distSqr(blockPos)).thenComparingInt(Vec3i::getY)); + return foundPortalPos.map(pos -> { + final var portalBlockState = level.getBlockState(pos); + final var axis = portalBlockState.getValue(BlockStateProperties.HORIZONTAL_AXIS); + final var foundRectangle = BlockUtil.getLargestRectangleAround(pos, axis, 21, Direction.Axis.Y, 21, pos2 -> level.getBlockState(pos2) == portalBlockState); + return new SpongePortal(at.world().location(VecHelper.toVector3i(pos)), (PortalLogic) this, NetherPortalBlockMixin.impl$portalAABB(foundRectangle, axis)); + }); + } + + private static AABB impl$portalAABB(final BlockUtil.FoundRectangle portal, final Direction.Axis axis) { + final var minCorner = VecHelper.toVector3i(portal.minCorner); + if (axis == Direction.Axis.X) { + return AABB.of(minCorner, minCorner.add(portal.axis1Size, portal.axis2Size, 1)); + } + // it's z + return AABB.of(minCorner, minCorner.add(1, portal.axis2Size, portal.axis1Size)); + } + + @Override + public Optional bridge$generatePortal(final ServerLocation at, final Axis axis) { + final var level = ((ServerLevel) at.world()); + final var blockPos = VecHelper.toBlockPos(at.position()); + + final var portal = level.getPortalForcer().createPortal(blockPos, AxisUtil.getFor(axis)); + return portal.map(p -> new SpongePortal(at, (PortalLogic) this, NetherPortalBlockMixin.impl$portalAABB(p, AxisUtil.getFor(axis)))); + } + + @Override + public boolean bridge$teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + final var toLevel = (ServerLevel) destination.world(); + boolean toSmallerScaleLevel = toLevel.dimension() == Level.NETHER; + var found = this.bridge$findPortal(destination, toSmallerScaleLevel ? 16 : 128); + var portalDestination = found.map(Portal::position); + if (portalDestination.isPresent()) { + entity.setLocation(portalDestination.get()); + return true; + } + if (!generateDestinationPortal) { + return false; + } + final Axis axis = AxisUtil.getFor(Direction.Axis.X); + var generated = this.bridge$generatePortal(destination, axis); + portalDestination = generated.map(Portal::position); + if (portalDestination.isPresent()) { + entity.setLocation(portalDestination.get()); + return true; + } + return false; + } + + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/TheEndGatewayBlockEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/TheEndGatewayBlockEntityMixin.java deleted file mode 100644 index 674e0f1ce8a..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/TheEndGatewayBlockEntityMixin.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.mixin.core.world.level.block.entity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.common.event.tracking.PhaseTracker; - -@Mixin(TheEndGatewayBlockEntity.class) -public abstract class TheEndGatewayBlockEntityMixin extends TheEndPortalBlockEntity { - - protected TheEndGatewayBlockEntityMixin( - BlockEntityType var1, BlockPos var2, - BlockState var3 - ) { - super(var1, var2, var3); - } - - @Redirect(method = "teleportEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;teleportToWithTicket(DDD)V")) - private static void impl$createCauseFrameForTeleport( - final Entity entity, final double x, final double y, final double z, Level var0, BlockPos var1, BlockState var2, Entity var3, TheEndGatewayBlockEntity var4 - ) { - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - // We'll already have the entity in the cause if they are a player and threw their pearl into it. We do not - // want to re-arrange the cause - if (!frame.currentCause().containsType(entity.getClass())) { - frame.pushCause(entity); - } - frame.pushCause(var4); - frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.END_GATEWAY.get()); - - entity.teleportToWithTicket(x, y, z); - } - } -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/LivingEntityMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/LivingEntityMixin_Tracker.java index 3c09df3be46..6f7e33dd68a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/LivingEntityMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/LivingEntityMixin_Tracker.java @@ -24,14 +24,12 @@ */ package org.spongepowered.common.mixin.tracker.world.entity; -import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatEntry; import net.minecraft.world.damagesource.CombatTracker; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; import org.spongepowered.asm.mixin.Mixin; @@ -52,23 +50,16 @@ public abstract class LivingEntityMixin_Tracker extends EntityMixin_Tracker { // @formatter:off - @Shadow protected boolean dead; - @Shadow protected int deathScore; - @Shadow protected int lastHurtByPlayerTime; @Shadow protected abstract void shadow$tickDeath(); - @Shadow protected abstract boolean shadow$shouldDropExperience(); - @Shadow protected abstract void shadow$dropFromLootTable(DamageSource damageSourceIn, boolean p_213354_2_); - @Shadow protected abstract void shadow$dropEquipment(); @Shadow public abstract CombatTracker shadow$getCombatTracker(); - @Shadow @Nullable public abstract LivingEntity shadow$getKillCredit(); @Shadow public void shadow$die(final DamageSource cause) {} - @Shadow protected abstract void shadow$dropAllDeathLoot(DamageSource damageSourceIn); - @Shadow protected abstract void shadow$createWitherRose(@Nullable LivingEntity p_226298_1_); - @Shadow public abstract void shadow$swing(InteractionHand p_184609_1_); @Shadow protected abstract void shadow$pushEntities(); @Shadow public abstract float shadow$getHealth(); + @Shadow public int deathTime; + @Shadow protected boolean dead; + // @formatter:on @Override diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index e52564e867a..c8cdb9fe8b6 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -1,501 +1,503 @@ { - "required": true, - "parent": "mixins.sponge.parent.json", - "package": "org.spongepowered.common.mixin.api", - "mixinPriority": 1100, - "mixins": [ - "common.entity.living.HumanEntityMixin_API", - "data.DataHolderMixin_API", - "data.persistence.DataContainerMixin_API", - "entity.ai.goal.AbstractGoalMixin_API", - "item.merchant.MerchantMixin_API", - "minecraft.advancements.AdvancementMixin_API", - "minecraft.advancements.AdvancementNodeMixin_API", - "minecraft.advancements.AdvancementProgressMixin_API", - "minecraft.advancements.AdvancementTypeMixin_API", - "minecraft.advancements.CriterionMixin_API", - "minecraft.advancements.CriterionProgressMixin_API", - "minecraft.advancements.CriterionTriggerInstanceMixin_API", - "minecraft.advancements.CriterionTriggerMixin_API", - "minecraft.advancements.DisplayInfoMixin_API", - "minecraft.block.AbstractBlockMixin_API", - "minecraft.block.BlockMixin_API", - "minecraft.block.BlockSoundGroupMixin_API", - "minecraft.commands.CommandSourceStackMixin_API", - "minecraft.commands.arguments.selector.EntitySelectorMixin_API", - "minecraft.commands.arguments.selector.EntitySelectorParserMixin_API", - "minecraft.commands.synchronization.SuggestionProviders_WrapperMixin_API", - "minecraft.core.MappedRegistryMixin_API", - "minecraft.core.particles.ParticleTypeMixin_API", - "minecraft.entity.boss.WitherEntityMixin_API", - "minecraft.item.BlockItemMixin_API", - "minecraft.map.MapDecorationMixin_API", - "minecraft.map.MapDecorationTypeMixin_API", - "minecraft.map.MapInfoMixin_API", - "minecraft.network.FriendlyByteBufMixin_API", - "minecraft.network.chat.ChatTypeMixin_API", - "minecraft.network.chat.ChatTypeMixin_API$BoundMixin_API", - "minecraft.network.chat.MessageSignatureMixin_API", - "minecraft.network.chat.NumberFormatMixin_API", - "minecraft.network.protocol.status.ServerStatus_FaviconMixin_API", - "minecraft.network.protocol.status.ServerStatus_PlayersMixin_API", - "minecraft.network.protocol.status.ServerStatus_VersionMixin_API", - "minecraft.network.protocol.status.ServerStatusMixin_API", - "minecraft.resources.ResourceLocationMixin_API", - "minecraft.server.MinecraftServerMixin_API", - "minecraft.server.ServerScoreboardMixin_API", - "minecraft.server.level.ChunkMapMixin_API", - "minecraft.server.level.ServerLevelMixin_API", - "minecraft.server.level.ServerPlayerMixin_API", - "minecraft.server.level.TicketMixin_API", - "minecraft.server.level.TicketTypeMixin_API", - "minecraft.server.level.WorldGenRegionMixin_API", - "minecraft.server.network.MemoryServerHandshakePacketListenerImplMixin_API", - "minecraft.server.network.ServerCommonPacketListenerImplMixin_API", - "minecraft.server.network.ServerConfigurationPacketListenerImplMixin_API", - "minecraft.server.network.ServerGamePacketListenerImplMixin_API", - "minecraft.server.network.ServerHandshakePacketListenerImplMixin_API", - "minecraft.server.network.ServerLoginPacketListenerImplMixin_API", - "minecraft.server.packs.PackResourcesMixin_API", - "minecraft.server.packs.PackTypeMixin_API", - "minecraft.server.packs.repository.PackCompatibilityMixin_API", - "minecraft.server.packs.repository.PackMixin_API", - "minecraft.server.packs.repository.PackRepositoryMixin_API", - "minecraft.server.packs.resources.ResourceManagerMixin_API", - "minecraft.server.players.BanListEntryMixin_API", - "minecraft.server.players.GameProfileCacheMixin_API", - "minecraft.server.players.IpBanListEntryMixin_API", - "minecraft.server.players.StoredUserEntryMixin_API", - "minecraft.server.players.UserBanListEntryMixin_API", - "minecraft.server.rcon.RconConsoleSourceMixin_API", - "minecraft.server.rcon.thread.RconClientMixin_API", - "minecraft.sounds.MusicMixin_API", - "minecraft.sounds.SoundEventMixin_API", - "minecraft.state.BooleanPropertyMixin_API", - "minecraft.state.EnumPropertyMixin_API", - "minecraft.state.IntegerPropertyMixin_API", - "minecraft.state.PropertyMixin_API", - "minecraft.stats.StatMixin_API", - "minecraft.stats.StatTypeMixin_API", - "minecraft.tags.TagKeyMixin_API", - "minecraft.util.RandomSourceMixin_API", - "minecraft.util.StringRepresentableMixin_API", - "minecraft.world.DifficultyMixin_API", - "minecraft.world.InteractionHandMixin_API", - "minecraft.world.IWorldGenerationBaseReaderMixin_API", - "minecraft.world.IWorldGenerationReaderMixin_API", - "minecraft.world.damagesource.DamageScalingMixin_API", - "minecraft.world.damagesource.DamageSourceMixin_API", - "minecraft.world.damagesource.DamageTypeMixin_API", - "minecraft.world.effect.MobEffectInstanceMixin_API", - "minecraft.world.effect.MobEffectMixin_API", - "minecraft.world.entity.AgeableMobMixin_API", - "minecraft.world.entity.AreaEffectCloudMixin_API", - "minecraft.world.entity.Display_BillboardConstraintsMixin_API", - "minecraft.world.entity.Display_BlockDisplayMixin_API", - "minecraft.world.entity.Display_ItemDisplayMixin_API", - "minecraft.world.entity.Display_TextDisplay_AlignMixin_API", - "minecraft.world.entity.Display_TextDisplayMixin_API", - "minecraft.world.entity.DisplayMixin_API", - "minecraft.world.entity.EntityMixin_API", - "minecraft.world.entity.EntityTypeMixin_API", - "minecraft.world.entity.ExperienceOrbMixin_API", - "minecraft.world.entity.FlyingMobMixin_API", - "minecraft.world.entity.HumanoidArmMixin_API", - "minecraft.world.entity.InteractionMixin_API", - "minecraft.world.entity.LightningBoltMixin_API", - "minecraft.world.entity.LivingEntityMixin_API", - "minecraft.world.entity.MarkerMixin_API", - "minecraft.world.entity.MobCategoryMixin_API", - "minecraft.world.entity.MobMixin_API", + "required": true, + "parent": "mixins.sponge.parent.json", + "package": "org.spongepowered.common.mixin.api", + "mixinPriority": 1100, + "mixins": [ + "common.entity.living.HumanEntityMixin_API", + "data.DataHolderMixin_API", + "data.persistence.DataContainerMixin_API", + "entity.ai.goal.AbstractGoalMixin_API", + "item.merchant.MerchantMixin_API", + "minecraft.advancements.AdvancementMixin_API", + "minecraft.advancements.AdvancementNodeMixin_API", + "minecraft.advancements.AdvancementProgressMixin_API", + "minecraft.advancements.AdvancementTypeMixin_API", + "minecraft.advancements.CriterionMixin_API", + "minecraft.advancements.CriterionProgressMixin_API", + "minecraft.advancements.CriterionTriggerInstanceMixin_API", + "minecraft.advancements.CriterionTriggerMixin_API", + "minecraft.advancements.DisplayInfoMixin_API", + "minecraft.block.AbstractBlockMixin_API", + "minecraft.block.BlockMixin_API", + "minecraft.block.BlockSoundGroupMixin_API", + "minecraft.commands.CommandSourceStackMixin_API", + "minecraft.commands.arguments.selector.EntitySelectorMixin_API", + "minecraft.commands.arguments.selector.EntitySelectorParserMixin_API", + "minecraft.commands.synchronization.SuggestionProviders_WrapperMixin_API", + "minecraft.core.MappedRegistryMixin_API", + "minecraft.core.particles.ParticleTypeMixin_API", + "minecraft.entity.boss.WitherEntityMixin_API", + "minecraft.item.BlockItemMixin_API", + "minecraft.map.MapDecorationMixin_API", + "minecraft.map.MapDecorationTypeMixin_API", + "minecraft.map.MapInfoMixin_API", + "minecraft.network.FriendlyByteBufMixin_API", + "minecraft.network.chat.ChatTypeMixin_API", + "minecraft.network.chat.ChatTypeMixin_API$BoundMixin_API", + "minecraft.network.chat.MessageSignatureMixin_API", + "minecraft.network.chat.NumberFormatMixin_API", + "minecraft.network.protocol.status.ServerStatus_FaviconMixin_API", + "minecraft.network.protocol.status.ServerStatus_PlayersMixin_API", + "minecraft.network.protocol.status.ServerStatus_VersionMixin_API", + "minecraft.network.protocol.status.ServerStatusMixin_API", + "minecraft.resources.ResourceLocationMixin_API", + "minecraft.server.MinecraftServerMixin_API", + "minecraft.server.ServerScoreboardMixin_API", + "minecraft.server.level.ChunkMapMixin_API", + "minecraft.server.level.ServerLevelMixin_API", + "minecraft.server.level.ServerPlayerMixin_API", + "minecraft.server.level.TicketMixin_API", + "minecraft.server.level.TicketTypeMixin_API", + "minecraft.server.level.WorldGenRegionMixin_API", + "minecraft.server.network.MemoryServerHandshakePacketListenerImplMixin_API", + "minecraft.server.network.ServerCommonPacketListenerImplMixin_API", + "minecraft.server.network.ServerConfigurationPacketListenerImplMixin_API", + "minecraft.server.network.ServerGamePacketListenerImplMixin_API", + "minecraft.server.network.ServerHandshakePacketListenerImplMixin_API", + "minecraft.server.network.ServerLoginPacketListenerImplMixin_API", + "minecraft.server.packs.PackResourcesMixin_API", + "minecraft.server.packs.PackTypeMixin_API", + "minecraft.server.packs.repository.PackCompatibilityMixin_API", + "minecraft.server.packs.repository.PackMixin_API", + "minecraft.server.packs.repository.PackRepositoryMixin_API", + "minecraft.server.packs.resources.ResourceManagerMixin_API", + "minecraft.server.players.BanListEntryMixin_API", + "minecraft.server.players.GameProfileCacheMixin_API", + "minecraft.server.players.IpBanListEntryMixin_API", + "minecraft.server.players.StoredUserEntryMixin_API", + "minecraft.server.players.UserBanListEntryMixin_API", + "minecraft.server.rcon.RconConsoleSourceMixin_API", + "minecraft.server.rcon.thread.RconClientMixin_API", + "minecraft.sounds.MusicMixin_API", + "minecraft.sounds.SoundEventMixin_API", + "minecraft.state.BooleanPropertyMixin_API", + "minecraft.state.EnumPropertyMixin_API", + "minecraft.state.IntegerPropertyMixin_API", + "minecraft.state.PropertyMixin_API", + "minecraft.stats.StatMixin_API", + "minecraft.stats.StatTypeMixin_API", + "minecraft.tags.TagKeyMixin_API", + "minecraft.util.RandomSourceMixin_API", + "minecraft.util.StringRepresentableMixin_API", + "minecraft.world.DifficultyMixin_API", + "minecraft.world.InteractionHandMixin_API", + "minecraft.world.IWorldGenerationBaseReaderMixin_API", + "minecraft.world.IWorldGenerationReaderMixin_API", + "minecraft.world.damagesource.DamageScalingMixin_API", + "minecraft.world.damagesource.DamageSourceMixin_API", + "minecraft.world.damagesource.DamageTypeMixin_API", + "minecraft.world.effect.MobEffectInstanceMixin_API", + "minecraft.world.effect.MobEffectMixin_API", + "minecraft.world.entity.AgeableMobMixin_API", + "minecraft.world.entity.AreaEffectCloudMixin_API", + "minecraft.world.entity.Display_BillboardConstraintsMixin_API", + "minecraft.world.entity.Display_BlockDisplayMixin_API", + "minecraft.world.entity.Display_ItemDisplayMixin_API", + "minecraft.world.entity.Display_TextDisplay_AlignMixin_API", + "minecraft.world.entity.Display_TextDisplayMixin_API", + "minecraft.world.entity.DisplayMixin_API", + "minecraft.world.entity.EntityMixin_API", + "minecraft.world.entity.EntityTypeMixin_API", + "minecraft.world.entity.ExperienceOrbMixin_API", + "minecraft.world.entity.FlyingMobMixin_API", + "minecraft.world.entity.HumanoidArmMixin_API", + "minecraft.world.entity.InteractionMixin_API", + "minecraft.world.entity.LightningBoltMixin_API", + "minecraft.world.entity.LivingEntityMixin_API", + "minecraft.world.entity.MarkerMixin_API", + "minecraft.world.entity.MobCategoryMixin_API", + "minecraft.world.entity.MobMixin_API", "minecraft.world.entity.OminousItemSpawnerMixin_API", - "minecraft.world.entity.PathfinderMobMixin_API", - "minecraft.world.entity.TamableAnimalMixin_API", - "minecraft.world.entity.ai.attributes.AttributeInstanceMixin_API", - "minecraft.world.entity.ai.attributes.AttributeMixin_API", - "minecraft.world.entity.ai.attributes.AttributeModifier_OperationMixin_API", - "minecraft.world.entity.ai.attributes.AttributeModifierMixin_API", - "minecraft.world.entity.ai.attributes.RangedAttributeMixin_API", - "minecraft.world.entity.ai.goal.AvoidEntityGoalMixin_API", - "minecraft.world.entity.ai.goal.FloatGoalMixin_API", - "minecraft.world.entity.ai.goal.GoalMixin_API", - "minecraft.world.entity.ai.goal.GoalSelectorMixin_API", - "minecraft.world.entity.ai.goal.LookAtPlayerGoalMixin_API", - "minecraft.world.entity.ai.goal.MeleeAttackGoalMixin_API", - "minecraft.world.entity.ai.goal.RandomLookAroundGoalMixin_API", - "minecraft.world.entity.ai.goal.RandomStrollGoalMixin_API", - "minecraft.world.entity.ai.goal.RangedAttackGoalMixin_API", - "minecraft.world.entity.ai.goal.RunAroundLikeCrazyGoalMixin_API", - "minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoalMixin_API", - "minecraft.world.entity.ai.goal.target.TargetGoalMixin_API", - "minecraft.world.entity.ambient.AmbientCreatureMixin_API", - "minecraft.world.entity.ambient.BatMixin_API", - "minecraft.world.entity.animal.AbstractFishMixin_API", - "minecraft.world.entity.animal.AbstractGolemMixin_API", - "minecraft.world.entity.animal.AbstractSchoolingFishMixin_API", - "minecraft.world.entity.animal.AnimalMixin_API", + "minecraft.world.entity.PathfinderMobMixin_API", + "minecraft.world.entity.PortalProcessorMixin_API", + "minecraft.world.entity.TamableAnimalMixin_API", + "minecraft.world.entity.ai.attributes.AttributeInstanceMixin_API", + "minecraft.world.entity.ai.attributes.AttributeMixin_API", + "minecraft.world.entity.ai.attributes.AttributeModifier_OperationMixin_API", + "minecraft.world.entity.ai.attributes.AttributeModifierMixin_API", + "minecraft.world.entity.ai.attributes.RangedAttributeMixin_API", + "minecraft.world.entity.ai.goal.AvoidEntityGoalMixin_API", + "minecraft.world.entity.ai.goal.FloatGoalMixin_API", + "minecraft.world.entity.ai.goal.GoalMixin_API", + "minecraft.world.entity.ai.goal.GoalSelectorMixin_API", + "minecraft.world.entity.ai.goal.LookAtPlayerGoalMixin_API", + "minecraft.world.entity.ai.goal.MeleeAttackGoalMixin_API", + "minecraft.world.entity.ai.goal.RandomLookAroundGoalMixin_API", + "minecraft.world.entity.ai.goal.RandomStrollGoalMixin_API", + "minecraft.world.entity.ai.goal.RangedAttackGoalMixin_API", + "minecraft.world.entity.ai.goal.RunAroundLikeCrazyGoalMixin_API", + "minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoalMixin_API", + "minecraft.world.entity.ai.goal.target.TargetGoalMixin_API", + "minecraft.world.entity.ambient.AmbientCreatureMixin_API", + "minecraft.world.entity.ambient.BatMixin_API", + "minecraft.world.entity.animal.AbstractFishMixin_API", + "minecraft.world.entity.animal.AbstractGolemMixin_API", + "minecraft.world.entity.animal.AbstractSchoolingFishMixin_API", + "minecraft.world.entity.animal.AnimalMixin_API", "minecraft.world.entity.animal.ArmadilloMixin_API", - "minecraft.world.entity.animal.BeeMixin_API", - "minecraft.world.entity.animal.CatMixin_API", - "minecraft.world.entity.animal.CatVariantMixin_API", - "minecraft.world.entity.animal.ChickenMixin_API", - "minecraft.world.entity.animal.CodMixin_API", - "minecraft.world.entity.animal.CowMixin_API", - "minecraft.world.entity.animal.DolphinMixin_API", - "minecraft.world.entity.animal.Fox_TypeMixin_API", - "minecraft.world.entity.animal.FoxMixin_API", - "minecraft.world.entity.animal.IronGolemMixin_API", - "minecraft.world.entity.animal.MushroomCow_MushroomTypeMixin_API", - "minecraft.world.entity.animal.MushroomCowMixin_API", - "minecraft.world.entity.animal.OcelotMixin_API", - "minecraft.world.entity.animal.Panda_GeneMixin_API", - "minecraft.world.entity.animal.PandaMixin_API", - "minecraft.world.entity.animal.Parrot_VariantMixin_API", - "minecraft.world.entity.animal.ParrotMixin_API", - "minecraft.world.entity.animal.PigMixin_API", - "minecraft.world.entity.animal.PolarBearMixin_API", - "minecraft.world.entity.animal.PufferfishMixin_API", - "minecraft.world.entity.animal.Rabbit_VariantMixin_API", - "minecraft.world.entity.animal.RabbitMixin_API", - "minecraft.world.entity.animal.SalmonMixin_API", - "minecraft.world.entity.animal.SheepMixin_API", - "minecraft.world.entity.animal.ShoulderRidingEntityMixin_API", - "minecraft.world.entity.animal.SnowGolemMixin_API", - "minecraft.world.entity.animal.SquidMixin_API", - "minecraft.world.entity.animal.TropicalFish_PatternMixin_API", - "minecraft.world.entity.animal.TropicalFishMixin_API", - "minecraft.world.entity.animal.TurtleMixin_API", - "minecraft.world.entity.animal.WaterAnimalMixin_API", - "minecraft.world.entity.animal.WolfMixin_API", - "minecraft.world.entity.animal.allay.AllayMixin_API", - "minecraft.world.entity.animal.camel.CamelMixin_API", - "minecraft.world.entity.animal.frog.FrogMixin_API", - "minecraft.world.entity.animal.frog.TadpoleMixin_API", - "minecraft.world.entity.animal.horse.AbstractChestedHorseMixin_API", - "minecraft.world.entity.animal.horse.AbstractHorseMixin_API", - "minecraft.world.entity.animal.horse.DonkeyMixin_API", - "minecraft.world.entity.animal.horse.HorseMixin_API", - "minecraft.world.entity.animal.horse.LLama_VariantMixin_API", - "minecraft.world.entity.animal.horse.LlamaMixin_API", - "minecraft.world.entity.animal.horse.MarkingsMixin_API", - "minecraft.world.entity.animal.horse.MuleMixin_API", - "minecraft.world.entity.animal.horse.SkeletonHorseMixin_API", - "minecraft.world.entity.animal.horse.TraderLlamaMixin_API", - "minecraft.world.entity.animal.horse.VariantMixin_API", - "minecraft.world.entity.animal.horse.ZombieHorseMixin_API", - "minecraft.world.entity.animal.sniffer.SnifferMixin_API", - "minecraft.world.entity.boss.EnderDragonPartMixin_API", - "minecraft.world.entity.boss.enderdragon.EndCrystalMixin_API", - "minecraft.world.entity.boss.enderdragon.EnderDragonMixin_API", - "minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstanceMixin_API", - "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManagerMixin_API", - "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseMixin_API", - "minecraft.world.entity.decoration.ArmorStandMixin_API", + "minecraft.world.entity.animal.BeeMixin_API", + "minecraft.world.entity.animal.CatMixin_API", + "minecraft.world.entity.animal.CatVariantMixin_API", + "minecraft.world.entity.animal.ChickenMixin_API", + "minecraft.world.entity.animal.CodMixin_API", + "minecraft.world.entity.animal.CowMixin_API", + "minecraft.world.entity.animal.DolphinMixin_API", + "minecraft.world.entity.animal.Fox_TypeMixin_API", + "minecraft.world.entity.animal.FoxMixin_API", + "minecraft.world.entity.animal.IronGolemMixin_API", + "minecraft.world.entity.animal.MushroomCow_MushroomTypeMixin_API", + "minecraft.world.entity.animal.MushroomCowMixin_API", + "minecraft.world.entity.animal.OcelotMixin_API", + "minecraft.world.entity.animal.Panda_GeneMixin_API", + "minecraft.world.entity.animal.PandaMixin_API", + "minecraft.world.entity.animal.Parrot_VariantMixin_API", + "minecraft.world.entity.animal.ParrotMixin_API", + "minecraft.world.entity.animal.PigMixin_API", + "minecraft.world.entity.animal.PolarBearMixin_API", + "minecraft.world.entity.animal.PufferfishMixin_API", + "minecraft.world.entity.animal.Rabbit_VariantMixin_API", + "minecraft.world.entity.animal.RabbitMixin_API", + "minecraft.world.entity.animal.SalmonMixin_API", + "minecraft.world.entity.animal.SheepMixin_API", + "minecraft.world.entity.animal.ShoulderRidingEntityMixin_API", + "minecraft.world.entity.animal.SnowGolemMixin_API", + "minecraft.world.entity.animal.SquidMixin_API", + "minecraft.world.entity.animal.TropicalFish_PatternMixin_API", + "minecraft.world.entity.animal.TropicalFishMixin_API", + "minecraft.world.entity.animal.TurtleMixin_API", + "minecraft.world.entity.animal.WaterAnimalMixin_API", + "minecraft.world.entity.animal.WolfMixin_API", + "minecraft.world.entity.animal.allay.AllayMixin_API", + "minecraft.world.entity.animal.camel.CamelMixin_API", + "minecraft.world.entity.animal.frog.FrogMixin_API", + "minecraft.world.entity.animal.frog.TadpoleMixin_API", + "minecraft.world.entity.animal.horse.AbstractChestedHorseMixin_API", + "minecraft.world.entity.animal.horse.AbstractHorseMixin_API", + "minecraft.world.entity.animal.horse.DonkeyMixin_API", + "minecraft.world.entity.animal.horse.HorseMixin_API", + "minecraft.world.entity.animal.horse.LLama_VariantMixin_API", + "minecraft.world.entity.animal.horse.LlamaMixin_API", + "minecraft.world.entity.animal.horse.MarkingsMixin_API", + "minecraft.world.entity.animal.horse.MuleMixin_API", + "minecraft.world.entity.animal.horse.SkeletonHorseMixin_API", + "minecraft.world.entity.animal.horse.TraderLlamaMixin_API", + "minecraft.world.entity.animal.horse.VariantMixin_API", + "minecraft.world.entity.animal.horse.ZombieHorseMixin_API", + "minecraft.world.entity.animal.sniffer.SnifferMixin_API", + "minecraft.world.entity.boss.EnderDragonPartMixin_API", + "minecraft.world.entity.boss.enderdragon.EndCrystalMixin_API", + "minecraft.world.entity.boss.enderdragon.EnderDragonMixin_API", + "minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstanceMixin_API", + "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManagerMixin_API", + "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseMixin_API", + "minecraft.world.entity.decoration.ArmorStandMixin_API", "minecraft.world.entity.decoration.BlockAttachedEntityMixin_API", - "minecraft.world.entity.decoration.HangingEntityMixin_API", - "minecraft.world.entity.decoration.ItemFrameMixin_API", - "minecraft.world.entity.decoration.LeashFenceKnotEntityMixin_API", - "minecraft.world.entity.decoration.PaintingMixin_API", - "minecraft.world.entity.decoration.PaintingVariantMixin_API", - "minecraft.world.entity.item.FallingBlockEntityMixin_API", - "minecraft.world.entity.item.ItemEntityMixin_API", - "minecraft.world.entity.item.PrimedTntMixin_API", - "minecraft.world.entity.monster.AbstractIllagerMixin_API", - "minecraft.world.entity.monster.AbstractSkeletonMixin_API", - "minecraft.world.entity.monster.BlazeMixin_API", + "minecraft.world.entity.decoration.HangingEntityMixin_API", + "minecraft.world.entity.decoration.ItemFrameMixin_API", + "minecraft.world.entity.decoration.LeashFenceKnotEntityMixin_API", + "minecraft.world.entity.decoration.PaintingMixin_API", + "minecraft.world.entity.decoration.PaintingVariantMixin_API", + "minecraft.world.entity.item.FallingBlockEntityMixin_API", + "minecraft.world.entity.item.ItemEntityMixin_API", + "minecraft.world.entity.item.PrimedTntMixin_API", + "minecraft.world.entity.monster.AbstractIllagerMixin_API", + "minecraft.world.entity.monster.AbstractSkeletonMixin_API", + "minecraft.world.entity.monster.BlazeMixin_API", "minecraft.world.entity.monster.BoggedMixin_API", - "minecraft.world.entity.monster.BreezeMixin_API", - "minecraft.world.entity.monster.CaveSpiderMixin_API", - "minecraft.world.entity.monster.CreeperMixin_API", - "minecraft.world.entity.monster.DrownedMixin_API", - "minecraft.world.entity.monster.ElderGuardianMixin_API", - "minecraft.world.entity.monster.EnderManMixin_API", - "minecraft.world.entity.monster.EndermiteMixin_API", - "minecraft.world.entity.monster.EvokerMixin_API", - "minecraft.world.entity.monster.GhastMixin_API", - "minecraft.world.entity.monster.GiantMixin_API", - "minecraft.world.entity.monster.GuardianMixin_API", - "minecraft.world.entity.monster.HoglinMixin_API", - "minecraft.world.entity.monster.HuskMixin_API", - "minecraft.world.entity.monster.IllusionerMixin_API", - "minecraft.world.entity.monster.MagmaCubeMixin_API", - "minecraft.world.entity.monster.MonsterMixin_API", - "minecraft.world.entity.monster.PatrollingMonsterMixin_API", - "minecraft.world.entity.monster.Phantom_AttackPhaseMixin_API", - "minecraft.world.entity.monster.PhantomMixin_API", - "minecraft.world.entity.monster.PiglinBruteMixin_API", - "minecraft.world.entity.monster.PiglinMixin_API", - "minecraft.world.entity.monster.PillagerMixin_API", - "minecraft.world.entity.monster.RangedAttackMobMixin_API", - "minecraft.world.entity.monster.RavagerMixin_API", - "minecraft.world.entity.monster.ShulkerMixin_API", - "minecraft.world.entity.monster.SilverfishMixin_API", - "minecraft.world.entity.monster.SkeletonMixin_API", - "minecraft.world.entity.monster.SlimeMixin_API", - "minecraft.world.entity.monster.SpellcasterIllager_IllagerSpellMixin_API", - "minecraft.world.entity.monster.SpellcasterIllagerMixin_API", - "minecraft.world.entity.monster.SpiderMixin_API", - "minecraft.world.entity.monster.StrayMixin_API", - "minecraft.world.entity.monster.VexMixin_API", - "minecraft.world.entity.monster.VindicatorMixin_API", - "minecraft.world.entity.monster.WitchMixin_API", - "minecraft.world.entity.monster.WitherSkeletonMixin_API", - "minecraft.world.entity.monster.ZoglinMixin_API", - "minecraft.world.entity.monster.ZombieMixin_API", - "minecraft.world.entity.monster.ZombieVillagerMixin_API", - "minecraft.world.entity.monster.ZombifiedPiglinMixin_API", - "minecraft.world.entity.monster.warden.WardenMixin_API", - "minecraft.world.entity.npc.AbstractVillagerMixin_API", - "minecraft.world.entity.npc.VillagerMixin_API", - "minecraft.world.entity.npc.VillagerProfessionMixin_API", - "minecraft.world.entity.npc.VillagerTrades_ItemListingMixin_API", - "minecraft.world.entity.npc.VillagerTypeMixin_API", - "minecraft.world.entity.npc.WanderingTraderMixin_API", - "minecraft.world.entity.player.ChatVisiblityMixin_API", - "minecraft.world.entity.player.PlayerMixin_API", - "minecraft.world.entity.projectile.AbstractArrow_PickupMixin_API", - "minecraft.world.entity.projectile.AbstractArrowMixin_API", - "minecraft.world.entity.projectile.AbstractHurtingProjectileMixin_API", - "minecraft.world.entity.projectile.ArrowMixin_API", - "minecraft.world.entity.projectile.DragonFireballMixin_API", - "minecraft.world.entity.projectile.EvokerFangsMixin_API", - "minecraft.world.entity.projectile.EyeOfEnderMixin_API", - "minecraft.world.entity.projectile.FireballMixin_API", - "minecraft.world.entity.projectile.FireworkRocketEntityMixin_API", - "minecraft.world.entity.projectile.FishingHookMixin_API", - "minecraft.world.entity.projectile.LargeFireballMixin_API", - "minecraft.world.entity.projectile.LlamaSpitMixin_API", - "minecraft.world.entity.projectile.ProjectileMixin_API", - "minecraft.world.entity.projectile.ShulkerBulletMixin_API", - "minecraft.world.entity.projectile.SmallFireballMixin_API", - "minecraft.world.entity.projectile.SnowballMixin_API", - "minecraft.world.entity.projectile.SpectralArrowMixin_API", - "minecraft.world.entity.projectile.ThrowableItemProjectileMixin_API", - "minecraft.world.entity.projectile.ThrowableProjectileMixin_API", - "minecraft.world.entity.projectile.ThrownEggMixin_API", - "minecraft.world.entity.projectile.ThrownEnderpearlMixin_API", - "minecraft.world.entity.projectile.ThrownExperienceBottleMixin_API", - "minecraft.world.entity.projectile.ThrownPotionMixin_API", - "minecraft.world.entity.projectile.ThrownTridentMixin_API", - "minecraft.world.entity.projectile.WitherSkullMixin_API", + "minecraft.world.entity.monster.BreezeMixin_API", + "minecraft.world.entity.monster.CaveSpiderMixin_API", + "minecraft.world.entity.monster.CreeperMixin_API", + "minecraft.world.entity.monster.DrownedMixin_API", + "minecraft.world.entity.monster.ElderGuardianMixin_API", + "minecraft.world.entity.monster.EnderManMixin_API", + "minecraft.world.entity.monster.EndermiteMixin_API", + "minecraft.world.entity.monster.EvokerMixin_API", + "minecraft.world.entity.monster.GhastMixin_API", + "minecraft.world.entity.monster.GiantMixin_API", + "minecraft.world.entity.monster.GuardianMixin_API", + "minecraft.world.entity.monster.HoglinMixin_API", + "minecraft.world.entity.monster.HuskMixin_API", + "minecraft.world.entity.monster.IllusionerMixin_API", + "minecraft.world.entity.monster.MagmaCubeMixin_API", + "minecraft.world.entity.monster.MonsterMixin_API", + "minecraft.world.entity.monster.PatrollingMonsterMixin_API", + "minecraft.world.entity.monster.Phantom_AttackPhaseMixin_API", + "minecraft.world.entity.monster.PhantomMixin_API", + "minecraft.world.entity.monster.PiglinBruteMixin_API", + "minecraft.world.entity.monster.PiglinMixin_API", + "minecraft.world.entity.monster.PillagerMixin_API", + "minecraft.world.entity.monster.RangedAttackMobMixin_API", + "minecraft.world.entity.monster.RavagerMixin_API", + "minecraft.world.entity.monster.ShulkerMixin_API", + "minecraft.world.entity.monster.SilverfishMixin_API", + "minecraft.world.entity.monster.SkeletonMixin_API", + "minecraft.world.entity.monster.SlimeMixin_API", + "minecraft.world.entity.monster.SpellcasterIllager_IllagerSpellMixin_API", + "minecraft.world.entity.monster.SpellcasterIllagerMixin_API", + "minecraft.world.entity.monster.SpiderMixin_API", + "minecraft.world.entity.monster.StrayMixin_API", + "minecraft.world.entity.monster.VexMixin_API", + "minecraft.world.entity.monster.VindicatorMixin_API", + "minecraft.world.entity.monster.WitchMixin_API", + "minecraft.world.entity.monster.WitherSkeletonMixin_API", + "minecraft.world.entity.monster.ZoglinMixin_API", + "minecraft.world.entity.monster.ZombieMixin_API", + "minecraft.world.entity.monster.ZombieVillagerMixin_API", + "minecraft.world.entity.monster.ZombifiedPiglinMixin_API", + "minecraft.world.entity.monster.warden.WardenMixin_API", + "minecraft.world.entity.npc.AbstractVillagerMixin_API", + "minecraft.world.entity.npc.VillagerMixin_API", + "minecraft.world.entity.npc.VillagerProfessionMixin_API", + "minecraft.world.entity.npc.VillagerTrades_ItemListingMixin_API", + "minecraft.world.entity.npc.VillagerTypeMixin_API", + "minecraft.world.entity.npc.WanderingTraderMixin_API", + "minecraft.world.entity.player.ChatVisiblityMixin_API", + "minecraft.world.entity.player.PlayerMixin_API", + "minecraft.world.entity.projectile.AbstractArrow_PickupMixin_API", + "minecraft.world.entity.projectile.AbstractArrowMixin_API", + "minecraft.world.entity.projectile.AbstractHurtingProjectileMixin_API", + "minecraft.world.entity.projectile.ArrowMixin_API", + "minecraft.world.entity.projectile.DragonFireballMixin_API", + "minecraft.world.entity.projectile.EvokerFangsMixin_API", + "minecraft.world.entity.projectile.EyeOfEnderMixin_API", + "minecraft.world.entity.projectile.FireballMixin_API", + "minecraft.world.entity.projectile.FireworkRocketEntityMixin_API", + "minecraft.world.entity.projectile.FishingHookMixin_API", + "minecraft.world.entity.projectile.LargeFireballMixin_API", + "minecraft.world.entity.projectile.LlamaSpitMixin_API", + "minecraft.world.entity.projectile.ProjectileMixin_API", + "minecraft.world.entity.projectile.ShulkerBulletMixin_API", + "minecraft.world.entity.projectile.SmallFireballMixin_API", + "minecraft.world.entity.projectile.SnowballMixin_API", + "minecraft.world.entity.projectile.SpectralArrowMixin_API", + "minecraft.world.entity.projectile.ThrowableItemProjectileMixin_API", + "minecraft.world.entity.projectile.ThrowableProjectileMixin_API", + "minecraft.world.entity.projectile.ThrownEggMixin_API", + "minecraft.world.entity.projectile.ThrownEnderpearlMixin_API", + "minecraft.world.entity.projectile.ThrownExperienceBottleMixin_API", + "minecraft.world.entity.projectile.ThrownPotionMixin_API", + "minecraft.world.entity.projectile.ThrownTridentMixin_API", + "minecraft.world.entity.projectile.WitherSkullMixin_API", "minecraft.world.entity.projectile.windcharge.BreezeWindChargeMixin_API", "minecraft.world.entity.projectile.windcharge.WindChargeMixin_API", - "minecraft.world.entity.raid.Raid_RaidStatusMixin_API", - "minecraft.world.entity.raid.RaiderMixin_API", - "minecraft.world.entity.raid.RaidMixin_API", - "minecraft.world.entity.vehicle.AbstractMinecartContainerMixin_API", - "minecraft.world.entity.vehicle.AbstractMinecartMixin_API", - "minecraft.world.entity.vehicle.Boat_TypeMixin_API", - "minecraft.world.entity.vehicle.BoatMixin_API", - "minecraft.world.entity.vehicle.ChestBoatMixin_API", - "minecraft.world.entity.vehicle.MinecartChestMixin_API", - "minecraft.world.entity.vehicle.MinecartCommandBlockMixin_API", - "minecraft.world.entity.vehicle.MinecartFurnaceMixin_API", - "minecraft.world.entity.vehicle.MinecartHopperMixin_API", - "minecraft.world.entity.vehicle.MinecartMixin_API", - "minecraft.world.entity.vehicle.MinecartSpawnerMixin_API", - "minecraft.world.entity.vehicle.MinecartTNTMixin_API", - "minecraft.world.item.ArmorMaterialMixin_API", - "minecraft.world.item.DyeColorMixin_API", - "minecraft.world.item.FireworkExplosion_ShapeMixin_API", - "minecraft.world.item.ItemCooldownsMixin_API", - "minecraft.world.item.ItemDisplayContextMixin_API", - "minecraft.world.item.ItemMixin_API", - "minecraft.world.item.ItemStackMixin_API", + "minecraft.world.entity.raid.Raid_RaidStatusMixin_API", + "minecraft.world.entity.raid.RaiderMixin_API", + "minecraft.world.entity.raid.RaidMixin_API", + "minecraft.world.entity.vehicle.AbstractMinecartContainerMixin_API", + "minecraft.world.entity.vehicle.AbstractMinecartMixin_API", + "minecraft.world.entity.vehicle.Boat_TypeMixin_API", + "minecraft.world.entity.vehicle.BoatMixin_API", + "minecraft.world.entity.vehicle.ChestBoatMixin_API", + "minecraft.world.entity.vehicle.MinecartChestMixin_API", + "minecraft.world.entity.vehicle.MinecartCommandBlockMixin_API", + "minecraft.world.entity.vehicle.MinecartFurnaceMixin_API", + "minecraft.world.entity.vehicle.MinecartHopperMixin_API", + "minecraft.world.entity.vehicle.MinecartMixin_API", + "minecraft.world.entity.vehicle.MinecartSpawnerMixin_API", + "minecraft.world.entity.vehicle.MinecartTNTMixin_API", + "minecraft.world.item.ArmorMaterialMixin_API", + "minecraft.world.item.DyeColorMixin_API", + "minecraft.world.item.FireworkExplosion_ShapeMixin_API", + "minecraft.world.item.ItemCooldownsMixin_API", + "minecraft.world.item.ItemDisplayContextMixin_API", + "minecraft.world.item.ItemMixin_API", + "minecraft.world.item.ItemStackMixin_API", "minecraft.world.item.JukeboxSongMixin_API", - "minecraft.world.item.RarityMixin_API", - "minecraft.world.item.TiersMixin_API", - "minecraft.world.item.alchemy.PotionMixin_API", - "minecraft.world.item.component.FireworkExplosionMixin_API", - "minecraft.world.item.component.Tool_RuleMixin_API", - "minecraft.world.item.crafting.AbstractCookingRecipeMixin_API", - "minecraft.world.item.crafting.CraftingRecipeMixin_API", - "minecraft.world.item.crafting.CustomRecipeMixin_API", - "minecraft.world.item.crafting.IngredientMixin_API", - "minecraft.world.item.crafting.RecipeManagerMixin_API", - "minecraft.world.item.crafting.RecipeMixin_API", - "minecraft.world.item.crafting.RecipeTypeMixin_API", - "minecraft.world.item.crafting.ShapedRecipeMixin_API", - "minecraft.world.item.crafting.ShapelessRecipeMixin_API", - "minecraft.world.item.crafting.SingleItemRecipeMixin_API", - "minecraft.world.item.crafting.SmithingTransformRecipeMixin_API", - "minecraft.world.item.crafting.StonecutterRecipeMixin_API", - "minecraft.world.item.enchantment.EnchantmentMixin_API", - "minecraft.world.item.trading.MerchantOfferMixin_API", - "minecraft.world.level.BlockGetterMixin_API", - "minecraft.world.level.EntityGetterMixin_API", - "minecraft.world.level.ExplosionMixin_API", - "minecraft.world.level.GameRules_KeyMixin_API", - "minecraft.world.level.GameTypeMixin_API", - "minecraft.world.level.LevelAccessorMixin_API", - "minecraft.world.level.LevelMixin_API", - "minecraft.world.level.LevelReaderMixin_API", - "minecraft.world.level.LevelWriterMixin_API", - "minecraft.world.level.LightLayerMixin_API", - "minecraft.world.level.biome.AmbientAdditionsSettingsMixin_API", - "minecraft.world.level.biome.AmbientMoodSettingsMixin_API", - "minecraft.world.level.biome.AmbientParticleSettingsMixin_API", - "minecraft.world.level.biome.Biome_PrecipitationMixin_API", - "minecraft.world.level.biome.Biome_TemperatureModifierMixin_API", - "minecraft.world.level.biome.BiomeMixin_API", - "minecraft.world.level.biome.BiomeSourceMixin_API", - "minecraft.world.level.biome.BiomeSpecialEffects_GrassColorModifierMixin_API", - "minecraft.world.level.biome.CheckerboardColumnBiomeSourceMixin_API", - "minecraft.world.level.biome.Climate_ParameterMixin_API", - "minecraft.world.level.biome.Climate_ParameterPointMixin_API", - "minecraft.world.level.biome.FixedBiomeSourceMixin_API", - "minecraft.world.level.biome.MobSpawnSettings_MobSpawnCostMixin_API", - "minecraft.world.level.biome.MobSpawnSettings_SpawnerDataMixin_API", - "minecraft.world.level.biome.MultiNoiseBiomeSourceMixin_API", - "minecraft.world.level.biome.TheEndBiomeSourceMixin_API", - "minecraft.world.level.block.MirrorMixin_API", - "minecraft.world.level.block.RotationMixin_API", - "minecraft.world.level.block.entity.AbstractFurnaceBlockEntityMixin_API", - "minecraft.world.level.block.entity.BannerBlockEntityMixin_API", - "minecraft.world.level.block.entity.BannerPatternLayers_LayerMixin_API", - "minecraft.world.level.block.entity.BannerPatternMixin_API", - "minecraft.world.level.block.entity.BarrelBlockEntityMixin_API", - "minecraft.world.level.block.entity.BaseContainerBlockEntityMixin_API", - "minecraft.world.level.block.entity.BeaconBlockEntityMixin_API", - "minecraft.world.level.block.entity.BedBlockEntityMixin_API", - "minecraft.world.level.block.entity.BeehiveBlockEntityMixin_API", - "minecraft.world.level.block.entity.BellBlockEntityMixin_API", - "minecraft.world.level.block.entity.BlastFurnaceBlockEntityMixin_API", - "minecraft.world.level.block.entity.BlockEntityMixin_API", - "minecraft.world.level.block.entity.BlockEntityTypeMixin_API", - "minecraft.world.level.block.entity.BrewingStandBlockEntityMixin_API", - "minecraft.world.level.block.entity.CampfireBlockEntityMixin_API", - "minecraft.world.level.block.entity.ChestBlockEntityMixin_API", - "minecraft.world.level.block.entity.CommandBlockEntityMixin_API", - "minecraft.world.level.block.entity.ComparatorBlockEntityMixin_API", - "minecraft.world.level.block.entity.ConduitBlockEntityMixin_API", - "minecraft.world.level.block.entity.DaylightDetectorBlockEntityMixin_API", - "minecraft.world.level.block.entity.DispenserBlockEntityMixin_API", - "minecraft.world.level.block.entity.DropperBlockEntityMixin_API", - "minecraft.world.level.block.entity.EnchantmentTableBlockEntityMixin_API", - "minecraft.world.level.block.entity.EnderChestBlockEntityMixin_API", - "minecraft.world.level.block.entity.FurnaceBlockEntityMixin_API", - "minecraft.world.level.block.entity.HopperBlockEntityMixin_API", - "minecraft.world.level.block.entity.JigsawBlockEntityMixin_API", - "minecraft.world.level.block.entity.JukeboxBlockEntityMixin_API", - "minecraft.world.level.block.entity.LecternBlockEntityMixin_API", - "minecraft.world.level.block.entity.RandomizableContainerBlockEntityMixin_API", - "minecraft.world.level.block.entity.SculkSensorBlockEntityMixin_API", - "minecraft.world.level.block.entity.ShulkerBoxBlockEntityMixin_API", - "minecraft.world.level.block.entity.SignBlockEntityMixin_API", - "minecraft.world.level.block.entity.SignTextMixin_API", - "minecraft.world.level.block.entity.SkullBlockEntityMixin_API", - "minecraft.world.level.block.entity.SmokerBlockEntityMixin_API", - "minecraft.world.level.block.entity.SpawnerBlockEntityMixin_API", - "minecraft.world.level.block.entity.StructureBlockEntityMixin_API", - "minecraft.world.level.block.entity.TheEndGatewayBlockEntityMixin_API", - "minecraft.world.level.block.entity.TheEndPortalBlockEntityMixin_API", - "minecraft.world.level.block.entity.TrappedCheckBlockEntityMixin_API", - "minecraft.world.level.block.entity.trialspawner.TrialSpawnerStateMixin_API", - "minecraft.world.level.block.entity.vault.VaultStateMixin_API", - "minecraft.world.level.block.piston.PistonMovingBlockEntityMixin_API", - "minecraft.world.level.block.state.BlockBehaviour_BlockStateBaseMixin_API", - "minecraft.world.level.block.state.BlockStateMixin_API", - "minecraft.world.level.block.state.StateHolderMixin_API", - "minecraft.world.level.block.state.properties.AttachFaceMixin_API", - "minecraft.world.level.block.state.properties.BambooLeavesMixin_API", - "minecraft.world.level.block.state.properties.BellAttachTypeMixin_API", - "minecraft.world.level.block.state.properties.ChestTypeMixin_API", - "minecraft.world.level.block.state.properties.ComparatorModeMixin_API", - "minecraft.world.level.block.state.properties.DoorHingeSideMixin_API", - "minecraft.world.level.block.state.properties.DripstoneThicknessMixin_API", - "minecraft.world.level.block.state.properties.FrontAndTopMixin_API", - "minecraft.world.level.block.state.properties.HalfMixin_API", - "minecraft.world.level.block.state.properties.NoteBlockInstrumentMixin_API", - "minecraft.world.level.block.state.properties.PistonTypeMixin_API", - "minecraft.world.level.block.state.properties.RailShapeMixin_API", - "minecraft.world.level.block.state.properties.RedstoneSideMixin_API", - "minecraft.world.level.block.state.properties.SculkSensorPhaseMixin_API", - "minecraft.world.level.block.state.properties.SlabTypeMixin_API", - "minecraft.world.level.block.state.properties.StairsShapeMixin_API", - "minecraft.world.level.block.state.properties.StructureModeMixin_API", - "minecraft.world.level.block.state.properties.TiltMixin_API", - "minecraft.world.level.block.state.properties.WallSideMixin_API", - "minecraft.world.level.border.WorldBorderMixin_Settings_API", - "minecraft.world.level.chunk.ChunkAccessMixin_API", - "minecraft.world.level.chunk.ChunkGeneratorMixin_API", - "minecraft.world.level.chunk.ChunkStatusMixin_API", - "minecraft.world.level.chunk.EmptyLevelChunkMixin_API", - "minecraft.world.level.chunk.LevelChunkMixin_API", - "minecraft.world.level.chunk.ProtoChunkMixin_API", - "minecraft.world.level.dimension.DimensionTypeMixin_API", - "minecraft.world.level.levelgen.DensityFunctionMixin_API", - "minecraft.world.level.levelgen.FlatLevelSourceMixin_API", - "minecraft.world.level.levelgen.GenerationStep_CarvingMixin_API", - "minecraft.world.level.levelgen.GenerationStep_DecorationMixin_API", - "minecraft.world.level.levelgen.Heightmap_TypeMixin_API", - "minecraft.world.level.levelgen.NoiseBasedChunkGeneratorMixin_API", - "minecraft.world.level.levelgen.NoiseGeneratorSettingsMixin_API", - "minecraft.world.level.levelgen.NoiseRouterMixin_API", - "minecraft.world.level.levelgen.NoiseSettingsMixin_API", - "minecraft.world.level.levelgen.NormalNoise_NoiseParametersMixin_API", - "minecraft.world.level.levelgen.SurfaceRules_ConditionSourceMixin_API", - "minecraft.world.level.levelgen.SurfaceRules_RulesSourceMixin_API", - "minecraft.world.level.levelgen.VerticalAnchorMixin_API", - "minecraft.world.level.levelgen.WorldOptionsMixin_API", - "minecraft.world.level.levelgen.carver.ConfiguredWorldCarverMixin_API", - "minecraft.world.level.levelgen.carver.WorldCarverMixin_API", - "minecraft.world.level.levelgen.feature.ConfiguredFeatureMixin_API", - "minecraft.world.level.levelgen.feature.FeatureMixin_API", - "minecraft.world.level.levelgen.flat.FlatLayerInfoMixin_API", - "minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettingsMixin_API", - "minecraft.world.level.levelgen.placement.PlacedFeatureMixin_API", - "minecraft.world.level.levelgen.placement.PlacementModifierMixin_API", - "minecraft.world.level.levelgen.placement.PlacementModifierTypeMixin_API", - "minecraft.world.level.levelgen.structure.StructureMixin_API", - "minecraft.world.level.levelgen.structure.StructurePlacementMixin_API", - "minecraft.world.level.levelgen.structure.StructureSetMixin_API", - "minecraft.world.level.levelgen.structure.StructureSpawnOverrideMixin_API", - "minecraft.world.level.levelgen.structure.StructureTypeMixin_API", - "minecraft.world.level.levelgen.structure.pools.StructurePoolElementMixin_API", - "minecraft.world.level.levelgen.structure.pools.StructureTemplatePool_ProjectionMixin_API", - "minecraft.world.level.levelgen.structure.pools.StructureTemplatePoolMixin_API", - "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorListMixin_API", - "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorMixin_API", - "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorTypeMixin_API", - "minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateMixin_API", - "minecraft.world.level.material.FluidMixin_API", - "minecraft.world.level.material.FluidStateMixin_API", - "minecraft.world.level.material.PushReactionMixin_API", - "minecraft.world.level.saveddata.MapDecorationMixin", - "minecraft.world.level.saveddata.MapItemSavedDataMixin", - "minecraft.world.level.storage.LevelDataMixin_API", - "minecraft.world.level.storage.PrimaryLevelDataMixin_API", - "minecraft.world.level.storage.ServerLevelDataMixin_API", - "minecraft.world.scores.DisplaySlotMixin_API", - "minecraft.world.scores.PlayerTeamMixin_API", - "minecraft.world.scores.Team_CollisionRuleMixin_API", - "minecraft.world.scores.Team_VisibilityMixin_API", - "minecraft.world.scores.criteria.ObjectiveCriteria_RenderTypeMixin_API", - "minecraft.world.scores.criteria.ObjectiveCriteriaMixin_API", - "minecraft.world.ticks.LevelTicksMixin_API", - "minecraft.world.ticks.ScheduledTickMixin_API", - "minecraft.world.ticks.TickPriorityMixin_API", - "service.permission.SubjectMixin_API", - "world.LocatableBlockMixin_API" - ], - "client": [ - "minecraft.client.MinecraftMixin_API", - "minecraft.client.multiplayer.ClientCommonPacketListenerImplMixin_API", - "minecraft.client.multiplayer.ClientConfigurationPacketListenerImplMixin_API", - "minecraft.client.multiplayer.ClientHandshakePacketListenerImplMixin_API", - "minecraft.client.multiplayer.ClientLevel_ClientLevelDataMixin_API", - "minecraft.client.multiplayer.ClientLevelMixin_API", - "minecraft.client.multiplayer.ClientPacketListenerMixin_API", - "minecraft.client.player.AbstractClientPlayerMixin_API", - "minecraft.client.player.LocalPlayerMixin_API", - "minecraft.client.player.RemotePlayerMixin_API", - "minecraft.client.server.IntegratedServerMixin_API" - ], - "server": [ - "minecraft.server.dedicated.DedicatedServerMixin_API" - ], - "overwrites": { - "conformVisibility": true + "minecraft.world.item.RarityMixin_API", + "minecraft.world.item.TiersMixin_API", + "minecraft.world.item.alchemy.PotionMixin_API", + "minecraft.world.item.component.FireworkExplosionMixin_API", + "minecraft.world.item.component.Tool_RuleMixin_API", + "minecraft.world.item.crafting.AbstractCookingRecipeMixin_API", + "minecraft.world.item.crafting.CraftingRecipeMixin_API", + "minecraft.world.item.crafting.CustomRecipeMixin_API", + "minecraft.world.item.crafting.IngredientMixin_API", + "minecraft.world.item.crafting.RecipeManagerMixin_API", + "minecraft.world.item.crafting.RecipeMixin_API", + "minecraft.world.item.crafting.RecipeTypeMixin_API", + "minecraft.world.item.crafting.ShapedRecipeMixin_API", + "minecraft.world.item.crafting.ShapelessRecipeMixin_API", + "minecraft.world.item.crafting.SingleItemRecipeMixin_API", + "minecraft.world.item.crafting.SmithingTransformRecipeMixin_API", + "minecraft.world.item.crafting.StonecutterRecipeMixin_API", + "minecraft.world.item.enchantment.EnchantmentMixin_API", + "minecraft.world.item.trading.MerchantOfferMixin_API", + "minecraft.world.level.BlockGetterMixin_API", + "minecraft.world.level.EntityGetterMixin_API", + "minecraft.world.level.ExplosionMixin_API", + "minecraft.world.level.GameRules_KeyMixin_API", + "minecraft.world.level.GameTypeMixin_API", + "minecraft.world.level.LevelAccessorMixin_API", + "minecraft.world.level.LevelMixin_API", + "minecraft.world.level.LevelReaderMixin_API", + "minecraft.world.level.LevelWriterMixin_API", + "minecraft.world.level.LightLayerMixin_API", + "minecraft.world.level.biome.AmbientAdditionsSettingsMixin_API", + "minecraft.world.level.biome.AmbientMoodSettingsMixin_API", + "minecraft.world.level.biome.AmbientParticleSettingsMixin_API", + "minecraft.world.level.biome.Biome_PrecipitationMixin_API", + "minecraft.world.level.biome.Biome_TemperatureModifierMixin_API", + "minecraft.world.level.biome.BiomeMixin_API", + "minecraft.world.level.biome.BiomeSourceMixin_API", + "minecraft.world.level.biome.BiomeSpecialEffects_GrassColorModifierMixin_API", + "minecraft.world.level.biome.CheckerboardColumnBiomeSourceMixin_API", + "minecraft.world.level.biome.Climate_ParameterMixin_API", + "minecraft.world.level.biome.Climate_ParameterPointMixin_API", + "minecraft.world.level.biome.FixedBiomeSourceMixin_API", + "minecraft.world.level.biome.MobSpawnSettings_MobSpawnCostMixin_API", + "minecraft.world.level.biome.MobSpawnSettings_SpawnerDataMixin_API", + "minecraft.world.level.biome.MultiNoiseBiomeSourceMixin_API", + "minecraft.world.level.biome.TheEndBiomeSourceMixin_API", + "minecraft.world.level.block.MirrorMixin_API", + "minecraft.world.level.block.PortalMixin_API", + "minecraft.world.level.block.RotationMixin_API", + "minecraft.world.level.block.entity.AbstractFurnaceBlockEntityMixin_API", + "minecraft.world.level.block.entity.BannerBlockEntityMixin_API", + "minecraft.world.level.block.entity.BannerPatternLayers_LayerMixin_API", + "minecraft.world.level.block.entity.BannerPatternMixin_API", + "minecraft.world.level.block.entity.BarrelBlockEntityMixin_API", + "minecraft.world.level.block.entity.BaseContainerBlockEntityMixin_API", + "minecraft.world.level.block.entity.BeaconBlockEntityMixin_API", + "minecraft.world.level.block.entity.BedBlockEntityMixin_API", + "minecraft.world.level.block.entity.BeehiveBlockEntityMixin_API", + "minecraft.world.level.block.entity.BellBlockEntityMixin_API", + "minecraft.world.level.block.entity.BlastFurnaceBlockEntityMixin_API", + "minecraft.world.level.block.entity.BlockEntityMixin_API", + "minecraft.world.level.block.entity.BlockEntityTypeMixin_API", + "minecraft.world.level.block.entity.BrewingStandBlockEntityMixin_API", + "minecraft.world.level.block.entity.CampfireBlockEntityMixin_API", + "minecraft.world.level.block.entity.ChestBlockEntityMixin_API", + "minecraft.world.level.block.entity.CommandBlockEntityMixin_API", + "minecraft.world.level.block.entity.ComparatorBlockEntityMixin_API", + "minecraft.world.level.block.entity.ConduitBlockEntityMixin_API", + "minecraft.world.level.block.entity.DaylightDetectorBlockEntityMixin_API", + "minecraft.world.level.block.entity.DispenserBlockEntityMixin_API", + "minecraft.world.level.block.entity.DropperBlockEntityMixin_API", + "minecraft.world.level.block.entity.EnchantmentTableBlockEntityMixin_API", + "minecraft.world.level.block.entity.EnderChestBlockEntityMixin_API", + "minecraft.world.level.block.entity.FurnaceBlockEntityMixin_API", + "minecraft.world.level.block.entity.HopperBlockEntityMixin_API", + "minecraft.world.level.block.entity.JigsawBlockEntityMixin_API", + "minecraft.world.level.block.entity.JukeboxBlockEntityMixin_API", + "minecraft.world.level.block.entity.LecternBlockEntityMixin_API", + "minecraft.world.level.block.entity.RandomizableContainerBlockEntityMixin_API", + "minecraft.world.level.block.entity.SculkSensorBlockEntityMixin_API", + "minecraft.world.level.block.entity.ShulkerBoxBlockEntityMixin_API", + "minecraft.world.level.block.entity.SignBlockEntityMixin_API", + "minecraft.world.level.block.entity.SignTextMixin_API", + "minecraft.world.level.block.entity.SkullBlockEntityMixin_API", + "minecraft.world.level.block.entity.SmokerBlockEntityMixin_API", + "minecraft.world.level.block.entity.SpawnerBlockEntityMixin_API", + "minecraft.world.level.block.entity.StructureBlockEntityMixin_API", + "minecraft.world.level.block.entity.TheEndGatewayBlockEntityMixin_API", + "minecraft.world.level.block.entity.TheEndPortalBlockEntityMixin_API", + "minecraft.world.level.block.entity.TrappedCheckBlockEntityMixin_API", + "minecraft.world.level.block.entity.trialspawner.TrialSpawnerStateMixin_API", + "minecraft.world.level.block.entity.vault.VaultStateMixin_API", + "minecraft.world.level.block.piston.PistonMovingBlockEntityMixin_API", + "minecraft.world.level.block.state.BlockBehaviour_BlockStateBaseMixin_API", + "minecraft.world.level.block.state.BlockStateMixin_API", + "minecraft.world.level.block.state.StateHolderMixin_API", + "minecraft.world.level.block.state.properties.AttachFaceMixin_API", + "minecraft.world.level.block.state.properties.BambooLeavesMixin_API", + "minecraft.world.level.block.state.properties.BellAttachTypeMixin_API", + "minecraft.world.level.block.state.properties.ChestTypeMixin_API", + "minecraft.world.level.block.state.properties.ComparatorModeMixin_API", + "minecraft.world.level.block.state.properties.DoorHingeSideMixin_API", + "minecraft.world.level.block.state.properties.DripstoneThicknessMixin_API", + "minecraft.world.level.block.state.properties.FrontAndTopMixin_API", + "minecraft.world.level.block.state.properties.HalfMixin_API", + "minecraft.world.level.block.state.properties.NoteBlockInstrumentMixin_API", + "minecraft.world.level.block.state.properties.PistonTypeMixin_API", + "minecraft.world.level.block.state.properties.RailShapeMixin_API", + "minecraft.world.level.block.state.properties.RedstoneSideMixin_API", + "minecraft.world.level.block.state.properties.SculkSensorPhaseMixin_API", + "minecraft.world.level.block.state.properties.SlabTypeMixin_API", + "minecraft.world.level.block.state.properties.StairsShapeMixin_API", + "minecraft.world.level.block.state.properties.StructureModeMixin_API", + "minecraft.world.level.block.state.properties.TiltMixin_API", + "minecraft.world.level.block.state.properties.WallSideMixin_API", + "minecraft.world.level.border.WorldBorderMixin_Settings_API", + "minecraft.world.level.chunk.ChunkAccessMixin_API", + "minecraft.world.level.chunk.ChunkGeneratorMixin_API", + "minecraft.world.level.chunk.ChunkStatusMixin_API", + "minecraft.world.level.chunk.EmptyLevelChunkMixin_API", + "minecraft.world.level.chunk.LevelChunkMixin_API", + "minecraft.world.level.chunk.ProtoChunkMixin_API", + "minecraft.world.level.dimension.DimensionTypeMixin_API", + "minecraft.world.level.levelgen.DensityFunctionMixin_API", + "minecraft.world.level.levelgen.FlatLevelSourceMixin_API", + "minecraft.world.level.levelgen.GenerationStep_CarvingMixin_API", + "minecraft.world.level.levelgen.GenerationStep_DecorationMixin_API", + "minecraft.world.level.levelgen.Heightmap_TypeMixin_API", + "minecraft.world.level.levelgen.NoiseBasedChunkGeneratorMixin_API", + "minecraft.world.level.levelgen.NoiseGeneratorSettingsMixin_API", + "minecraft.world.level.levelgen.NoiseRouterMixin_API", + "minecraft.world.level.levelgen.NoiseSettingsMixin_API", + "minecraft.world.level.levelgen.NormalNoise_NoiseParametersMixin_API", + "minecraft.world.level.levelgen.SurfaceRules_ConditionSourceMixin_API", + "minecraft.world.level.levelgen.SurfaceRules_RulesSourceMixin_API", + "minecraft.world.level.levelgen.VerticalAnchorMixin_API", + "minecraft.world.level.levelgen.WorldOptionsMixin_API", + "minecraft.world.level.levelgen.carver.ConfiguredWorldCarverMixin_API", + "minecraft.world.level.levelgen.carver.WorldCarverMixin_API", + "minecraft.world.level.levelgen.feature.ConfiguredFeatureMixin_API", + "minecraft.world.level.levelgen.feature.FeatureMixin_API", + "minecraft.world.level.levelgen.flat.FlatLayerInfoMixin_API", + "minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettingsMixin_API", + "minecraft.world.level.levelgen.placement.PlacedFeatureMixin_API", + "minecraft.world.level.levelgen.placement.PlacementModifierMixin_API", + "minecraft.world.level.levelgen.placement.PlacementModifierTypeMixin_API", + "minecraft.world.level.levelgen.structure.StructureMixin_API", + "minecraft.world.level.levelgen.structure.StructurePlacementMixin_API", + "minecraft.world.level.levelgen.structure.StructureSetMixin_API", + "minecraft.world.level.levelgen.structure.StructureSpawnOverrideMixin_API", + "minecraft.world.level.levelgen.structure.StructureTypeMixin_API", + "minecraft.world.level.levelgen.structure.pools.StructurePoolElementMixin_API", + "minecraft.world.level.levelgen.structure.pools.StructureTemplatePool_ProjectionMixin_API", + "minecraft.world.level.levelgen.structure.pools.StructureTemplatePoolMixin_API", + "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorListMixin_API", + "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorMixin_API", + "minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorTypeMixin_API", + "minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateMixin_API", + "minecraft.world.level.material.FluidMixin_API", + "minecraft.world.level.material.FluidStateMixin_API", + "minecraft.world.level.material.PushReactionMixin_API", + "minecraft.world.level.saveddata.MapDecorationMixin", + "minecraft.world.level.saveddata.MapItemSavedDataMixin", + "minecraft.world.level.storage.LevelDataMixin_API", + "minecraft.world.level.storage.PrimaryLevelDataMixin_API", + "minecraft.world.level.storage.ServerLevelDataMixin_API", + "minecraft.world.scores.DisplaySlotMixin_API", + "minecraft.world.scores.PlayerTeamMixin_API", + "minecraft.world.scores.Team_CollisionRuleMixin_API", + "minecraft.world.scores.Team_VisibilityMixin_API", + "minecraft.world.scores.criteria.ObjectiveCriteria_RenderTypeMixin_API", + "minecraft.world.scores.criteria.ObjectiveCriteriaMixin_API", + "minecraft.world.ticks.LevelTicksMixin_API", + "minecraft.world.ticks.ScheduledTickMixin_API", + "minecraft.world.ticks.TickPriorityMixin_API", + "service.permission.SubjectMixin_API", + "world.LocatableBlockMixin_API" + ], + "client": [ + "minecraft.client.MinecraftMixin_API", + "minecraft.client.multiplayer.ClientCommonPacketListenerImplMixin_API", + "minecraft.client.multiplayer.ClientConfigurationPacketListenerImplMixin_API", + "minecraft.client.multiplayer.ClientHandshakePacketListenerImplMixin_API", + "minecraft.client.multiplayer.ClientLevel_ClientLevelDataMixin_API", + "minecraft.client.multiplayer.ClientLevelMixin_API", + "minecraft.client.multiplayer.ClientPacketListenerMixin_API", + "minecraft.client.player.AbstractClientPlayerMixin_API", + "minecraft.client.player.LocalPlayerMixin_API", + "minecraft.client.player.RemotePlayerMixin_API", + "minecraft.client.server.IntegratedServerMixin_API" + ], + "server": [ + "minecraft.server.dedicated.DedicatedServerMixin_API" + ], + "overwrites": { + "conformVisibility": true } } diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index d96b7cafbbc..9c5a55ff9f3 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -20,13 +20,13 @@ "block.BedBlockMixin", "block.BlockMixin", "block.DyeColorBlockPropertiesMixin", - "commands.execution.tasks.ExecuteCommandMixin", "commands.CommandsMixin", "commands.CommandSourceMixin", "commands.CommandSourceStackMixin", "commands.arguments.ComponentArgumentMixin", "commands.arguments.DimensionArgumentMixin", "commands.arguments.selector.EntitySelectorParserMixin", + "commands.execution.tasks.ExecuteCommandMixin", "core.MappedRegistryMixin", "core.Vec3iMixin", "core.dispenser.ProjectileDispenseBehaviorMixin", @@ -118,6 +118,7 @@ "world.entity.LightningBoltMixin", "world.entity.LivingEntityMixin", "world.entity.MobMixin", + "world.entity.PortalProcessorMixin", "world.entity.ai.goal.BreakDoorGoalMixin", "world.entity.ai.goal.BreedGoalMixin", "world.entity.ai.goal.EatBlockGoalMixin", @@ -223,6 +224,7 @@ "world.level.block.FireBlockMixin", "world.level.block.LeavesBlockMixin", "world.level.block.MagmaBlockMixin", + "world.level.block.NetherPortalBlockMixin", "world.level.block.NoteBlockMixin", "world.level.block.entity.AbstractFurnaceBlockEntityMixin", "world.level.block.entity.BannerBlockEntityMixin", @@ -237,7 +239,6 @@ "world.level.block.entity.LecternBlockEntityMixin", "world.level.block.entity.SignBlockEntityMixin", "world.level.block.entity.SkullBlockEntityMixin", - "world.level.block.entity.TheEndGatewayBlockEntityMixin", "world.level.block.piston.PistonMovingBlockEntityMixin", "world.level.block.state.BlockBehaviour_PropertiesMixin", "world.level.block.state.BlockStateMixin", @@ -257,7 +258,6 @@ "world.level.levelgen.flat.FlatLayerInfoMixin", "world.level.levelgen.flat.FlatLevelGeneratorSettingsMixin", "world.level.levelgen.structure.LegacyStructureDataHandlerMixin", - "world.level.portal.PortalShapeMixin", "world.level.saveddata.MapIdTrackerMixin", "world.level.storage.DimensionDataStorageMixin", "world.level.storage.LevelDataMixin", diff --git a/testplugins/src/main/java/org/spongepowered/test/changeblock/ChangeBlockTest.java b/testplugins/src/main/java/org/spongepowered/test/changeblock/ChangeBlockTest.java index 5376a767775..a8951a5dd8e 100644 --- a/testplugins/src/main/java/org/spongepowered/test/changeblock/ChangeBlockTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/changeblock/ChangeBlockTest.java @@ -227,7 +227,7 @@ class ChangeBlockListener { private void onChangeBlock(final ChangeBlockEvent.All post) { final Logger pluginLogger = ChangeBlockTest.this.plugin.logger(); pluginLogger.log(Level.INFO, ChangeBlockTest.marker, "/*************"); - pluginLogger.log(Level.INFO, ChangeBlockTest.marker, "/* ChangeBlockEvent"); + pluginLogger.log(Level.INFO, ChangeBlockTest.marker, "/* ChangeBlockEvent " + post.transactions().size() + " transactions"); pluginLogger.log(Level.INFO, ChangeBlockTest.marker, "/"); pluginLogger.log(Level.INFO, ChangeBlockTest.marker, "/ Cause:"); for (final Object o : post.cause()) { @@ -246,6 +246,7 @@ private void onChangeBlock(final ChangeBlockEvent.All post) { return; } } + if (ChangeBlockTest.this.cancelAll) { post.setCancelled(true); } diff --git a/testplugins/src/main/java/org/spongepowered/test/portal/PortalTest.java b/testplugins/src/main/java/org/spongepowered/test/portal/PortalTest.java index ea0ebde530c..4d46920fa4f 100644 --- a/testplugins/src/main/java/org/spongepowered/test/portal/PortalTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/portal/PortalTest.java @@ -25,12 +25,31 @@ package org.spongepowered.test.portal; import com.google.inject.Inject; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.EventContextKeys; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.cause.entity.MovementTypes; +import org.spongepowered.api.event.entity.ChangeEntityWorldEvent; +import org.spongepowered.api.event.entity.InvokePortalEvent; +import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3i; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; import org.spongepowered.test.LoadableModule; +import java.util.Optional; + @Plugin("portaltest") public final class PortalTest implements LoadableModule { @@ -48,6 +67,10 @@ public PortalTest(final PluginContainer pluginContainer) { @Override public void enable(final CommandContext ctx) { Sponge.eventManager().registerListeners(this.pluginContainer, PortalTest.Holder.INSTANCE); + ctx.cause().first(ServerPlayer.class).ifPresent(player -> { + final var portalONE = PortalLogic.builder().addSimplePortal((from, fromPos, entity) -> Optional.of(entity.serverLocation().add(Vector3i.ONE))).build(); + player.offer(Keys.PORTAL_LOGIC, portalONE); + }); } @Override @@ -55,4 +78,70 @@ public void disable(final CommandContext ctx) { Sponge.eventManager().unregisterListeners(PortalTest.Holder.INSTANCE); } + /** + * A portal that + *

- calculates to the exit to be 6 blocks up from the entity position

+ *

- tries to find an existing nether-portal at the exit location

+ *

- generates an end platform at the exit location if no portal was found

+ */ + public static class ExanplePortalLogic implements PortalLogic.PortalExitCalculator, PortalLogic.PortalFinder, PortalLogic.PortalGenerator { + + @Override + public Optional calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final Entity entity) { + return Optional.of(entity.serverLocation().add(Vector3i.UP.mul(6))); + } + + @Override + public Optional findPortal(final ServerLocation location, final int searchRange) { + return Optional.empty(); +// return PortalLogic.factory().netherPortalFinder().findPortal(location, 16); + } + + @Override + public Optional generatePortal(final ServerLocation location, final Axis axis) { + return PortalLogic.factory().endPlatformGenerator().generatePortal(location, axis); + } + } + + public static final class PortalTestListener { + + @Listener + private void onChangeWorldPre(final ChangeEntityWorldEvent.Pre event) { + if (PortalTestListener.filter(event)) { + event.setDestinationWorld(event.originalWorld()); + } + } + + @Listener + private void onChangeWorldReposition(final ChangeEntityWorldEvent.Reposition event) { + if (PortalTestListener.filter(event)) { + event.setDestinationPosition(event.destinationPosition().add(0, 2, 0)); + } + } + + @Listener + private void onPortalEnter(final InvokePortalEvent.Enter event) { + System.out.println("InvokePortalEvent.Enter"); + } + + @Listener + private void onPortalPrepare(final InvokePortalEvent.Prepare event) { + System.out.println("InvokePortalEvent.Prepare"); + event.setPortalLogic(PortalLogic.builder().addPortal(new ExanplePortalLogic()).build()); + } + + @Listener + private void onPortalExecute(final InvokePortalEvent.Execute event) { + event.setCancelled(true); + System.out.println("InvokePortalEvent.Execute"); + if (event.entity() instanceof ServerPlayer p) { + p.showTitle(Title.title(Component.text("No nether for you!"), Component.text(":("))); + } + } + + private static boolean filter(final Event event) { + return event.cause().context().get(EventContextKeys.MOVEMENT_TYPE).filter(x -> x == MovementTypes.PORTAL.get()).isPresent(); + } + + } } diff --git a/testplugins/src/main/java/org/spongepowered/test/portal/PortalTestListener.java b/testplugins/src/main/java/org/spongepowered/test/portal/PortalTestListener.java deleted file mode 100644 index 73d888bde91..00000000000 --- a/testplugins/src/main/java/org/spongepowered/test/portal/PortalTestListener.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.test.portal; - -import org.spongepowered.api.event.Event; -import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.event.entity.ChangeEntityWorldEvent; - -public final class PortalTestListener { - - @Listener - private void onChangeWorldPre(final ChangeEntityWorldEvent.Pre event) { - if (PortalTestListener.filter(event)) { - event.setDestinationWorld(event.originalWorld()); - } - } - - @Listener - private void onChangeWorldReposition(final ChangeEntityWorldEvent.Reposition event) { - if (PortalTestListener.filter(event)) { - event.setDestinationPosition(event.originalPosition().add(100, 0, 100)); - } - } - - private static boolean filter(final Event event) { - return event.cause().context().get(EventContextKeys.MOVEMENT_TYPE).filter(x -> x == MovementTypes.PORTAL.get()).isPresent(); - } - -} diff --git a/testplugins/src/main/java/org/spongepowered/test/world/WorldTest.java b/testplugins/src/main/java/org/spongepowered/test/world/WorldTest.java index 83bb89f7a00..358e3364690 100644 --- a/testplugins/src/main/java/org/spongepowered/test/world/WorldTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/world/WorldTest.java @@ -50,7 +50,7 @@ import org.spongepowered.api.world.WorldType; import org.spongepowered.api.world.WorldTypeTemplate; import org.spongepowered.api.world.WorldTypes; -import org.spongepowered.api.world.portal.PortalType; +import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.DataPackManager; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; @@ -82,17 +82,16 @@ private void onRegisterCommand(final RegisterCommandEvent final Parameter.Value worldKeyParameter = Parameter.resourceKey().key("world").build(); final Parameter.Value optWorldParameter = Parameter.world().optional().key("world").build(); final Parameter.Value optPositionParameter = Parameter.vector3d().optional().key("position").build(); - final Parameter.Value portalTypeParameter = Parameter.registryElement(TypeToken.get(PortalType.class), RegistryTypes.PORTAL_TYPE, "minecraft", "sponge").key("portal_type").build(); final Parameter.Value worldTypeParameter = Parameter.registryElement(TypeToken.get(WorldType.class), RegistryTypes.WORLD_TYPE, "minecraft", "sponge").key("world_type").build(); final Parameter.Value copyWorldKeyParameter = Parameter.resourceKey().key("copy_world").build(); final Parameter.Value moveWorldKeyParameter = Parameter.resourceKey().key("move_world").build(); - event.register(this.plugin, Command.builder().addParameters(CommonParameters.LOCATION_ONLINE_ONLY, portalTypeParameter) + event.register(this.plugin, Command.builder().addParameters(CommonParameters.LOCATION_ONLINE_ONLY) .permission(this.plugin.metadata().id() + ".command.portal.create") - .executor(context -> this.createPortal(context, portalTypeParameter)).build(), "cp", "createportal") - .register(this.plugin, Command.builder().addParameters(optPlayerParameter, CommonParameters.LOCATION_ONLINE_ONLY, portalTypeParameter) + .executor(this::createPortal).build(), "cp", "createportal") + .register(this.plugin, Command.builder().addParameters(optPlayerParameter, CommonParameters.LOCATION_ONLINE_ONLY) .permission(this.plugin.metadata().id() + ".command.portal.use") - .executor(context -> this.useportal(context, optPlayerParameter, portalTypeParameter)).build(), "up", "useportal") + .executor(context -> this.useportal(context, optPlayerParameter)).build(), "up", "useportal") .register(this.plugin, Command.builder().addParameters(optPlayerParameter, worldTypeParameter) .permission(this.plugin.metadata().id() + ".command.environment.change") .executor(context -> this.changeEnvironement(context, optPlayerParameter, worldTypeParameter)).build(), "ce", "changeenvironment") @@ -125,16 +124,15 @@ private void onRegisterCommand(final RegisterCommandEvent ; } - private CommandResult createPortal(final CommandContext context, final Parameter.Value portalTypeParameter) { + private CommandResult createPortal(final CommandContext context) { final ServerLocation location = context.requireOne(CommonParameters.LOCATION_ONLINE_ONLY); - final PortalType portalType = context.requireOne(portalTypeParameter); - portalType.generatePortal(location, Axis.X); + PortalLogic.factory().netherPortal().generator().get().generatePortal(location, Axis.X); return CommandResult.success(); } - private CommandResult useportal(final CommandContext context, final Parameter.Value optPlayerParameter, final Parameter.Value portalTypeParameter) { + private CommandResult useportal(final CommandContext context, final Parameter.Value optPlayerParameter) { final ServerPlayer player = context.one(optPlayerParameter).orElse(this.getSourcePlayer(context)); final ServerLocation location = context.requireOne(CommonParameters.LOCATION_ONLINE_ONLY); - final PortalType portalType = context.requireOne(portalTypeParameter); + final PortalLogic portalType = PortalLogic.factory().netherPortal(); return portalType.teleport(player, location, true) ? CommandResult.success() : CommandResult.error(Component.text("Could not teleport!")); } diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java index 0536dc07ba2..8897322b235 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java @@ -24,13 +24,10 @@ */ package org.spongepowered.vanilla.mixin.core.server.level; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.DimensionType; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; import org.spongepowered.common.entity.player.ClientType; @@ -41,7 +38,6 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.network.packet.ChangeViewerEnvironmentPacket; import org.spongepowered.common.network.packet.SpongePacketHandler; -import org.spongepowered.common.world.portal.PortalLogic; import org.spongepowered.vanilla.mixin.core.world.entity.LivingEntityMixin_Vanilla; @Mixin(net.minecraft.server.level.ServerPlayer.class) @@ -54,26 +50,6 @@ public abstract class ServerPlayerMixin_Vanilla extends LivingEntityMixin_Vanill } } - /** - * @author dualspiral - 18th December 2020 - 1.16.4 - * @reason Redirects the vanilla changeDimension method to our own - * to support our event and other logic (see - * ServerPlayerEntityMixin on the common mixin sourceset for - * details). - * - * This method does not explicitly exist on SeverPlayerEntity - * on Forge, it is an overridden method in Vanilla so needs doing - * here as well as in EntityMixin_Vanilla. - * - * This will get called on the nether dimension changes, as the - * end portal teleport call itself has been redirected to provide - * the correct type. - */ - @Overwrite - public net.minecraft.world.entity.@Nullable Entity changeDimension(final ServerLevel target) { - return this.bridge$changeDimension(target, (PortalLogic) target.getPortalForcer()); - } - // override from LivingEntityMixin_Vanilla @Override protected void vanilla$onElytraUse(final CallbackInfo ci) { diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/EntityMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/EntityMixin_Vanilla.java index b9797c685c9..2b76a635ef3 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/EntityMixin_Vanilla.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/EntityMixin_Vanilla.java @@ -26,12 +26,9 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.bridge.world.entity.EntityBridge; -import org.spongepowered.common.world.portal.PortalLogic; @Mixin(Entity.class) public abstract class EntityMixin_Vanilla implements EntityBridge { @@ -40,17 +37,4 @@ public abstract class EntityMixin_Vanilla implements EntityBridge { @Shadow public abstract Level shadow$level(); // @formatter:on - - /** - * @author dualspiral - 19th December 2020 - 1.16.4 - * @reason Overwrite to redirect call to - * {@link #bridge$changeDimension(net.minecraft.server.level.ServerLevel, PortalLogic)}, this - * is to support Forge mods and their ITeleporter - */ - @Overwrite - @Nullable - public Entity changeDimension(final net.minecraft.server.level.ServerLevel originalDestinationWorld) { - return this.bridge$changeDimension(originalDestinationWorld, (PortalLogic) originalDestinationWorld.getPortalForcer()); - } - } diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/projectile/ThrownEnderpearlMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/projectile/ThrownEnderpearlMixin_Vanilla.java deleted file mode 100644 index 901dcaf6f13..00000000000 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/projectile/ThrownEnderpearlMixin_Vanilla.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.mixin.core.world.entity.projectile; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.projectile.ThrownEnderpearl; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ThrownEnderpearl.class) -public abstract class ThrownEnderpearlMixin_Vanilla { - - @Redirect(method = "changeDimension", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ThrownEnderpearl;getOwner()Lnet/minecraft/world/entity/Entity;")) - private Entity vanilla$preventUnsetOwnerUntilLater(final ThrownEnderpearl thrownEnderpearl) { - // This allows us to ensure the if statement after is always false - // We deal with this later (see the common mixin) - return null; - } - -} diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/portal/PortalForcerMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/portal/PortalForcerMixin_Vanilla.java deleted file mode 100644 index 16a3bdcc40e..00000000000 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/portal/PortalForcerMixin_Vanilla.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.mixin.core.world.level.portal; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.portal.PortalForcer; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.phys.Vec3; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.event.cause.entity.MovementType; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.PortalTypes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.world.portal.PortalLogic; - -import java.util.function.Function; - -@Mixin(PortalForcer.class) -public abstract class PortalForcerMixin_Vanilla implements PortalLogic { - - @Override - public @Nullable PortalInfo getPortalInfo( - final Entity entity, final ServerLevel targetWorld, final Function defaultPortalInfo) { - return this.isVanilla() ? defaultPortalInfo.apply(targetWorld) : new PortalInfo(entity.position(), Vec3.ZERO, entity.getYRot(), entity.getXRot()); - } - - @Override - public @Nullable Entity placeEntity(final Entity entity, final ServerLevel currentWorld, final ServerLevel targetWorld, final float yRot, - final Function teleportLogic) { - return teleportLogic.apply(true); - } - - @Override - public boolean isVanilla() { - return this.getClass().equals(PortalForcer.class); - } - - @Override - public MovementType getMovementType() { - return MovementTypes.PORTAL.get(); - } - - @Override - public PortalType getPortalType() { - return PortalTypes.NETHER.get(); - } -} diff --git a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json index c732b3254c0..8110e3c8a58 100644 --- a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json +++ b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json @@ -40,12 +40,10 @@ "world.entity.MobMixin_Attack_Impl", "world.entity.ai.attributes.DefaultAttributesMixin", "world.entity.item.ItemEntityMixin_Vanilla", - "world.entity.projectile.ThrownEnderpearlMixin_Vanilla", "world.entity.player.PlayerMixin_Attack_Impl", "world.entity.vehicle.BoatMixin_Vanilla", "world.level.block.FireBlockMixin_Vanilla", "world.level.block.entity.AbstractFurnaceBlockEntityMixin_Vanilla", - "world.level.portal.PortalForcerMixin_Vanilla", "world.level.storage.LevelStorageSourceMixin_Vanilla" ], "overwrites": { From 45e842931797e9e72d81a418f0f68df86b01f810 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:15:51 +0200 Subject: [PATCH 044/226] fix recipes and inventory + implement RecipeInputs also fixes special crafting recipes --- ...ccessor.java => SmithingMenuAccessor.java} | 15 +- .../inventory/StonecutterMenuAccessor.java} | 31 +- .../AbstractFurnaceBlockEntityAccessor.java | 4 +- .../resources/mixins.sponge.accessors.json | 273 +++++++++--------- .../common/datapack/SpongeDataPackType.java | 2 +- .../inventory/ContainerBasedTransaction.java | 2 +- .../inventory/CraftingPreviewTransaction.java | 2 +- .../SpongeViewableInventoryBuilder.java | 3 +- ...anslator.java => ContainerTranslator.java} | 2 +- .../fabric/InventoryTranslators.java | 4 +- .../fabric/RecipeInputTranslator.java | 78 +++++ .../lens/impl/slot/EquipmentSlotLens.java | 5 +- .../common/inventory/util/InventoryUtil.java | 54 +++- .../item/recipe/SpongeRecipeInputFactory.java | 53 ++++ .../item/recipe/SpongeRecipeRegistration.java | 22 +- .../recipe/cooking/SpongeBlastingRecipe.java | 8 +- .../cooking/SpongeCampfireCookingRecipe.java | 8 +- .../cooking/SpongeCookingRecipeBuilder.java | 10 +- .../SpongeCookingRecipeRegistration.java | 12 +- .../recipe/cooking/SpongeSmeltingRecipe.java | 9 +- .../recipe/cooking/SpongeSmokingRecipe.java | 9 +- .../SpongeSpecialCraftingRecipeBuilder.java | 14 +- ...ongeSpecialCraftingRecipeRegistration.java | 17 +- .../crafting/custom/SpongeSpecialRecipe.java | 43 ++- .../SpongeShapedCraftingRecipeBuilder.java | 19 +- ...pongeShapedCraftingRecipeRegistration.java | 18 +- .../crafting/shaped/SpongeShapedRecipe.java | 10 +- .../SpongeShapelessCraftingRecipeBuilder.java | 15 +- ...geShapelessCraftingRecipeRegistration.java | 18 +- .../shapeless/SpongeShapelessRecipe.java | 29 +- .../ingredient/IngredientResultUtil.java | 10 +- .../recipe/smithing/SpongeSmithingRecipe.java | 4 +- .../smithing/SpongeSmithingRecipeBuilder.java | 10 +- .../SpongeSmithingRecipeRegistration.java | 10 +- .../SpongeStoneCutterRecipeBuilder.java | 10 +- .../SpongeStonecuttingRecipe.java | 8 +- .../SpongeStonecuttingRecipeRegistration.java | 10 +- .../registry/SpongeFactoryProvider.java | 3 + .../server/level/ServerPlayerMixin_API.java | 2 +- .../AttributeModifierMixin_API.java | 18 +- .../item/crafting/RecipeManagerMixin_API.java | 76 ++--- .../world/item/crafting/RecipeMixin_API.java | 26 +- .../item/crafting/RecipeTypeMixin_API.java | 2 +- .../AbstractFurnaceBlockEntityMixin_API.java | 17 +- .../entity/CampfireBlockEntityMixin_API.java | 15 + .../SimpleCraftingRecipeSerializerMixin.java | 58 ++++ .../AbstractFurnaceBlockEntityMixin.java | 7 +- ...erBlockBlockEntityMixin_Inventory_API.java | 51 ++++ .../CraftingContainerMixin_Inventory_API.java | 69 +++++ ...tCraftingContainerMixin_Inventory_API.java | 19 +- .../CraftingInputMixin_Inventory_API.java | 62 ++++ .../RecipeInputMixin_Inventory_API.java | 53 ++++ ...SingleRecipeInputMixin_Inventory_API.java} | 20 +- ...mithingRecipeInputMixin_Inventory_API.java | 35 +++ .../entity/LivingEntityMixin_Inventory.java | 4 +- .../level/ServerPlayerMixin_Inventory.java | 6 +- .../inventory/ResultSlotMixin_Inventory.java | 13 +- .../TraitMixin_InventoryBridge_Inventory.java | 8 +- ...MenuMixin_TrackedMenuBridge_Inventory.java | 2 +- .../RecipeInputMixin_Fabric_Inventory.java | 34 +++ src/mixins/resources/mixins.sponge.core.json | 1 + .../resources/mixins.sponge.inventory.json | 9 +- .../resources/mixins.sponge.optimization.json | 1 - .../spongepowered/test/recipe/RecipeTest.java | 42 ++- 64 files changed, 1005 insertions(+), 499 deletions(-) rename src/accessors/java/org/spongepowered/common/accessor/world/inventory/{InventoryMenuAccessor.java => SmithingMenuAccessor.java} (77%) rename src/{main/java/org/spongepowered/common/util/LazyDataFixerBuilder.java => accessors/java/org/spongepowered/common/accessor/world/inventory/StonecutterMenuAccessor.java} (63%) rename src/main/java/org/spongepowered/common/inventory/fabric/{IInventoryTranslator.java => ContainerTranslator.java} (97%) create mode 100644 src/main/java/org/spongepowered/common/inventory/fabric/RecipeInputTranslator.java create mode 100644 src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/item/crafting/SimpleCraftingRecipeSerializerMixin.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CraftingContainerMixin_Inventory_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/CraftingInputMixin_Inventory_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/RecipeInputMixin_Inventory_API.java rename src/mixins/java/org/spongepowered/common/mixin/{optimization/general/DataFixersMixin_Optimization_LazyDFU.java => inventory/api/world/item/crafting/SingleRecipeInputMixin_Inventory_API.java} (61%) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SmithingRecipeInputMixin_Inventory_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/item/crafting/RecipeInputMixin_Fabric_Inventory.java diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/inventory/InventoryMenuAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/inventory/SmithingMenuAccessor.java similarity index 77% rename from src/accessors/java/org/spongepowered/common/accessor/world/inventory/InventoryMenuAccessor.java rename to src/accessors/java/org/spongepowered/common/accessor/world/inventory/SmithingMenuAccessor.java index 96d2e9fcbf2..19dd70999c2 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/inventory/InventoryMenuAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/inventory/SmithingMenuAccessor.java @@ -24,16 +24,13 @@ */ package org.spongepowered.common.accessor.world.inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.SmithingMenu; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(InventoryMenu.class) -public interface InventoryMenuAccessor { - - @Accessor("craftSlots") CraftingContainer accessor$craftSlots(); - @Accessor("owner") Player accessor$owner(); +@Mixin(SmithingMenu.class) +public interface SmithingMenuAccessor { + @Invoker("createRecipeInput") SmithingRecipeInput invoker$createRecipeInput(); } diff --git a/src/main/java/org/spongepowered/common/util/LazyDataFixerBuilder.java b/src/accessors/java/org/spongepowered/common/accessor/world/inventory/StonecutterMenuAccessor.java similarity index 63% rename from src/main/java/org/spongepowered/common/util/LazyDataFixerBuilder.java rename to src/accessors/java/org/spongepowered/common/accessor/world/inventory/StonecutterMenuAccessor.java index 5c77fa9357f..7b6b94afb21 100644 --- a/src/main/java/org/spongepowered/common/util/LazyDataFixerBuilder.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/inventory/StonecutterMenuAccessor.java @@ -22,29 +22,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.util; +package org.spongepowered.common.accessor.world.inventory; -import com.mojang.datafixers.DSL; -import com.mojang.datafixers.DataFixer; -import com.mojang.datafixers.DataFixerBuilder; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.StonecutterMenu; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; +import org.spongepowered.common.UntransformedInvokerError; -import java.util.Set; -import java.util.concurrent.Executor; +@Mixin(StonecutterMenu.class) +public interface StonecutterMenuAccessor { -/** - * This version of {@code DataFixerBuilder} does not immediately initialize rules. - */ -public class LazyDataFixerBuilder extends DataFixerBuilder { - - private static final Executor NO_OP_EXECUTOR = command -> {}; - - public LazyDataFixerBuilder(int dataVersion) { - super(dataVersion); + @Invoker("createRecipeInput") static SingleRecipeInput invoker$createRecipeInput(Container $$0) { + throw new UntransformedInvokerError(); } - @Override - public DataFixer buildOptimized(final Set requiredTypes, final Executor executor) { - return super.buildOptimized(requiredTypes, NO_OP_EXECUTOR); - - } } diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/AbstractFurnaceBlockEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/AbstractFurnaceBlockEntityAccessor.java index 0329ad357b9..2ec3b5a53e5 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/AbstractFurnaceBlockEntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/AbstractFurnaceBlockEntityAccessor.java @@ -24,9 +24,9 @@ */ package org.spongepowered.common.accessor.world.level.block.entity; -import net.minecraft.world.Container; import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -50,6 +50,6 @@ public interface AbstractFurnaceBlockEntityAccessor { @Accessor("cookingTotalTime") void accessor$cookingTotalTime(final int cookingTotalTime); - @Accessor("quickCheck") RecipeManager.CachedCheck accessor$quickCheck(); + @Accessor("quickCheck") RecipeManager.CachedCheck accessor$quickCheck(); } diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index d3c3064e29a..1ba75a1b31d 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -1,144 +1,145 @@ { - "required": true, - "parent": "mixins.sponge.parent.json", - "package": "org.spongepowered.common.accessor", - "client": [ - "client.KeyMappingAccessor", - "client.multiplayer.ClientLevelAccessor", - "world.level.entity.TransientEntitySectionManagerAccessor" - ], - "mixins": [ - "ChatFormattingAccessor", - "advancements.CriteriaTriggersAccessor", - "advancements.critereon.MinMaxBounds_DoublesAccessor", - "advancements.critereon.MinMaxBounds_IntsAccessor", - "commands.CommandSourceStackAccessor", - "commands.arguments.DimensionArgumentAccessor", - "commands.arguments.OperationArgumentAccessor", - "commands.arguments.selector.EntitySelectorParserAccessor", - "commands.arguments.selector.options.EntitySelectorOptions_OptionAccessor", - "commands.arguments.selector.options.EntitySelectorOptionsAccessor", - "core.MappedRegistryAccessor", - "entity.passive.AbstractChestedHorseEntityAccessor", - "network.ConnectionAccessor", - "network.chat.HoverEvent_ItemStackInfoAccessor", - "network.chat.StyleAccessor", - "network.protocol.game.ClientboundAddEntityPacketAccessor", - "network.protocol.game.ClientboundPlayerInfoUpdatePacketAccessor", - "network.protocol.game.ServerboundInteractPacket_InteractionActionAccessor", - "network.protocol.game.ServerboundInteractPacket_InteractionAtLocationActionAccessor", - "network.protocol.game.ServerboundInteractPacketAccessor", - "network.protocol.game.ServerboundMovePlayerPacketAccessor", - "network.protocol.game.ServerboundMoveVehiclePacketAccessor", - "network.protocol.handshake.ClientIntentionPacketAccessor", - "resources.ResourceKeyAccessor", - "server.MinecraftServerAccessor", - "server.level.ChunkMap_TrackedEntityAccessor", - "server.level.ChunkMapAccessor", - "server.level.ServerChunkCacheAccessor", - "server.level.ServerLevelAccessor", - "server.level.ServerPlayer_ContainerListenerAccessor", - "server.level.ServerPlayerAccessor", - "server.level.ServerPlayerGameModeAccessor", - "server.level.TicketAccessor", - "server.level.TicketTypeAccessor", - "server.network.ServerCommonPacketListenerImplAccessor", - "server.network.ServerGamePacketListenerImplAccessor", - "server.network.ServerLoginPacketListenerImplAccessor", - "server.players.GameProfileCache_GameProfileInfoAccessor", - "server.players.IpBanListAccessor", - "server.players.PlayerListAccessor", - "server.players.StoredUserEntryAccessor", - "server.players.StoredUserListAccessor", - "server.rcon.thread.RconClientAccessor", - "sounds.SoundEventAccessor", - "stats.StatsCounterAccessor", - "util.datafix.schemas.V100Accessor", - "world.CompoundContainerAccessor", - "world.damagesource.CombatTrackerAccessor", - "world.entity.AgableMobAccessor", - "world.entity.AreaEffectCloudAccessor", - "world.entity.Display_BlockDisplayAccessor", - "world.entity.Display_ItemDisplayAccessor", - "world.entity.Display_TextDisplayAccessor", - "world.entity.DisplayAccessor", - "world.entity.EntityAccessor", - "world.entity.EntityTypeAccessor", - "world.entity.ExperienceOrbAccessor", - "world.entity.LightningBoltAccessor", - "world.entity.LivingEntityAccessor", - "world.entity.MobAccessor", + "required": true, + "parent": "mixins.sponge.parent.json", + "package": "org.spongepowered.common.accessor", + "client": [ + "client.KeyMappingAccessor", + "client.multiplayer.ClientLevelAccessor", + "world.level.entity.TransientEntitySectionManagerAccessor" + ], + "mixins": [ + "ChatFormattingAccessor", + "advancements.CriteriaTriggersAccessor", + "advancements.critereon.MinMaxBounds_DoublesAccessor", + "advancements.critereon.MinMaxBounds_IntsAccessor", + "commands.CommandSourceStackAccessor", + "commands.arguments.DimensionArgumentAccessor", + "commands.arguments.OperationArgumentAccessor", + "commands.arguments.selector.EntitySelectorParserAccessor", + "commands.arguments.selector.options.EntitySelectorOptions_OptionAccessor", + "commands.arguments.selector.options.EntitySelectorOptionsAccessor", + "core.MappedRegistryAccessor", + "entity.passive.AbstractChestedHorseEntityAccessor", + "network.ConnectionAccessor", + "network.chat.HoverEvent_ItemStackInfoAccessor", + "network.chat.StyleAccessor", + "network.protocol.game.ClientboundAddEntityPacketAccessor", + "network.protocol.game.ClientboundPlayerInfoUpdatePacketAccessor", + "network.protocol.game.ServerboundInteractPacket_InteractionActionAccessor", + "network.protocol.game.ServerboundInteractPacket_InteractionAtLocationActionAccessor", + "network.protocol.game.ServerboundInteractPacketAccessor", + "network.protocol.game.ServerboundMovePlayerPacketAccessor", + "network.protocol.game.ServerboundMoveVehiclePacketAccessor", + "network.protocol.handshake.ClientIntentionPacketAccessor", + "resources.ResourceKeyAccessor", + "server.MinecraftServerAccessor", + "server.level.ChunkMap_TrackedEntityAccessor", + "server.level.ChunkMapAccessor", + "server.level.ServerChunkCacheAccessor", + "server.level.ServerLevelAccessor", + "server.level.ServerPlayer_ContainerListenerAccessor", + "server.level.ServerPlayerAccessor", + "server.level.ServerPlayerGameModeAccessor", + "server.level.TicketAccessor", + "server.level.TicketTypeAccessor", + "server.network.ServerCommonPacketListenerImplAccessor", + "server.network.ServerGamePacketListenerImplAccessor", + "server.network.ServerLoginPacketListenerImplAccessor", + "server.players.GameProfileCache_GameProfileInfoAccessor", + "server.players.IpBanListAccessor", + "server.players.PlayerListAccessor", + "server.players.StoredUserEntryAccessor", + "server.players.StoredUserListAccessor", + "server.rcon.thread.RconClientAccessor", + "sounds.SoundEventAccessor", + "stats.StatsCounterAccessor", + "util.datafix.schemas.V100Accessor", + "world.CompoundContainerAccessor", + "world.damagesource.CombatTrackerAccessor", + "world.entity.AgableMobAccessor", + "world.entity.AreaEffectCloudAccessor", + "world.entity.Display_BlockDisplayAccessor", + "world.entity.Display_ItemDisplayAccessor", + "world.entity.Display_TextDisplayAccessor", + "world.entity.DisplayAccessor", + "world.entity.EntityAccessor", + "world.entity.EntityTypeAccessor", + "world.entity.ExperienceOrbAccessor", + "world.entity.LightningBoltAccessor", + "world.entity.LivingEntityAccessor", + "world.entity.MobAccessor", "world.entity.PortalProcessorAccessor", - "world.entity.ai.targeting.TargetingConditionsAccessor", - "world.entity.animal.AnimalAccessor", - "world.entity.animal.CatAccessor", - "world.entity.animal.FoxAccessor", - "world.entity.animal.MushroomCow_MushroomTypeAccessor", - "world.entity.animal.OcelotAccessor", - "world.entity.animal.PandaAccessor", - "world.entity.animal.PigAccessor", - "world.entity.animal.PufferfishAccessor", - "world.entity.animal.SheepAccessor", - "world.entity.animal.TropicalFishAccessor", - "world.entity.animal.TurtleAccessor", - "world.entity.animal.WolfAccessor", - "world.entity.animal.horse.HorseAccessor", - "world.entity.animal.horse.LlamaAccessor", - "world.entity.animal.horse.TraderLlamaAccessor", - "world.entity.boss.enderdragon.phases.EnderDragonPhaseAccessor", - "world.entity.boss.wither.WitherBossAccessor", - "world.entity.decoration.ArmorStandAccessor", - "world.entity.decoration.HangingEntityAccessor", - "world.entity.decoration.ItemFrameAccessor", - "world.entity.item.FallingBlockEntityAccessor", - "world.entity.item.PrimedTntAccessor", - "world.entity.monster.BlazeAccessor", - "world.entity.monster.CreeperAccessor", - "world.entity.monster.EnderManAccessor", - "world.entity.monster.EndermiteAccessor", - "world.entity.monster.EvokerAccessor", - "world.entity.monster.GuardianAccessor", - "world.entity.monster.PatrollingMonsterAccessor", - "world.entity.monster.PhantomAccessor", - "world.entity.monster.PillagerAccessor", - "world.entity.monster.RavagerAccessor", - "world.entity.monster.SlimeAccessor", - "world.entity.monster.SpellcasterIllagerAccessor", - "world.entity.monster.VexAccessor", - "world.entity.monster.VindicatorAccessor", - "world.entity.monster.ZombifiedPiglinAccessor", - "world.entity.npc.AbstractVillagerAccessor", - "world.entity.player.AbilitiesAccessor", - "world.entity.player.PlayerAccessor", + "world.entity.ai.targeting.TargetingConditionsAccessor", + "world.entity.animal.AnimalAccessor", + "world.entity.animal.CatAccessor", + "world.entity.animal.FoxAccessor", + "world.entity.animal.MushroomCow_MushroomTypeAccessor", + "world.entity.animal.OcelotAccessor", + "world.entity.animal.PandaAccessor", + "world.entity.animal.PigAccessor", + "world.entity.animal.PufferfishAccessor", + "world.entity.animal.SheepAccessor", + "world.entity.animal.TropicalFishAccessor", + "world.entity.animal.TurtleAccessor", + "world.entity.animal.WolfAccessor", + "world.entity.animal.horse.HorseAccessor", + "world.entity.animal.horse.LlamaAccessor", + "world.entity.animal.horse.TraderLlamaAccessor", + "world.entity.boss.enderdragon.phases.EnderDragonPhaseAccessor", + "world.entity.boss.wither.WitherBossAccessor", + "world.entity.decoration.ArmorStandAccessor", + "world.entity.decoration.HangingEntityAccessor", + "world.entity.decoration.ItemFrameAccessor", + "world.entity.item.FallingBlockEntityAccessor", + "world.entity.item.PrimedTntAccessor", + "world.entity.monster.BlazeAccessor", + "world.entity.monster.CreeperAccessor", + "world.entity.monster.EnderManAccessor", + "world.entity.monster.EndermiteAccessor", + "world.entity.monster.EvokerAccessor", + "world.entity.monster.GuardianAccessor", + "world.entity.monster.PatrollingMonsterAccessor", + "world.entity.monster.PhantomAccessor", + "world.entity.monster.PillagerAccessor", + "world.entity.monster.RavagerAccessor", + "world.entity.monster.SlimeAccessor", + "world.entity.monster.SpellcasterIllagerAccessor", + "world.entity.monster.VexAccessor", + "world.entity.monster.VindicatorAccessor", + "world.entity.monster.ZombifiedPiglinAccessor", + "world.entity.npc.AbstractVillagerAccessor", + "world.entity.player.AbilitiesAccessor", + "world.entity.player.PlayerAccessor", "world.entity.projectile.AbstractArrowAccessor", - "world.entity.projectile.ArrowAccessor", - "world.entity.projectile.EyeOfEnderAccessor", - "world.entity.projectile.FireworkRocketEntityAccessor", - "world.entity.projectile.FishingHookAccessor", - "world.entity.projectile.ProjectileAccessor", - "world.entity.projectile.ShulkerBulletAccessor", - "world.entity.raid.RaidAccessor", - "world.entity.raid.RaiderAccessor", - "world.entity.raid.RaidsAccessor", - "world.entity.vehicle.BoatAccessor", - "world.entity.vehicle.MinecartFurnaceAccessor", - "world.food.FoodDataAccessor", - "world.inventory.AbstractContainerMenuAccessor", - "world.inventory.AbstractFurnaceMenuAccessor", - "world.inventory.BeaconMenuAccessor", - "world.inventory.BrewingStandMenuAccessor", - "world.inventory.CraftingMenuAccessor", - "world.inventory.DispenserMenuAccessor", - "world.inventory.HopperMenuAccessor", - "world.inventory.HorseInventoryMenuAccessor", - "world.inventory.InventoryMenuAccessor", - "world.inventory.ItemCombinerMenuAccessor", - "world.inventory.MerchantMenuAccessor", - "world.inventory.ResultSlotAccessor", - "world.inventory.SlotAccessor", + "world.entity.projectile.ArrowAccessor", + "world.entity.projectile.EyeOfEnderAccessor", + "world.entity.projectile.FireworkRocketEntityAccessor", + "world.entity.projectile.FishingHookAccessor", + "world.entity.projectile.ProjectileAccessor", + "world.entity.projectile.ShulkerBulletAccessor", + "world.entity.raid.RaidAccessor", + "world.entity.raid.RaiderAccessor", + "world.entity.raid.RaidsAccessor", + "world.entity.vehicle.BoatAccessor", + "world.entity.vehicle.MinecartFurnaceAccessor", + "world.food.FoodDataAccessor", + "world.inventory.AbstractContainerMenuAccessor", + "world.inventory.AbstractFurnaceMenuAccessor", + "world.inventory.BeaconMenuAccessor", + "world.inventory.BrewingStandMenuAccessor", + "world.inventory.CraftingMenuAccessor", + "world.inventory.DispenserMenuAccessor", + "world.inventory.HopperMenuAccessor", + "world.inventory.HorseInventoryMenuAccessor", + "world.inventory.ItemCombinerMenuAccessor", + "world.inventory.MerchantMenuAccessor", + "world.inventory.ResultSlotAccessor", + "world.inventory.SlotAccessor", + "world.inventory.SmithingMenuAccessor", + "world.inventory.StonecutterMenuAccessor", "world.item.AdventureModePredicateAccessor", "world.item.ItemCooldowns_CooldownInstanceAccessor", - "world.item.component.CustomDataAccessor", + "world.item.component.CustomDataAccessor", "world.item.enchantment.ItemEnchantmentsAccessor", "world.item.trading.MerchantOfferAccessor", "world.level.BaseCommandBlockAccessor", diff --git a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java index 1aeb63341bb..aabee127c9f 100644 --- a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java +++ b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java @@ -99,7 +99,7 @@ public static final class FactoryImpl implements DataPackType.Factory { true); private final SpongeDataPackType recipe = SpongeDataPackType.custom(RecipeRegistration.class, - "recipes", new RecipeDataPackSerializer(SpongeRecipeRegistration::encode, null), // TODO decoder + "recipe", new RecipeDataPackSerializer(SpongeRecipeRegistration::encode, null), // TODO decoder true); private final SpongeDataPackType worldType = SpongeDataPackType.basic(WorldTypeTemplate.class, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ContainerBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ContainerBasedTransaction.java index a1eb7262b8d..52811cbb503 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ContainerBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ContainerBasedTransaction.java @@ -288,7 +288,7 @@ private void handleCraftingPreview(final Player player, final ClickContainerEven // TODO push event to cause? // TODO prevent event when there is no preview? final SlotTransaction previewTransaction = this.getPreviewTransaction(this.craftingInventory.result(), event.transactions()); - final var recipe = player.level().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, this.craftingContainer, player.level()); + final var recipe = player.level().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, this.craftingContainer.asCraftInput(), player.level()); final CraftItemEvent.Preview previewEvent = SpongeEventFactory.createCraftItemEventPreview(event.cause(), (Container) this.menu, this.craftingInventory, event.cursorTransaction(), previewTransaction, recipe.map(RecipeHolder::value).map(CraftingRecipe.class::cast), recipe.map(h -> h.id()).map(ResourceKey.class::cast), Optional.empty(), event.transactions()); SpongeCommon.post(previewEvent); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CraftingPreviewTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CraftingPreviewTransaction.java index f6ce13279ff..2fb3bf724e7 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CraftingPreviewTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CraftingPreviewTransaction.java @@ -76,7 +76,7 @@ Optional createInventoryEvent(final List s } final ItemStackSnapshot cursor = ItemStackUtil.snapshotOf(this.player.containerMenu.getCarried()); final SlotTransaction previewTransaction = this.getPreviewTransaction(this.craftingInventory.result(), slotTransactions); - final var recipe = this.player.level().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, this.craftSlots, this.player.level()); + final var recipe = this.player.level().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, this.craftSlots.asCraftInput(), this.player.level()); final CraftItemEvent.Preview event = SpongeEventFactory.createCraftItemEventPreview(currentCause, ContainerUtil.fromNative(this.menu), this.craftingInventory, new Transaction<>(cursor, cursor), previewTransaction, recipe.map(RecipeHolder::value).map(CraftingRecipe.class::cast), diff --git a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java index 23b0461ecdd..4d04c948206 100644 --- a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java +++ b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java @@ -388,9 +388,10 @@ public static Map containerTypeInfo() { // horse is used for distance to player // checking HorseArmor Item in Slot // chested State and capacity (hasChest/getInventoryColumns) to add more Slots + int chestColumns = 0; AbstractHorse horse = null; ContainerTypeInfo.of(0, 0, - (id, i, p, vi) -> new HorseInventoryMenu(id, i, vi, horse)); + (id, i, p, vi) -> new HorseInventoryMenu(id, i, vi, horse, chestColumns)); return SpongeViewableInventoryBuilder.containerTypeInfo; } diff --git a/src/main/java/org/spongepowered/common/inventory/fabric/IInventoryTranslator.java b/src/main/java/org/spongepowered/common/inventory/fabric/ContainerTranslator.java similarity index 97% rename from src/main/java/org/spongepowered/common/inventory/fabric/IInventoryTranslator.java rename to src/main/java/org/spongepowered/common/inventory/fabric/ContainerTranslator.java index 0bfa1338f2d..2e3272f83b0 100644 --- a/src/main/java/org/spongepowered/common/inventory/fabric/IInventoryTranslator.java +++ b/src/main/java/org/spongepowered/common/inventory/fabric/ContainerTranslator.java @@ -34,7 +34,7 @@ /** * Provides {@link Fabric} access to an {@link Container} */ -class IInventoryTranslator implements InventoryTranslator { +class ContainerTranslator implements InventoryTranslator { @Override public Collection allInventories(Container inventory) { return ImmutableSet.of((InventoryBridge) inventory); diff --git a/src/main/java/org/spongepowered/common/inventory/fabric/InventoryTranslators.java b/src/main/java/org/spongepowered/common/inventory/fabric/InventoryTranslators.java index 5e470e5d55f..4838e115c92 100644 --- a/src/main/java/org/spongepowered/common/inventory/fabric/InventoryTranslators.java +++ b/src/main/java/org/spongepowered/common/inventory/fabric/InventoryTranslators.java @@ -25,6 +25,7 @@ package org.spongepowered.common.inventory.fabric; import net.minecraft.world.Container; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import java.util.HashMap; import java.util.Map; @@ -33,7 +34,8 @@ public class InventoryTranslators { private static final Map, InventoryTranslator> fabricTranslators = new HashMap<>(); static { - InventoryTranslators.register(Container.class, new IInventoryTranslator()); + InventoryTranslators.register(Container.class, new ContainerTranslator()); + InventoryTranslators.register(RecipeInput.class, new RecipeInputTranslator()); } public static void register(Class inventoryInterface, InventoryTranslator translator) { diff --git a/src/main/java/org/spongepowered/common/inventory/fabric/RecipeInputTranslator.java b/src/main/java/org/spongepowered/common/inventory/fabric/RecipeInputTranslator.java new file mode 100644 index 00000000000..e97ba5a3e52 --- /dev/null +++ b/src/main/java/org/spongepowered/common/inventory/fabric/RecipeInputTranslator.java @@ -0,0 +1,78 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.inventory.fabric; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeInput; +import org.spongepowered.common.bridge.world.inventory.InventoryBridge; + +import java.util.Collection; + +/** + * Provides {@link Fabric} access to an {@link RecipeInput} + */ +class RecipeInputTranslator implements InventoryTranslator { + @Override + public Collection allInventories(RecipeInput inventory) { + return ImmutableSet.of((InventoryBridge) inventory); + } + + @Override + @SuppressWarnings("unchecked") + public InventoryBridge get(RecipeInput inventory, int index) { + return (InventoryBridge) inventory; + } + + @Override + public ItemStack getStack(RecipeInput inventory, int index) { + return inventory.getItem(index); + } + + @Override + public void setStack(RecipeInput inventory, int index, ItemStack stack) { + throw new UnsupportedOperationException("setStack is not supported"); + } + + @Override + public int getMaxStackSize(RecipeInput inventory) { + return 64; // TODO detach max stack size from inventory + } + + @Override + public int getSize(RecipeInput inventory) { + return inventory.size(); + } + + @Override + public void clear(RecipeInput inventory) { + throw new UnsupportedOperationException("clear is not supported"); + } + + @Override + public void markDirty(RecipeInput inventory) { + throw new UnsupportedOperationException("markDirty is not supported"); + } +} diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java index 175127b62e3..0af32460cec 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java @@ -25,7 +25,7 @@ package org.spongepowered.common.inventory.lens.impl.slot; import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.Equipable; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.equipment.EquipmentType; @@ -52,7 +52,8 @@ private static FilteringSlotLens.ItemStackFilter equipmentTypeFilter(EquipmentTy if (item.isEmpty()) { return true; } - final EquipmentSlot itemSlotType = Mob.getEquipmentSlotForItem(ItemStackUtil.toNative(item)); + final var equipable = Equipable.get(ItemStackUtil.toNative(item)); + final var itemSlotType = equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND; return itemSlotType == (Object) type; }; } diff --git a/src/main/java/org/spongepowered/common/inventory/util/InventoryUtil.java b/src/main/java/org/spongepowered/common/inventory/util/InventoryUtil.java index 7292a40e97a..b6c489f060c 100644 --- a/src/main/java/org/spongepowered/common/inventory/util/InventoryUtil.java +++ b/src/main/java/org/spongepowered/common/inventory/util/InventoryUtil.java @@ -28,7 +28,14 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.StonecutterMenu; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.world.level.block.entity.CampfireBlockEntity; import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.level.block.state.properties.ChestType; import org.checkerframework.checker.nullness.qual.Nullable; @@ -38,12 +45,15 @@ import org.spongepowered.api.block.entity.carrier.chest.Chest; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.item.inventory.Carrier; -import org.spongepowered.api.item.inventory.Container; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.inventory.type.CarriedInventory; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.accessor.world.inventory.CraftingMenuAccessor; +import org.spongepowered.common.accessor.world.inventory.SmithingMenuAccessor; +import org.spongepowered.common.accessor.world.inventory.StonecutterMenuAccessor; import org.spongepowered.common.bridge.world.inventory.container.TrackedInventoryBridge; import org.spongepowered.common.entity.player.SpongeUserData; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; @@ -68,21 +78,37 @@ public static CraftingGridInventory toSpongeInventory(final CraftingContainer in return (CraftingGridInventory) inv; } + public static RecipeInput.Crafting toSponge(final CraftingInput input) { + return (RecipeInput.Crafting) input; + } + + public static RecipeInput.Smithing toSponge(final SmithingRecipeInput input) { + return (RecipeInput.Smithing) (Object) input; + } + + public static RecipeInput.Single toSponge(final SingleRecipeInput input) { + return (RecipeInput.Single) (Object) input; + } + + @SuppressWarnings("unchecked") - public static C toNativeInventory(final Inventory inv) { - if (inv instanceof CraftingContainer) { - return (C) inv; - } - if (inv instanceof Container) { - for (final Object inventory : ((InventoryAdapter) inv).inventoryAdapter$getFabric().fabric$allInventories()) { - if (inventory instanceof CraftingContainer) { - return (C) inventory; - } - } - } + public static Optional toCraftingInput(final Inventory inv) { + final var recipeInput = switch (inv) { + case AbstractFurnaceBlockEntity furnace -> new SingleRecipeInput(furnace.getItem(0)); + case CampfireBlockEntity campfire -> campfire.getItems().stream().filter(stack -> !stack.isEmpty()).findFirst() + .map(SingleRecipeInput::new).orElse(null); + case CraftingMenuAccessor menu -> menu.accessor$craftSlots().asCraftInput(); + case InventoryMenu menu -> menu.getCraftSlots().asCraftInput(); + case StonecutterMenu menu -> StonecutterMenuAccessor.invoker$createRecipeInput(menu.container); + case SmithingMenuAccessor menu -> menu.invoker$createRecipeInput(); + default -> null; + }; + return Optional.ofNullable((I) recipeInput); + } - // Gather Debug Info... - throw new IllegalStateException("Invalid CraftingGridInventory. Could not find CraftingInventory.\nInventory was: " + inv.getClass().getSimpleName()); + @SuppressWarnings("unchecked") + public static I toCraftingInputOrThrow(final Inventory inv) { + return (I) toCraftingInput(inv).orElseThrow(() -> new IllegalStateException("Invalid CraftingGridInventory. Could not find CraftingInventory.\nInventory was: " + inv.getClass().getSimpleName())); } public static Optional getDoubleChestInventory(final ChestBlockEntity chest) { diff --git a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java new file mode 100644 index 00000000000..0f591977d30 --- /dev/null +++ b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java @@ -0,0 +1,53 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.item.recipe; + +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.item.crafting.SmithingRecipeInput; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.Slot; +import org.spongepowered.api.item.inventory.type.GridInventory; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.common.item.util.ItemStackUtil; + +public final class SpongeRecipeInputFactory implements RecipeInput.Factory { + + @Override + public RecipeInput.Single single(final ItemStack stack) { + return (RecipeInput.Single) (Object) new SingleRecipeInput(ItemStackUtil.toNative(stack)); + } + + @Override + public RecipeInput.Smithing smithing(final ItemStack template, final ItemStack base, final ItemStack addtion) { + return (RecipeInput.Smithing) (Object) new SmithingRecipeInput(ItemStackUtil.toNative(template), ItemStackUtil.toNative(base), ItemStackUtil.toNative(addtion)); + } + + @Override + public RecipeInput.Crafting crafting(final GridInventory grid) { + final var list = grid.slots().stream().map(Slot::peek).map(ItemStackUtil::toNative).toList(); + return (RecipeInput.Crafting) CraftingInput.of(grid.columns(), grid.rows(), list); + } +} diff --git a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java index 23991b0a0f3..ea711e4797e 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java @@ -37,10 +37,10 @@ import net.minecraft.core.RegistryAccess; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.item.crafting.RecipeSerializer; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.data.persistence.DataContainer; @@ -54,7 +54,7 @@ import java.util.Collection; import java.util.function.Function; -public abstract class SpongeRecipeRegistration> implements RecipeRegistration { +public abstract class SpongeRecipeRegistration> implements RecipeRegistration { private static final Gson GSON = new Gson(); @@ -77,8 +77,8 @@ public SpongeRecipeRegistration(final ResourceLocation key, this.group = group == null ? "" : group; } - public static , C extends Container> RecipeSerializer determineSerializer(final ItemStack resultStack, - final Function resultFunction, + public static , I extends RecipeInput> RecipeSerializer determineSerializer(final ItemStack resultStack, + final Function resultFunction, final Function> remainingItemsFunction, final Collection ingredients, final RecipeSerializer vanilla, final RecipeSerializer sponge) { @@ -93,9 +93,9 @@ public static , C extends Container> RecipeSerializer boolean isVanillaSerializer(final ItemStack resultStack, - final Function resultFunction, - final Function> remainingItemsFunction, + public static boolean isVanillaSerializer(final ItemStack resultStack, + final Function resultFunction, + final Function> remainingItemsFunction, final Collection ingredients) { if (!resultStack.getComponents().isEmpty() || resultFunction != null || remainingItemsFunction != null) { return false; @@ -163,13 +163,13 @@ public static JsonObject encode(RecipeRegistration template, RegistryAccess acce } } - public interface ResultFunctionRegistration { + public interface ResultFunctionRegistration { - Function resultFunction(); + Function resultFunction(); } - public interface RemainingItemsFunctionRegistration { + public interface RemainingItemsFunctionRegistration { - Function> remainingItems(); + Function> remainingItems(); } } diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeBlastingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeBlastingRecipe.java index d7b377823a9..6675d43b475 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeBlastingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeBlastingRecipe.java @@ -25,11 +25,11 @@ package org.spongepowered.common.item.recipe.cooking; import net.minecraft.core.HolderLookup; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.BlastingRecipe; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import org.spongepowered.common.item.recipe.ResultFunctionRecipe; import org.spongepowered.common.item.recipe.ingredient.IngredientResultUtil; @@ -50,13 +50,13 @@ public Optional resultFunctionId() { } @Override - public ItemStack assemble(final Container container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final SingleRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); result.setCount(1); return result; } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCampfireCookingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCampfireCookingRecipe.java index 9deec819dfb..ecce010f0ab 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCampfireCookingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCampfireCookingRecipe.java @@ -25,11 +25,11 @@ package org.spongepowered.common.item.recipe.cooking; import net.minecraft.core.HolderLookup; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CampfireCookingRecipe; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import org.spongepowered.common.item.recipe.ResultFunctionRecipe; import org.spongepowered.common.item.recipe.ingredient.IngredientResultUtil; @@ -50,13 +50,13 @@ public Optional resultFunctionId() { } @Override - public ItemStack assemble(final Container container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final SingleRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); result.setCount(1); return result; } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java index efcbd0b99b1..ba328b162e8 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java @@ -26,20 +26,20 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.RecipeType; import org.spongepowered.api.item.recipe.cooking.CookingRecipe; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.util.Ticks; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.util.ItemStackUtil; @@ -54,7 +54,7 @@ public final class SpongeCookingRecipeBuilder extends AbstractResourceKeyedBuild private net.minecraft.world.item.crafting.RecipeType type; private Ingredient ingredient; private ItemStack result; - private Function resultFunction; + private Function resultFunction; private @Nullable Float experience; private @Nullable Ticks cookingTime; @@ -104,9 +104,9 @@ public EndStep result(final ItemStackSnapshot result) { } // currently unused - public EndStep result(final Function resultFunction, final org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { + public EndStep result(final Function resultFunction, final org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { this.result = ItemStackUtil.toNative(exemplaryResult); - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toInventory(inv))); + this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeRegistration.java index 88378c39f15..040c5be9642 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeRegistration.java @@ -26,7 +26,6 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.BlastingRecipe; @@ -35,6 +34,7 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.SmeltingRecipe; import net.minecraft.world.item.crafting.SmokingRecipe; import org.checkerframework.checker.nullness.qual.Nullable; @@ -50,7 +50,7 @@ import java.util.List; import java.util.function.Function; -public class SpongeCookingRecipeRegistration extends SpongeRecipeRegistration implements SpongeRecipeRegistration.ResultFunctionRegistration{ +public class SpongeCookingRecipeRegistration extends SpongeRecipeRegistration implements SpongeRecipeRegistration.ResultFunctionRegistration{ // Vanilla Recipe private final Ingredient ingredient; @@ -59,13 +59,13 @@ public class SpongeCookingRecipeRegistration extends SpongeRecipeRegistration resultFunction; + private final Function resultFunction; private final RecipeType type; private final CookingBookCategory cookingCategory; public SpongeCookingRecipeRegistration(final ResourceLocation key, final RecipeType type, final RecipeSerializer serializer, final String group, final Ingredient ingredient, final float experience, final Ticks cookingTime, - final ItemStack spongeResult, final Function resultFunction, + final ItemStack spongeResult, final Function resultFunction, final DataPack pack, final RecipeCategory category, final CookingBookCategory cookingCategory) { super(key, group, pack, category, serializer); this.type = type; @@ -79,7 +79,7 @@ public SpongeCookingRecipeRegistration(final ResourceLocation key, final RecipeT public static SpongeCookingRecipeRegistration of(final ResourceLocation key, final RecipeType type, final @Nullable String group, final Ingredient ingredient, final Float experience, final @Nullable Ticks cookingTime, final ItemStack result, - final Function resultFunction, final DataPack pack, final RecipeCategory recipeCategory, final CookingBookCategory cookingCategory) + final Function resultFunction, final DataPack pack, final RecipeCategory recipeCategory, final CookingBookCategory cookingCategory) { var finalCookingTime = cookingTime; @@ -151,7 +151,7 @@ public Recipe recipe() { } @Override - public Function resultFunction() { + public Function resultFunction() { return this.resultFunction; } } diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmeltingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmeltingRecipe.java index 9dec90b4c4e..13e51a37ac7 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmeltingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmeltingRecipe.java @@ -25,10 +25,10 @@ package org.spongepowered.common.item.recipe.cooking; import net.minecraft.core.HolderLookup; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.SmeltingRecipe; import org.spongepowered.common.item.recipe.ResultFunctionRecipe; import org.spongepowered.common.item.recipe.ingredient.IngredientResultUtil; @@ -49,15 +49,14 @@ public Optional resultFunctionId() { return Optional.ofNullable(this.resultFunctionId); } - @Override - public ItemStack assemble(final Container container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final SingleRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); result.setCount(1); return result; } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmokingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmokingRecipe.java index 26e4492f5d8..5397cad2138 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmokingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeSmokingRecipe.java @@ -25,10 +25,10 @@ package org.spongepowered.common.item.recipe.cooking; import net.minecraft.core.HolderLookup; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.SmokingRecipe; import org.spongepowered.common.item.recipe.ResultFunctionRecipe; import org.spongepowered.common.item.recipe.ingredient.IngredientResultUtil; @@ -49,15 +49,14 @@ public Optional resultFunctionId() { return Optional.ofNullable(this.resultFunctionId); } - @Override - public ItemStack assemble(final Container container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final SingleRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + final ItemStack result = IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); result.setCount(1); return result; } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java index 37ac1c3da3c..0fc65ff976c 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java @@ -30,8 +30,8 @@ import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.recipe.RecipeRegistration; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.SpecialCraftingRecipe; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.common.util.AbstractResourceKeyedBuilder; @@ -43,27 +43,27 @@ public final class SpongeSpecialCraftingRecipeBuilder extends AbstractResourceKeyedBuilder implements SpecialCraftingRecipe.Builder, SpecialCraftingRecipe.Builder.ResultStep, SpecialCraftingRecipe.Builder.EndStep { - private BiPredicate biPredicate; - private Function> remainingItemsFunction; - private Function resultFunction; + private BiPredicate biPredicate; + private Function> remainingItemsFunction; + private Function resultFunction; private DataPack pack = DataPacks.RECIPE; private RecipeCategory recipeCategory = RecipeCategory.MISC; // TODO support category @Override - public ResultStep matching(BiPredicate biPredicate) { + public ResultStep matching(BiPredicate biPredicate) { this.biPredicate = biPredicate; return this; } @Override - public ResultStep remainingItems(Function> remainingItemsFunction) { + public ResultStep remainingItems(Function> remainingItemsFunction) { this.remainingItemsFunction = remainingItemsFunction; return this; } @Override - public EndStep result(Function resultFunction) { + public EndStep result(Function resultFunction) { this.resultFunction = resultFunction; return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeRegistration.java index a5adcc426e0..27a73748ed3 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeRegistration.java @@ -29,9 +29,9 @@ import net.minecraft.world.item.crafting.CraftingBookCategory; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.recipe.Recipe; import org.spongepowered.api.item.recipe.RecipeRegistration; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.SpecialCraftingRecipe; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.common.item.recipe.SpongeRecipeRegistration; @@ -46,17 +46,17 @@ public class SpongeSpecialCraftingRecipeRegistration extends SpongeRecipeRegistr public static final Map RECIPES = new HashMap<>(); - private final BiPredicate biPredicate; - private final Function> remainingItemsFunction; - private final Function resultFunction; + private final BiPredicate biPredicate; + private final Function> remainingItemsFunction; + private final Function resultFunction; private final SpongeSpecialRecipe recipe; public SpongeSpecialCraftingRecipeRegistration(ResourceLocation key, final CraftingBookCategory category, - BiPredicate biPredicate, - Function> remainingItemsFunction, - Function resultFunction, + BiPredicate biPredicate, + Function> remainingItemsFunction, + Function resultFunction, DataPack pack, final RecipeCategory recipeCategory) { super(key, "", pack, recipeCategory, null); @@ -69,9 +69,8 @@ public SpongeSpecialCraftingRecipeRegistration(ResourceLocation key, } public static SpongeSpecialRecipe get(final String id, final CraftingBookCategory category) { - // TODO: category? return SpongeSpecialCraftingRecipeRegistration.RECIPES.getOrDefault(id, - new SpongeSpecialRecipe(ResourceLocation.tryParse(id), CraftingBookCategory.MISC, (x, y) -> false, null, null)); + new SpongeSpecialRecipe(ResourceLocation.tryParse(id), category, (x, y) -> false, null, null)); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialRecipe.java index 8bc472781da..09531ed46b4 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialRecipe.java @@ -24,21 +24,25 @@ */ package org.spongepowered.common.item.recipe.crafting.custom; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.util.ItemStackUtil; +import org.spongepowered.common.util.Constants; import org.spongepowered.common.util.MissingImplementationException; import java.util.List; @@ -47,16 +51,24 @@ public final class SpongeSpecialRecipe extends CustomRecipe { + public static final MapCodec SPONGE_CODEC = RecordCodecBuilder.mapCodec( + $$0 -> $$0.group( + Codec.STRING.fieldOf(Constants.Recipe.SPONGE_TYPE).forGetter(SpongeSpecialRecipe::id), // important to fail early when decoding vanilla recipes + CraftingBookCategory.CODEC.fieldOf(Constants.Recipe.CATEGORY).orElse(CraftingBookCategory.MISC).forGetter(SpongeSpecialRecipe::category) + ) + .apply($$0, SpongeSpecialCraftingRecipeRegistration::get) + ); + private final String id; - private final BiPredicate biPredicate; - private final Function> remainingItemsFunction; - private final Function resultFunction; + private final BiPredicate biPredicate; + private final Function> remainingItemsFunction; + private final Function resultFunction; public SpongeSpecialRecipe(ResourceLocation key, CraftingBookCategory category, - BiPredicate biPredicate, - Function> remainingItemsFunction, - Function resultFunction) { + BiPredicate biPredicate, + Function> remainingItemsFunction, + Function resultFunction) { super(category); this.id = key.toString(); this.biPredicate = biPredicate; @@ -68,14 +80,15 @@ public String id() { return id; } + @Override - public boolean matches(CraftingContainer inv, Level worldIn) { - return this.biPredicate.test(InventoryUtil.toSpongeInventory(inv), (ServerWorld) worldIn); + public boolean matches(final CraftingInput input, final Level level) { + return this.biPredicate.test(InventoryUtil.toSponge(input), (ServerWorld) level); } @Override - public ItemStack assemble(final CraftingContainer inv, final HolderLookup.Provider $$1) { - return ItemStackUtil.toNative(this.resultFunction.apply(InventoryUtil.toSpongeInventory(inv))); + public ItemStack assemble(final CraftingInput input, final HolderLookup.Provider lookup) { + return ItemStackUtil.toNative(this.resultFunction.apply(InventoryUtil.toSponge(input))); } @OnlyIn(Dist.CLIENT) @@ -85,11 +98,11 @@ public boolean canCraftInDimensions(int width, int height) { } @Override - public NonNullList getRemainingItems(CraftingContainer inv) { + public NonNullList getRemainingItems(final CraftingInput input) { if (this.remainingItemsFunction == null) { - return super.getRemainingItems(inv); + return super.getRemainingItems(input); } - final List remainingSponge = this.remainingItemsFunction.apply(InventoryUtil.toSpongeInventory(inv)); + final List remainingSponge = this.remainingItemsFunction.apply(InventoryUtil.toSponge(input)); final NonNullList remaining = NonNullList.create(); remainingSponge.forEach(item -> remaining.add(ItemStackUtil.toNative(item))); return remaining; diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java index c24b087aa15..cbc3331d1d2 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java @@ -31,15 +31,16 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.ShapedRecipePattern; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.Ingredient; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.ShapedCraftingRecipe; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.recipe.ingredient.IngredientUtil; @@ -66,8 +67,8 @@ public final class SpongeShapedCraftingRecipeBuilder extends AbstractResourceKey private final Map reverseIngredientMap = new IdentityHashMap<>(); private ItemStack result = ItemStack.empty(); - private Function> remainingItemsFunction; - private Function resultFunction; + private Function> remainingItemsFunction; + private Function resultFunction; private String group; private DataPack pack = DataPacks.RECIPE; @@ -136,15 +137,11 @@ public RowsStep.ResultStep row(final int skip, final Ingredient... ingredients) return this; } - public ShapedCraftingRecipe.Builder.ResultStep shapedLike(ShapedCraftingRecipe recipe) { - throw new UnsupportedOperationException("not implemented yet"); - } - @Override - public ShapedCraftingRecipe.Builder.ResultStep remainingItems(Function> remainingItemsFunction) { + public ShapedCraftingRecipe.Builder.ResultStep remainingItems(Function> remainingItemsFunction) { this.remainingItemsFunction = grid -> { final NonNullList mcList = NonNullList.create(); - remainingItemsFunction.apply(InventoryUtil.toSpongeInventory(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); + remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); return mcList; }; return this; @@ -165,8 +162,8 @@ public EndStep result(final ItemStack result) { } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSpongeInventory(inv))); + public EndStep result(Function resultFunction, ItemStack exemplaryResult) { + this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); this.result = exemplaryResult.copy(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeRegistration.java index d1ca937e54c..b65c5c09b99 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeRegistration.java @@ -27,9 +27,9 @@ import net.minecraft.core.NonNullList; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipePattern; @@ -42,22 +42,22 @@ import java.util.function.Function; public class SpongeShapedCraftingRecipeRegistration extends SpongeRecipeRegistration implements - SpongeRecipeRegistration.ResultFunctionRegistration, - SpongeRecipeRegistration.RemainingItemsFunctionRegistration { + SpongeRecipeRegistration.ResultFunctionRegistration, + SpongeRecipeRegistration.RemainingItemsFunctionRegistration { // Vanilla Recipe private final ShapedRecipePattern pattern; // Sponge Recipe private final ItemStack spongeResult; - private final Function resultFunction; - private final Function> remainingItemsFunction; + private final Function resultFunction; + private final Function> remainingItemsFunction; private final CraftingBookCategory craftingBookCategory; private final boolean showNotification = true; public SpongeShapedCraftingRecipeRegistration(final ResourceLocation key, final String group, final ShapedRecipePattern pattern, - final ItemStack spongeResult, final Function resultFunction, - final Function> remainingItemsFunction, + final ItemStack spongeResult, final Function resultFunction, + final Function> remainingItemsFunction, final DataPack pack, final RecipeCategory category, final CraftingBookCategory craftingBookCategory) { super(key, group, pack, category, RecipeSerializer.SHAPED_RECIPE); this.pattern = pattern; @@ -68,12 +68,12 @@ public SpongeShapedCraftingRecipeRegistration(final ResourceLocation key, final } @Override - public Function resultFunction() { + public Function resultFunction() { return this.resultFunction; } @Override - public Function> remainingItems() { + public Function> remainingItems() { return this.remainingItemsFunction; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedRecipe.java index da579b6fe18..0dd447c0c7c 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedRecipe.java @@ -30,9 +30,9 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipePattern; import org.spongepowered.common.bridge.world.item.crafting.RecipeResultBridge; @@ -103,15 +103,15 @@ public Optional remainingItemsFunctionId() { } @Override - public NonNullList getRemainingItems(CraftingContainer inv) { + public NonNullList getRemainingItems(final CraftingInput $$0) { if (this.remainingItemsFunctionId != null) { - return IngredientResultUtil.cachedRemainingItemsFunction(this.remainingItemsFunctionId).apply(inv); + return IngredientResultUtil.cachedRemainingItemsFunction(this.remainingItemsFunctionId).apply($$0); } - return super.getRemainingItems(inv); + return super.getRemainingItems($$0); } @Override - public ItemStack assemble(final CraftingContainer $$0, final HolderLookup.Provider $$1) { + public ItemStack assemble(final CraftingInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java index dc8f75f3eb1..cbdab7a7e60 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java @@ -31,14 +31,15 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.Ingredient; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.recipe.RecipeRegistration; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.ShapelessCraftingRecipe; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.recipe.ingredient.IngredientUtil; @@ -55,8 +56,8 @@ public class SpongeShapelessCraftingRecipeBuilder extends AbstractResourceKeyedB implements ShapelessCraftingRecipe.Builder.EndStep, ShapelessCraftingRecipe.Builder.ResultStep { private org.spongepowered.api.item.inventory.ItemStack result; - private Function resultFunction; - private Function> remainingItemsFunction; + private Function resultFunction; + private Function> remainingItemsFunction; private final NonNullList ingredients = NonNullList.create(); private String group; private DataPack pack = DataPacks.RECIPE; @@ -89,10 +90,10 @@ public ResultStep addIngredients(org.spongepowered.api.item.recipe.crafting.Ingr } @Override - public ResultStep remainingItems(Function> remainingItemsFunction) { + public ResultStep remainingItems(Function> remainingItemsFunction) { this.remainingItemsFunction = grid -> { final NonNullList mcList = NonNullList.create(); - remainingItemsFunction.apply(InventoryUtil.toSpongeInventory(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); + remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); return mcList; }; return this; @@ -115,8 +116,8 @@ public EndStep result(org.spongepowered.api.item.inventory.ItemStack result) { } @Override - public EndStep result(Function resultFunction, org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSpongeInventory(inv))); + public EndStep result(Function resultFunction, org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { + this.resultFunction = (input) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(input))); this.result = exemplaryResult.copy(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeRegistration.java index 70e19bb28b2..c70e8658c1f 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeRegistration.java @@ -27,9 +27,9 @@ import net.minecraft.core.NonNullList; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.ShapelessRecipe; @@ -43,21 +43,21 @@ import java.util.function.Function; public class SpongeShapelessCraftingRecipeRegistration extends SpongeRecipeRegistration implements - SpongeRecipeRegistration.ResultFunctionRegistration, - SpongeRecipeRegistration.RemainingItemsFunctionRegistration + SpongeRecipeRegistration.ResultFunctionRegistration, + SpongeRecipeRegistration.RemainingItemsFunctionRegistration { // Vanilla Recipe private final List ingredients; // Sponge Recipe private final ItemStack spongeResult; - private final Function resultFunction; - private final Function> remainingItemsFunction; + private final Function resultFunction; + private final Function> remainingItemsFunction; private final CraftingBookCategory craftingBookCategory; public SpongeShapelessCraftingRecipeRegistration(final ResourceLocation key, final String group, - final List ingredients, final ItemStack spongeResult, final Function resultFunction, - final Function> remainingItemsFunction, + final List ingredients, final ItemStack spongeResult, final Function resultFunction, + final Function> remainingItemsFunction, final DataPack pack, final RecipeCategory category, final CraftingBookCategory craftingBookCategory) { super(key, group, pack, category, RecipeSerializer.SHAPELESS_RECIPE); this.ingredients = ingredients; @@ -69,12 +69,12 @@ public SpongeShapelessCraftingRecipeRegistration(final ResourceLocation key, fin @Override - public Function resultFunction() { + public Function resultFunction() { return this.resultFunction; } @Override - public Function> remainingItems() { + public Function> remainingItems() { return this.remainingItemsFunction; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java index 439fff51607..02779a90f6d 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java @@ -30,9 +30,9 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraft.world.level.Level; @@ -124,36 +124,29 @@ public Optional remainingItemsFunctionId() { return Optional.ofNullable(remainingItemsFunctionId); } - @Override - public boolean matches(CraftingContainer inv, Level p_77569_2_) { + public boolean matches(final CraftingInput $$0, final Level $$1) { if (this.onlyVanillaIngredients) { - return super.matches(inv, p_77569_2_); - } - List items = new ArrayList<>(); - for(int j = 0; j < inv.getContainerSize(); ++j) { - final ItemStack itemstack = inv.getItem(j); - if (!itemstack.isEmpty()) { - items.add(itemstack); - } + return super.matches($$0, $$1); } - return SpongeShapelessRecipe.matches(items, this.getIngredients()); + return SpongeShapelessRecipe.matches($$0.items(), this.getIngredients()); } @Override - public NonNullList getRemainingItems(CraftingContainer inv) { + public NonNullList getRemainingItems(final CraftingInput $$0) { if (this.remainingItemsFunctionId != null) { - return IngredientResultUtil.cachedRemainingItemsFunction(this.remainingItemsFunctionId).apply(inv); + return IngredientResultUtil.cachedRemainingItemsFunction(this.remainingItemsFunctionId).apply($$0); } - return super.getRemainingItems(inv); + return super.getRemainingItems($$0); } + @Override - public ItemStack assemble(CraftingContainer container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final CraftingInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientResultUtil.java b/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientResultUtil.java index 03e427e8f65..11d658bef51 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientResultUtil.java +++ b/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientResultUtil.java @@ -32,6 +32,8 @@ import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Container; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.RecipeInput; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.SpongeCommon; @@ -57,8 +59,8 @@ public static JsonElement serializeItemStack(final net.minecraft.world.item.Item @Nullable @SuppressWarnings("unchecked") - public static Function cachedResultFunction(String id) { - return (Function) IngredientResultUtil.cachedResultFunctions.get(id); + public static Function cachedResultFunction(String id) { + return (Function) IngredientResultUtil.cachedResultFunctions.get(id); } @@ -81,8 +83,8 @@ public static String cacheResultFunction(ResourceLocation @Nullable @SuppressWarnings("unchecked") - public static Function> cachedRemainingItemsFunction(String id) { - return (Function>) IngredientResultUtil.cachedRemainingItemsFunctions.get(id); + public static Function> cachedRemainingItemsFunction(String id) { + return (Function>) IngredientResultUtil.cachedRemainingItemsFunctions.get(id); } diff --git a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipe.java index 8e71cb9657b..bff50643488 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipe.java @@ -30,9 +30,9 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.HolderLookup; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import net.minecraft.world.item.crafting.SmithingTransformRecipe; import org.spongepowered.common.bridge.world.item.crafting.RecipeResultBridge; import org.spongepowered.common.bridge.world.item.crafting.SmithingRecipeBridge; @@ -76,7 +76,7 @@ public Optional resultFunctionId() { } @Override - public ItemStack assemble(Container $$0, HolderLookup.Provider $$1) { + public ItemStack assemble(final SmithingRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); } diff --git a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java index 20d393de264..05c9ee108f6 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java @@ -27,17 +27,17 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.Item; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.recipe.RecipeRegistration; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.smithing.SmithingRecipe; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.recipe.ingredient.IngredientUtil; @@ -55,7 +55,7 @@ public final class SpongeSmithingRecipeBuilder extends AbstractResourceKeyedBuil private Ingredient template; private Ingredient base; private Ingredient addition; - private Function resultFunction; + private Function resultFunction; private @Nullable String group; private DataPack pack = DataPacks.RECIPE; @@ -113,12 +113,12 @@ public EndStep result(final ItemStack result) { } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { + public EndStep result(Function resultFunction, ItemStack exemplaryResult) { Objects.requireNonNull(exemplaryResult, "exemplaryResult"); Preconditions.checkState(!exemplaryResult.isEmpty(), "exemplaryResult must not be empty"); this.result = exemplaryResult; - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toInventory(inv))); + this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeRegistration.java index 5680a0f13a0..39a62cbb37a 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeRegistration.java @@ -26,10 +26,10 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import net.minecraft.world.item.crafting.SmithingTransformRecipe; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.item.recipe.Recipe; @@ -41,7 +41,7 @@ import java.util.function.Function; public class SpongeSmithingRecipeRegistration extends SpongeRecipeRegistration implements - SpongeRecipeRegistration.ResultFunctionRegistration { + SpongeRecipeRegistration.ResultFunctionRegistration { // Vanilla Recipe private final Ingredient template; @@ -51,10 +51,10 @@ public class SpongeSmithingRecipeRegistration extends SpongeRecipeRegistration resultFunction; + private final Function resultFunction; public SpongeSmithingRecipeRegistration(ResourceLocation key, String group, final Ingredient template, Ingredient base, - Ingredient addition, ItemStack spongeResult, Function resultFunction, + Ingredient addition, ItemStack spongeResult, Function resultFunction, DataPack pack, final RecipeCategory category) { super(key, group, pack, category, RecipeSerializer.SMITHING_TRANSFORM); this.template = template; @@ -75,7 +75,7 @@ public Recipe recipe() { } @Override - public Function resultFunction() { + public Function resultFunction() { return this.resultFunction; } } diff --git a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java index ff3b220dc01..86b7be9c191 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java @@ -27,17 +27,17 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.Item; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.SingleRecipeInput; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.recipe.RecipeRegistration; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.single.StoneCutterRecipe; import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.recipe.ingredient.IngredientUtil; @@ -53,7 +53,7 @@ public final class SpongeStoneCutterRecipeBuilder extends AbstractResourceKeyedB private ItemStack result; private Ingredient ingredient; - private Function resultFunction; + private Function resultFunction; private @Nullable String group; private DataPack pack = DataPacks.RECIPE; @@ -87,12 +87,12 @@ public EndStep result(final ItemStack result) { } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { + public EndStep result(Function resultFunction, ItemStack exemplaryResult) { Objects.requireNonNull(exemplaryResult, "exemplaryResult"); Preconditions.checkState(!exemplaryResult.isEmpty(), "exemplaryResult must not be empty"); this.result = exemplaryResult; - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toInventory(inv))); + this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipe.java index 2c2510cb335..a2401eadcd8 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipe.java @@ -31,10 +31,10 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.SingleItemRecipe; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.StonecutterRecipe; import org.spongepowered.common.bridge.world.item.crafting.RecipeResultBridge; import org.spongepowered.common.item.recipe.ResultFunctionRecipe; @@ -88,11 +88,11 @@ public Optional resultFunctionId() { } @Override - public ItemStack assemble(final Container container, final HolderLookup.Provider $$1) { + public ItemStack assemble(final SingleRecipeInput $$0, final HolderLookup.Provider $$1) { if (this.resultFunctionId != null) { - return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply(container); + return IngredientResultUtil.cachedResultFunction(this.resultFunctionId).apply($$0); } - return super.assemble(container, $$1); + return super.assemble($$0, $$1); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipeRegistration.java index cbe05e497d5..bb101b4c0b4 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStonecuttingRecipeRegistration.java @@ -26,10 +26,10 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.StonecutterRecipe; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.item.recipe.Recipe; @@ -41,17 +41,17 @@ import java.util.function.Function; public class SpongeStonecuttingRecipeRegistration extends SpongeRecipeRegistration implements - SpongeRecipeRegistration.ResultFunctionRegistration { + SpongeRecipeRegistration.ResultFunctionRegistration { // Vanilla Recipe private final Ingredient ingredient; // Sponge Recipe private final ItemStack spongeResult; - private Function resultFunction; + private Function resultFunction; public SpongeStonecuttingRecipeRegistration(ResourceLocation key, String group, Ingredient ingredient, - ItemStack spongeResult, Function resultFunction, + ItemStack spongeResult, Function resultFunction, DataPack pack, final RecipeCategory category) { super(key, group, pack, category, RecipeSerializer.STONECUTTER); this.ingredient = ingredient; @@ -70,7 +70,7 @@ public Recipe recipe() { } @Override - public Function resultFunction() { + public Function resultFunction() { return this.resultFunction; } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java index 33d62e6a35f..f913eb04cb9 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java @@ -50,6 +50,7 @@ import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackComparators; import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.network.channel.ChannelExceptionHandler; import org.spongepowered.api.network.status.Favicon; import org.spongepowered.api.profile.GameProfile; @@ -125,6 +126,7 @@ import org.spongepowered.common.item.SpongeItemStack; import org.spongepowered.common.item.SpongeItemStackSnapshot; import org.spongepowered.common.item.SpongeToolRuleFactory; +import org.spongepowered.common.item.recipe.SpongeRecipeInputFactory; import org.spongepowered.common.item.util.SpongeItemStackComparatorFactory; import org.spongepowered.common.network.channel.SpongeChannelExceptionHandlerFactory; import org.spongepowered.common.network.status.SpongeFavicon; @@ -281,6 +283,7 @@ public void registerDefaultFactories() { .registerFactory(ScoreFormat.Factory.class, new SpongeScoreFormatFactory()) .registerFactory(ToolRule.Factory.class, new SpongeToolRuleFactory()) .registerFactory(PortalLogic.Factory.class, new SpongePortalLogicFactory()) + .registerFactory(RecipeInput.Factory.class, new SpongeRecipeInputFactory()) ; } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java index 439050000b2..91379e7ee08 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java @@ -308,7 +308,7 @@ public boolean respawn() { if (this.shadow$getHealth() > 0.0F) { return false; } - this.connection.player = this.server.getPlayerList().respawn((net.minecraft.server.level.ServerPlayer) (Object) this, false); + this.connection.player = this.server.getPlayerList().respawn((net.minecraft.server.level.ServerPlayer) (Object) this, false, Entity.RemovalReason.DISCARDED); return true; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeModifierMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeModifierMixin_API.java index d28ade0751a..766744c19ee 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeModifierMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeModifierMixin_API.java @@ -24,31 +24,30 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.ai.attributes; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.entity.attribute.AttributeModifier; import org.spongepowered.api.entity.attribute.AttributeOperation; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import java.util.UUID; - @Mixin(net.minecraft.world.entity.ai.attributes.AttributeModifier.class) public abstract class AttributeModifierMixin_API implements AttributeModifier { // @formatter:off - @Shadow @Final private String name; @Shadow @Final private double amount; - @Shadow @Final private UUID id; - @Shadow @Final private Operation operation; + @Shadow @Final private ResourceLocation id; + // @formatter:on @Override - public String name() { - return this.name; + public ResourceKey key() { + return (ResourceKey) (Object) this.id; } @Override @@ -62,9 +61,4 @@ public double amount() { return this.amount; } - @Override - public UUID uniqueId() { - return this.id; - } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java index e7536de73be..efa6d8b2734 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java @@ -26,16 +26,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Container; -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.inventory.CraftingMenu; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.inventory.StonecutterMenu; -import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; -import net.minecraft.world.level.block.entity.CampfireBlockEntity; +import net.minecraft.world.item.crafting.RecipeInput; +import net.minecraft.world.item.crafting.RecipeManager.CachedCheck; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.level.Level; import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.recipe.Recipe; import org.spongepowered.api.item.recipe.RecipeManager; @@ -44,9 +40,7 @@ import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.common.accessor.world.inventory.CraftingMenuAccessor; -import org.spongepowered.common.accessor.world.inventory.InventoryMenuAccessor; -import org.spongepowered.common.accessor.world.level.block.entity.AbstractFurnaceBlockEntityAccessor; +import org.spongepowered.common.inventory.util.InventoryUtil; import org.spongepowered.common.item.util.ItemStackUtil; import java.util.Collection; @@ -59,33 +53,33 @@ public abstract class RecipeManagerMixin_API implements RecipeManager { // @formatter:off @Shadow public abstract Optional> shadow$byKey(ResourceLocation recipeId); - @Shadow protected abstract > Collection> shadow$byType(net.minecraft.world.item.crafting.RecipeType recipeTypeIn); + @Shadow protected abstract > Collection> shadow$byType(net.minecraft.world.item.crafting.RecipeType recipeTypeIn); @Shadow public abstract Collection> shadow$getRecipes(); - @Shadow public abstract > Optional shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType recipeTypeIn, C inventoryIn, net.minecraft.world.level.Level worldIn); + @Shadow public abstract > Optional shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType recipeTypeIn, I inventoryIn, net.minecraft.world.level.Level worldIn); // @formatter:on @Override - public Optional byKey(final ResourceKey key) { + public Optional> byKey(final ResourceKey key) { Objects.requireNonNull(key); return this.shadow$byKey((ResourceLocation) (Object) key).map(Recipe.class::cast); } @Override @SuppressWarnings(value = {"unchecked", "rawtypes"}) - public Collection all() { + public Collection> all() { return (Collection) this.shadow$getRecipes(); } @Override @SuppressWarnings(value = {"unchecked", "rawtypes"}) - public Collection allOfType(final RecipeType type) { + public > Collection allOfType(final RecipeType type) { Objects.requireNonNull(type); return this.shadow$byType((net.minecraft.world.item.crafting.RecipeType)type); } @Override - public Collection findByResult(final RecipeType type, final ItemStackSnapshot result) { + public > Collection findByResult(final RecipeType type, final ItemStackSnapshot result) { Objects.requireNonNull(type); Objects.requireNonNull(result); return this.allOfType(type).stream() @@ -93,45 +87,25 @@ public Collection findByResult(final RecipeType type, f .collect(Collectors.toList()); } - @Override - @SuppressWarnings("unchecked") - public Optional findMatchingRecipe(final Inventory inventory, final ServerWorld world) { - Objects.requireNonNull(inventory); - Objects.requireNonNull(world); - if (inventory instanceof AbstractFurnaceBlockEntity furnace) { - - final Optional recipeFor = ((AbstractFurnaceBlockEntityAccessor) inventory).accessor$quickCheck().getRecipeFor(furnace, furnace.getLevel()).map(RecipeHolder::value); - return recipeFor.map(Recipe.class::cast); - } - if (inventory instanceof CampfireBlockEntity) { - return this.shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType.CAMPFIRE_COOKING, (Container) inventory, (net.minecraft.world.level.Level) world).map(Recipe.class::cast); - } - if (inventory instanceof CraftingMenu) { - final CraftingContainer craftingInventory = ((CraftingMenuAccessor) inventory).accessor$craftSlots(); - return this.shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType.CRAFTING, craftingInventory, (net.minecraft.world.level.Level) world).map(Recipe.class::cast); - } - if (inventory instanceof InventoryMenu) { - final CraftingContainer craftingInventory = ((InventoryMenuAccessor) inventory).accessor$craftSlots(); - return this.shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType.CRAFTING, craftingInventory, (net.minecraft.world.level.Level) world).map(Recipe.class::cast); - } - if (inventory instanceof StonecutterMenu) { - final Container stonecutterInventory = ((StonecutterMenu) inventory).container; - return this.shadow$getRecipeFor(net.minecraft.world.item.crafting.RecipeType.STONECUTTING, stonecutterInventory, (net.minecraft.world.level.Level) world).map(Recipe.class::cast); - } - - return Optional.empty(); - } - @Override @SuppressWarnings(value = {"unchecked", "rawtypes"}) - public Optional findMatchingRecipe(final RecipeType type, final Inventory inventory, final ServerWorld world) { + public > Optional findMatchingRecipe(final RecipeType type, final I inventory, final ServerWorld world) { Objects.requireNonNull(type); Objects.requireNonNull(inventory); Objects.requireNonNull(world); if (!(inventory instanceof Container)) { return Optional.empty(); } - return this.shadow$getRecipeFor((net.minecraft.world.item.crafting.RecipeType) type, (Container) inventory, (net.minecraft.world.level.Level) world); + + final var mcRecipeType = (net.minecraft.world.item.crafting.RecipeType) type; + final var checker = net.minecraft.world.item.crafting.RecipeManager.createCheck(mcRecipeType); + final var level = (Level) world; + + return InventoryUtil.toCraftingInput(inventory).flatMap(in -> RecipeManagerMixin_API.impl$getRecipe(level, checker, in)); + } + + private static > Optional> impl$getRecipe(final Level level, final CachedCheck checker, final I input) { + return checker.getRecipeFor(input, level).map(RecipeHolder::value).map(Recipe.class::cast); } @Override @@ -139,8 +113,8 @@ public Optional findMatchingRecipe(final RecipeType typ public Optional findCookingRecipe(final RecipeType type, final ItemStackSnapshot ingredient) { Objects.requireNonNull(type); Objects.requireNonNull(ingredient); - final net.minecraft.world.SimpleContainer fakeFurnace = new net.minecraft.world.SimpleContainer(1); - fakeFurnace.setItem(0, ItemStackUtil.fromSnapshotToNative(ingredient)); - return this.shadow$getRecipeFor((net.minecraft.world.item.crafting.RecipeType) type, fakeFurnace, null); + + final SingleRecipeInput input = new SingleRecipeInput(ItemStackUtil.fromSnapshotToNative(ingredient)); + return this.shadow$getRecipeFor((net.minecraft.world.item.crafting.RecipeType) type, input, null); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeMixin_API.java index 06000af2650..af01bd79ede 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeMixin_API.java @@ -24,14 +24,13 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.item.crafting; -import static org.spongepowered.common.inventory.util.InventoryUtil.toNativeInventory; +import static org.spongepowered.common.inventory.util.InventoryUtil.toCraftingInputOrThrow; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeInput; import org.checkerframework.checker.nullness.qual.NonNull; -import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.recipe.Recipe; import org.spongepowered.api.item.recipe.RecipeType; @@ -47,14 +46,14 @@ import java.util.stream.Collectors; @Mixin(net.minecraft.world.item.crafting.Recipe.class) -public interface RecipeMixin_API extends Recipe { +public interface RecipeMixin_API extends Recipe { // @formatter:off - @Shadow ItemStack shadow$assemble(C inv, HolderLookup.Provider registryAccess); + @Shadow ItemStack shadow$assemble(I inv, HolderLookup.Provider registryAccess); @Shadow net.minecraft.world.item.ItemStack shadow$getResultItem(HolderLookup.Provider registryAccess); @Shadow boolean shadow$isSpecial(); - @Shadow boolean shadow$matches(C inv, net.minecraft.world.level.Level worldIn); - @Shadow NonNullList shadow$getRemainingItems(C inv); + @Shadow boolean shadow$matches(I inv, net.minecraft.world.level.Level worldIn); + @Shadow NonNullList shadow$getRemainingItems(I inv); @Shadow net.minecraft.world.item.crafting.RecipeType shadow$getType(); @Shadow NonNullList shadow$getIngredients(); // @formatter:on @@ -66,20 +65,21 @@ default ItemStackSnapshot exemplaryResult() { } @Override - default boolean isValid(@NonNull final Inventory inv, @NonNull final ServerWorld world) { - return this.shadow$matches(toNativeInventory(inv), (net.minecraft.world.level.Level) world); + default boolean isValid(@NonNull final I2 inv, @NonNull final ServerWorld world) { + return this.shadow$matches((I) toCraftingInputOrThrow(inv), (net.minecraft.world.level.Level) world); } @NonNull @Override - default ItemStackSnapshot result(@NonNull final Inventory inv) { - return ItemStackUtil.snapshotOf(this.shadow$assemble(toNativeInventory(inv), SpongeCommon.server().registryAccess())); + default ItemStackSnapshot result(@NonNull final I2 inv) { + return ItemStackUtil.snapshotOf(this.shadow$assemble((I) toCraftingInputOrThrow(inv), SpongeCommon.server().registryAccess())); } @NonNull @Override - default List remainingItems(@NonNull final Inventory inv) { - return this.shadow$getRemainingItems(toNativeInventory(inv)).stream() + default List remainingItems(@NonNull final I2 inv) { + final var nonNullList = this.shadow$getRemainingItems((I) toCraftingInputOrThrow(inv)); + return nonNullList.stream() .map(ItemStackUtil::snapshotOf) .collect(Collectors.toList()); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeTypeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeTypeMixin_API.java index 0a69fdb0268..a80d772cc56 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeTypeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeTypeMixin_API.java @@ -29,5 +29,5 @@ import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.item.crafting.RecipeType.class) -public interface RecipeTypeMixin_API extends RecipeType { +public interface RecipeTypeMixin_API> extends RecipeType { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/AbstractFurnaceBlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/AbstractFurnaceBlockEntityMixin_API.java index 5daf5a6f270..d2f65b5e945 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/AbstractFurnaceBlockEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/AbstractFurnaceBlockEntityMixin_API.java @@ -24,10 +24,14 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.level.block.entity; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; import org.spongepowered.api.block.entity.carrier.furnace.FurnaceBlockEntity; import org.spongepowered.api.data.persistence.DataContainer; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.util.Constants; @@ -38,10 +42,11 @@ public abstract class AbstractFurnaceBlockEntityMixin_API extends BaseContainerBlockEntityMixin_API implements FurnaceBlockEntity { // @formatter:off - @Shadow private int litTime; - @Shadow private int litDuration; - @Shadow private int cookingProgress; - @Shadow private int cookingTotalTime; + @Shadow int litTime; + @Shadow int litDuration; + @Shadow int cookingProgress; + @Shadow int cookingTotalTime; + @Shadow protected NonNullList items; // @formatter:on @Override @@ -65,4 +70,8 @@ public DataContainer toContainer() { .set(Constants.TileEntity.Furnace.COOK_TIME_TOTAL, this.cookingTotalTime); } + @Override + public RecipeInput.Single asRecipeInput() { + return (RecipeInput.Single) (Object) new SingleRecipeInput(this.items.get(0)); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/CampfireBlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/CampfireBlockEntityMixin_API.java index 4d032ed4c3d..de26556d819 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/CampfireBlockEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/CampfireBlockEntityMixin_API.java @@ -24,10 +24,25 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.level.block.entity; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.block.entity.CampfireBlockEntity; import org.spongepowered.api.block.entity.carrier.Campfire; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; @Mixin(CampfireBlockEntity.class) public abstract class CampfireBlockEntityMixin_API extends BlockEntityMixin_API implements Campfire { + + @Shadow @Final private NonNullList items; + + @Override + public List recipeInputs() { + return this.items.stream().map(SingleRecipeInput::new).map(RecipeInput.Single.class::cast).toList(); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/item/crafting/SimpleCraftingRecipeSerializerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/crafting/SimpleCraftingRecipeSerializerMixin.java new file mode 100644 index 00000000000..9defd9d4e6b --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/item/crafting/SimpleCraftingRecipeSerializerMixin.java @@ -0,0 +1,58 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.item.crafting; + +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.common.item.recipe.crafting.custom.SpongeSpecialRecipe; + +import java.util.function.Function; + +@Mixin(SimpleCraftingRecipeSerializer.class) +public abstract class SimpleCraftingRecipeSerializerMixin { + + + @Redirect(method = "", at = @At(value = "INVOKE", + target = "Lcom/mojang/serialization/codecs/RecordCodecBuilder;mapCodec(Ljava/util/function/Function;)Lcom/mojang/serialization/MapCodec;")) + private MapCodec impl$onCreateCodec(final Function, ? extends App, T>> builder) { + final var mcMapCodec = RecordCodecBuilder.mapCodec(builder); + final var eitherMapCodec = Codec.mapEither((MapCodec) SpongeSpecialRecipe.SPONGE_CODEC, mcMapCodec); + return eitherMapCodec.xmap(to -> to.map(si -> si, i -> i), fr -> { + if (fr instanceof SpongeSpecialRecipe) { + return Either.left(fr); + } + return Either.right(fr); + }); + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin.java index 7c1ad57ea1e..38afcfe57dc 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin.java @@ -26,11 +26,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -70,7 +70,7 @@ public abstract class AbstractFurnaceBlockEntityMixin extends BaseContainerBlock // @Formatter:on - @Shadow @Final private RecipeManager.CachedCheck quickCheck; + @Shadow @Final private RecipeManager.CachedCheck quickCheck; // Shrink Fuel @Redirect(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;shrink(I)V")) @@ -103,7 +103,8 @@ public abstract class AbstractFurnaceBlockEntityMixin extends BaseContainerBlock @Override public Optional> bridge$getCurrentRecipe() { - return this.quickCheck.getRecipeFor((AbstractFurnaceBlockEntity) (Object) this, this.level); + var recipeInpuit = new SingleRecipeInput(this.items.get(0)); + return this.quickCheck.getRecipeFor(recipeInpuit, this.level); } // Interrupt-Active - e.g. a player removing the currently smelting item diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java new file mode 100644 index 00000000000..acbe4cb35ae --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java @@ -0,0 +1,51 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.inventory; + + +import net.minecraft.world.level.block.entity.CrafterBlockEntity; +import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; +import org.spongepowered.api.item.inventory.type.GridInventory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.inventory.adapter.InventoryAdapter; +import org.spongepowered.common.inventory.fabric.Fabric; +import org.spongepowered.common.inventory.lens.impl.comp.CraftingGridInventoryLens; + +@Mixin(CrafterBlockEntity.class) +public abstract class CrafterBlockBlockEntityMixin_Inventory_API implements CraftingGridInventory { + + private GridInventory api$gridAdapter; + + @Override + public GridInventory asGrid() { + // override with caching + final CraftingGridInventoryLens lens = (CraftingGridInventoryLens) ((InventoryAdapter) this).inventoryAdapter$getRootLens(); + if (this.api$gridAdapter == null) { + this.api$gridAdapter = (GridInventory) lens.getGrid().getAdapter(((Fabric) this), this); + } + return this.api$gridAdapter; + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CraftingContainerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CraftingContainerMixin_Inventory_API.java new file mode 100644 index 00000000000..90d8b084213 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CraftingContainerMixin_Inventory_API.java @@ -0,0 +1,69 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.inventory; + + +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.crafting.CraftingInput; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; +import org.spongepowered.api.item.inventory.type.GridInventory; +import org.spongepowered.api.item.recipe.RecipeTypes; +import org.spongepowered.api.item.recipe.crafting.CraftingRecipe; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.inventory.adapter.InventoryAdapter; +import org.spongepowered.common.inventory.fabric.Fabric; +import org.spongepowered.common.inventory.lens.impl.comp.CraftingGridInventoryLens; + +import java.util.Objects; +import java.util.Optional; + +@Mixin(CraftingContainer.class) +public interface CraftingContainerMixin_Inventory_API extends CraftingGridInventory { + + // @formatter:off + @Shadow CraftingInput shadow$asCraftInput(); + // @formatter:on + + @Override + default RecipeInput.Crafting asRecipeInput() { + return (RecipeInput.Crafting) this.shadow$asCraftInput(); + } + + @Override + default GridInventory asGrid() { + final CraftingGridInventoryLens lens = (CraftingGridInventoryLens) ((InventoryAdapter) this).inventoryAdapter$getRootLens(); + return (GridInventory) lens.getGrid().getAdapter(((Fabric) this), null); // TODO crafter block + } + + @Override + default Optional recipe(ServerWorld world) { + return Sponge.server().recipeManager().findMatchingRecipe(RecipeTypes.CRAFTING, this.asRecipeInput(), Objects.requireNonNull(world, "world")).map(CraftingRecipe.class::cast); + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/TransientCraftingContainerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/TransientCraftingContainerMixin_Inventory_API.java index 7a8b32ac569..033f5ee3738 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/TransientCraftingContainerMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/TransientCraftingContainerMixin_Inventory_API.java @@ -27,12 +27,9 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.TransientCraftingContainer; -import org.spongepowered.api.Sponge; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.inventory.type.GridInventory; -import org.spongepowered.api.item.recipe.crafting.CraftingRecipe; -import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -40,9 +37,6 @@ import org.spongepowered.common.inventory.fabric.Fabric; import org.spongepowered.common.inventory.lens.impl.comp.CraftingGridInventoryLens; -import java.util.Objects; -import java.util.Optional; - @Mixin(TransientCraftingContainer.class) public abstract class TransientCraftingContainerMixin_Inventory_API implements CraftingGridInventory { @@ -50,20 +44,17 @@ public abstract class TransientCraftingContainerMixin_Inventory_API implements C @Shadow @Final private AbstractContainerMenu menu; // @formatter:on - private GridInventory gridAdapter; + private GridInventory api$gridAdapter; - @Override - public Optional recipe(ServerWorld world) { - return Sponge.server().recipeManager().findMatchingRecipe((Inventory) this.menu, Objects.requireNonNull(world, "world")).map(CraftingRecipe.class::cast); - } @Override public GridInventory asGrid() { + // override with caching final CraftingGridInventoryLens lens = (CraftingGridInventoryLens) ((InventoryAdapter) this).inventoryAdapter$getRootLens(); - if (this.gridAdapter == null) { - this.gridAdapter = (GridInventory) lens.getGrid().getAdapter(((Fabric) this), ((Inventory) this.menu)); + if (this.api$gridAdapter == null) { + this.api$gridAdapter = (GridInventory) lens.getGrid().getAdapter((Fabric) this, ((Inventory) this.menu)); } - return this.gridAdapter; + return this.api$gridAdapter; } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/CraftingInputMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/CraftingInputMixin_Inventory_API.java new file mode 100644 index 00000000000..e355dcb6eef --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/CraftingInputMixin_Inventory_API.java @@ -0,0 +1,62 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.item.crafting; + + +import net.minecraft.world.item.crafting.CraftingInput; +import org.spongepowered.api.item.inventory.type.GridInventory; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.bridge.world.inventory.LensGeneratorBridge; +import org.spongepowered.common.inventory.adapter.InventoryAdapter; +import org.spongepowered.common.inventory.fabric.Fabric; +import org.spongepowered.common.inventory.lens.Lens; +import org.spongepowered.common.inventory.lens.impl.comp.GridInventoryLens; +import org.spongepowered.common.inventory.lens.impl.slot.SlotLensProvider; + +@Mixin(CraftingInput.class) +public abstract class CraftingInputMixin_Inventory_API implements RecipeInput.Crafting, LensGeneratorBridge { + + @Shadow @Final private int width; + @Shadow @Final private int height; + private GridInventory api$gridAdapter; + + @Override + public GridInventory asGrid() { + // override with caching + final GridInventoryLens lens = (GridInventoryLens) ((InventoryAdapter) this).inventoryAdapter$getRootLens(); + if (this.api$gridAdapter == null) { + this.api$gridAdapter = (GridInventory) lens.getAdapter((Fabric) this, this); + } + return this.api$gridAdapter; + } + + @Override + public Lens lensGeneratorBridge$generateLens(final SlotLensProvider slotLensProvider) { + return new GridInventoryLens(0, this.width, this.height, slotLensProvider); + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/RecipeInputMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/RecipeInputMixin_Inventory_API.java new file mode 100644 index 00000000000..88db6035579 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/RecipeInputMixin_Inventory_API.java @@ -0,0 +1,53 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.item.crafting; + + +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.bridge.world.inventory.LensGeneratorBridge; +import org.spongepowered.common.inventory.adapter.impl.DefaultImplementedAdapterInventory; +import org.spongepowered.common.inventory.lens.Lens; +import org.spongepowered.common.inventory.lens.impl.DefaultIndexedLens; +import org.spongepowered.common.inventory.lens.impl.LensRegistrar; +import org.spongepowered.common.inventory.lens.impl.slot.SlotLensProvider; + +@Mixin(net.minecraft.world.item.crafting.RecipeInput.class) +public interface RecipeInputMixin_Inventory_API extends RecipeInput, DefaultImplementedAdapterInventory.WithClear, LensGeneratorBridge { + // @formatter:off + @Shadow int shadow$size(); + // @formatter:on + + @Override + default SlotLensProvider lensGeneratorBridge$generateSlotLensProvider() { + return new LensRegistrar.BasicSlotLensProvider(this.shadow$size()); + } + + @Override + default Lens lensGeneratorBridge$generateLens(SlotLensProvider slotLensProvider) { + return new DefaultIndexedLens(0, this.shadow$size(), slotLensProvider); + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/optimization/general/DataFixersMixin_Optimization_LazyDFU.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SingleRecipeInputMixin_Inventory_API.java similarity index 61% rename from src/mixins/java/org/spongepowered/common/mixin/optimization/general/DataFixersMixin_Optimization_LazyDFU.java rename to src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SingleRecipeInputMixin_Inventory_API.java index 9eda06ddeb8..f103e5b6c2d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/optimization/general/DataFixersMixin_Optimization_LazyDFU.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SingleRecipeInputMixin_Inventory_API.java @@ -22,22 +22,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.mixin.optimization.general; +package org.spongepowered.common.mixin.inventory.api.world.item.crafting; -import com.mojang.datafixers.DataFixerBuilder; -import net.minecraft.util.datafix.DataFixers; + +import net.minecraft.world.item.crafting.SingleRecipeInput; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.common.util.LazyDataFixerBuilder; -@Mixin(DataFixers.class) -public abstract class DataFixersMixin_Optimization_LazyDFU { +@Mixin(SingleRecipeInput.class) +public interface SingleRecipeInputMixin_Inventory_API extends RecipeInput.Single { - // Replaces Mojang's default DataFixerBuilder with a version that doesn't prebake all version rules at server - // startup. - @Redirect(method = "createFixerUpper", at = @At(value = "NEW", target = "com/mojang/datafixers/DataFixerBuilder")) - private static DataFixerBuilder createFixerUpper$replaceBuilder(int dataVersion) { - return new LazyDataFixerBuilder(dataVersion); - } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SmithingRecipeInputMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SmithingRecipeInputMixin_Inventory_API.java new file mode 100644 index 00000000000..c8165cbbec7 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/item/crafting/SmithingRecipeInputMixin_Inventory_API.java @@ -0,0 +1,35 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.item.crafting; + + +import net.minecraft.world.item.crafting.SmithingRecipeInput; +import org.spongepowered.api.item.recipe.crafting.RecipeInput; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(SmithingRecipeInput.class) +public interface SmithingRecipeInputMixin_Inventory_API extends RecipeInput.Smithing { + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/entity/LivingEntityMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/entity/LivingEntityMixin_Inventory.java index 113e05d1939..c1efdd8a2fb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/entity/LivingEntityMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/entity/LivingEntityMixin_Inventory.java @@ -90,8 +90,8 @@ protected LivingEntityMixin_Inventory(final EntityType param0, final Level pa final Slot slotAdapter = this.impl$getSpongeSlot(entry.getKey()); final ItemStack oldStack = switch (entry.getKey().getType()) { case HAND -> this.shadow$getLastHandItem(entry.getKey()); - case ARMOR -> this.shadow$getLastArmorItem(entry.getKey()); - case BODY -> this.lastBodyItemStack; + case HUMANOID_ARMOR -> this.shadow$getLastArmorItem(entry.getKey()); + case ANIMAL_ARMOR -> this.lastBodyItemStack; }; entry.setValue(this.impl$callEquipmentEvent(entry.getKey(), slotAdapter, entry.getValue(), oldStack)); }); diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java index 26258326a60..217d2ff77d4 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java @@ -259,17 +259,17 @@ public abstract class ServerPlayerMixin_Inventory extends PlayerMixin_Inventory method = "openHorseInventory", at = @At( value = "NEW", - target = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/entity/animal/horse/AbstractHorse;)Lnet/minecraft/world/inventory/HorseInventoryMenu;" + target = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/entity/animal/horse/AbstractHorse;I)Lnet/minecraft/world/inventory/HorseInventoryMenu;" ) ) private HorseInventoryMenu impl$transactHorseInventoryMenuCreationWithEffect( - final int $$0, final net.minecraft.world.entity.player.Inventory $$1, final Container $$2, final AbstractHorse $$3 + final int $$0, final net.minecraft.world.entity.player.Inventory $$1, final Container $$2, final AbstractHorse $$3, final int $$4 ) { try (final EffectTransactor ignored = PhaseTracker.SERVER.getPhaseContext() .getTransactor() .logOpenInventory((ServerPlayer) (Object) this) ) { - return new HorseInventoryMenu($$0, $$1, $$2, $$3); + return new HorseInventoryMenu($$0, $$1, $$2, $$3, $$4); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/world/inventory/ResultSlotMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/world/inventory/ResultSlotMixin_Inventory.java index e14fe83c440..65ac8c43f99 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/world/inventory/ResultSlotMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/world/inventory/ResultSlotMixin_Inventory.java @@ -35,6 +35,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import org.checkerframework.checker.nullness.qual.NonNull; @@ -86,9 +87,9 @@ public void set(@Nullable final ItemStack stack) { @Inject(method = "onTake", at = @At("HEAD")) private void impl$beforeTake(final Player thePlayer, final ItemStack stack, final CallbackInfo ci) { - if (this.impl$onTakeRecipe == null || !this.impl$onTakeRecipe.value().matches(this.craftSlots, thePlayer.level())) { + if (this.impl$onTakeRecipe == null || !this.impl$onTakeRecipe.value().matches(this.craftSlots.asCraftInput(), thePlayer.level())) { final RecipeManager manager = thePlayer.level().getRecipeManager(); - this.impl$onTakeRecipe = manager.getRecipeFor(RecipeType.CRAFTING, this.craftSlots, thePlayer.level()).orElse(null); + this.impl$onTakeRecipe = manager.getRecipeFor(RecipeType.CRAFTING, this.craftSlots.asCraftInput(), thePlayer.level()).orElse(null); } // When shift-crafting the crafted item was reduced to quantity 0 @@ -104,12 +105,12 @@ public void set(@Nullable final ItemStack stack) { stack.shrink(1); } - @Redirect(method = "onTake", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/crafting/RecipeManager;getRemainingItemsFor(Lnet/minecraft/world/item/crafting/RecipeType;Lnet/minecraft/world/Container;Lnet/minecraft/world/level/Level;)Lnet/minecraft/core/NonNullList;")) - private > NonNullList impl$onGetRemainingItems(final RecipeManager recipeManager, final RecipeType recipeTypeIn, final C inventoryIn, final net.minecraft.world.level.Level worldIn) { + @Redirect(method = "onTake", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/crafting/RecipeManager;getRemainingItemsFor(Lnet/minecraft/world/item/crafting/RecipeType;Lnet/minecraft/world/item/crafting/RecipeInput;Lnet/minecraft/world/level/Level;)Lnet/minecraft/core/NonNullList;")) + private > NonNullList impl$onGetRemainingItems(final RecipeManager recipeManager, final RecipeType recipeTypeIn, final I recipeInput, final net.minecraft.world.level.Level worldIn) { if (this.impl$onTakeRecipe == null) { - return NonNullList.withSize(inventoryIn.getContainerSize(), ItemStack.EMPTY); + return NonNullList.withSize(recipeInput.size(), ItemStack.EMPTY); } - return worldIn.getRecipeManager().getRemainingItemsFor(recipeTypeIn, inventoryIn, worldIn); + return worldIn.getRecipeManager().getRemainingItemsFor(recipeTypeIn, recipeInput, worldIn); } @Inject(method = "onTake", cancellable = true, at = @At("RETURN")) diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/TraitMixin_InventoryBridge_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/TraitMixin_InventoryBridge_Inventory.java index 572dedb3d32..259d84bbe9d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/TraitMixin_InventoryBridge_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/TraitMixin_InventoryBridge_Inventory.java @@ -36,6 +36,9 @@ import net.minecraft.world.inventory.ResultContainer; import net.minecraft.world.inventory.Slot; import net.minecraft.world.inventory.TransientCraftingContainer; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.item.crafting.SmithingRecipeInput; import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; import net.minecraft.world.level.block.entity.CampfireBlockEntity; import org.checkerframework.checker.nullness.qual.Nullable; @@ -67,7 +70,10 @@ ArmorStand.class, Mob.class, MerchantContainer.class, - CampfireBlockEntity.class + CampfireBlockEntity.class, + CraftingInput.class, + SingleRecipeInput.class, + SmithingRecipeInput.class }, targets = "net.minecraft.world.level.block.entity.LecternBlockEntity$1", priority = 999) public abstract class TraitMixin_InventoryBridge_Inventory implements InventoryAdapter, InventoryBridge { diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/inventory/HorseInventoryMenuMixin_TrackedMenuBridge_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/inventory/HorseInventoryMenuMixin_TrackedMenuBridge_Inventory.java index a87d5e1e19d..4566094a93a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/inventory/HorseInventoryMenuMixin_TrackedMenuBridge_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/inventory/HorseInventoryMenuMixin_TrackedMenuBridge_Inventory.java @@ -39,7 +39,7 @@ public abstract class HorseInventoryMenuMixin_TrackedMenuBridge_Inventory { @Inject(method = "", at = @At("RETURN")) - private void inventory$attachContainerMenu(final int $$0, final Inventory $$1, final Container $$2, final AbstractHorse $$3, final CallbackInfo ci) { + private void inventory$attachContainerMenu(final int $$0, final Inventory $$1, final Container $$2, final AbstractHorse $$3, final int $$4, final CallbackInfo ci) { if ($$1 instanceof final TrackedMenuBridge trackedMenu) { trackedMenu.bridge$trackContainerMenu((AbstractContainerMenu) (Object) this); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/item/crafting/RecipeInputMixin_Fabric_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/item/crafting/RecipeInputMixin_Fabric_Inventory.java new file mode 100644 index 00000000000..3f73f9fe953 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/impl/world/item/crafting/RecipeInputMixin_Fabric_Inventory.java @@ -0,0 +1,34 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.impl.world.item.crafting; + +import net.minecraft.world.item.crafting.RecipeInput; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.bridge.world.inventory.InventoryBridge; +import org.spongepowered.common.inventory.fabric.UniversalFabric; + +@Mixin(RecipeInput.class) +public interface RecipeInputMixin_Fabric_Inventory extends UniversalFabric, InventoryBridge { +} diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 9c5a55ff9f3..e7459b34a51 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -200,6 +200,7 @@ "world.item.crafting.ShapelessRecipe_SerializerMixin", "world.item.crafting.ShapelessRecipeMixin", "world.item.crafting.SimpleCookingSerializerMixin", + "world.item.crafting.SimpleCraftingRecipeSerializerMixin", "world.item.crafting.SingleItemRecipeMixin", "world.item.crafting.SmithingTransformRecipe_SerializerMixin", "world.item.crafting.SmithingTransformRecipeMixin", diff --git a/src/mixins/resources/mixins.sponge.inventory.json b/src/mixins/resources/mixins.sponge.inventory.json index 2b5606a39d9..f857d68d370 100644 --- a/src/mixins/resources/mixins.sponge.inventory.json +++ b/src/mixins/resources/mixins.sponge.inventory.json @@ -30,7 +30,8 @@ "api.world.inventory.AnvilMenuMixin_BlockCarrier_Inventory_API", "api.world.inventory.BrewingStandMenu_PotionSlotMixin_Inventory_API", "api.world.inventory.CartographyTableMenu_5Mixin_Inventory_API", - "api.world.inventory.TransientCraftingContainerMixin_Inventory_API", + "api.world.inventory.CrafterBlockBlockEntityMixin_Inventory_API", + "api.world.inventory.CraftingContainerMixin_Inventory_API", "api.world.inventory.CraftingMenuMixin_BlockCarrier_Inventory_API", "api.world.inventory.EnchantmentMenuMixin_BlockCarrier_Inventory_API", "api.world.inventory.FurnaceResultSlotMixin_Inventory_API", @@ -42,6 +43,11 @@ "api.world.inventory.SlotMixin_Inventory_API", "api.world.inventory.StonecutterMenu_2Mixin_Inventory_API", "api.world.inventory.StonecutterMenuMixin_BlockCarrier_Inventory_API", + "api.world.inventory.TransientCraftingContainerMixin_Inventory_API", + "api.world.item.crafting.CraftingInputMixin_Inventory_API", + "api.world.item.crafting.RecipeInputMixin_Inventory_API", + "api.world.item.crafting.SingleRecipeInputMixin_Inventory_API", + "api.world.item.crafting.SmithingRecipeInputMixin_Inventory_API", "api.world.level.block.entity.BaseContainerBlockEntityMixin_Carried_Inventory_API", "api.world.level.block.entity.BaseContainerBlockEntityMixin_Carrier_Inventory_API", "api.world.level.block.entity.CampfireBlockEntityMixin_Carried_Inventory_API", @@ -99,6 +105,7 @@ "impl.world.inventory.SlotMixin_Fabric_Inventory", "impl.world.inventory.SlotMixin_Lens_Inventory", "impl.world.inventory.StonecutterMenuMixin_TrackedMenuBridge_Inventory", + "impl.world.item.crafting.RecipeInputMixin_Fabric_Inventory", "impl.world.level.block.entity.CampfireBlockEntityMixin_Fabric_Inventory" ], "injectors": { diff --git a/src/mixins/resources/mixins.sponge.optimization.json b/src/mixins/resources/mixins.sponge.optimization.json index 015fd26b7f0..1500e429cc4 100644 --- a/src/mixins/resources/mixins.sponge.optimization.json +++ b/src/mixins/resources/mixins.sponge.optimization.json @@ -3,7 +3,6 @@ "package": "org.spongepowered.common.mixin.optimization", "plugin": "org.spongepowered.common.mixin.plugin.OptimizationPlugin", "mixins": [ - "general.DataFixersMixin_Optimization_LazyDFU", "world.entity.TamableAnimalMixin_Optimization_Owner", "world.level.block.entity.BellBlockEntityMixin_Optimization_BellLeak" ] diff --git a/testplugins/src/main/java/org/spongepowered/test/recipe/RecipeTest.java b/testplugins/src/main/java/org/spongepowered/test/recipe/RecipeTest.java index ba2d2ea9f80..2fb84f4a299 100644 --- a/testplugins/src/main/java/org/spongepowered/test/recipe/RecipeTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/recipe/RecipeTest.java @@ -232,13 +232,13 @@ private void onRecipeRegistry(final RegisterDataPackValueEvent hardnessPredicate = stack -> stack.type().block().map(b -> b.defaultState().get(Keys.DESTROY_SPEED).orElse(0d) > 20).orElse(false); // e.g. obsidian - final Ingredient hardBlock = Ingredient.of(ResourceKey.of(this.plugin, "hardblock"), hardnessPredicate, ItemStack.of(ItemTypes.BEDROCK)); + final Ingredient hardBlock = Ingredient.of(ResourceKey.of(this.plugin, "hardblock"), hardnessPredicate, ItemStack.of(ItemTypes.OBSIDIAN)); final RecipeRegistration hardblockToWool = ShapelessCraftingRecipe.builder().addIngredients(hardBlock).result(ItemStack.of(ItemTypes.WHITE_WOOL)) .key(ResourceKey.of(this.plugin, "hardblock_to_wool")) @@ -318,16 +318,14 @@ private void onRecipeRegistry(final RegisterDataPackValueEvent cookedAnvilRecipe = SmeltingRecipe.builder().type(RecipeTypes.BLASTING) -// .ingredient(ItemTypes.IRON_BLOCK) -// .result(inv -> { -// return anvil.copy(); -// }, anvil.copy()) -// .key(ResourceKey.of(this.plugin, "cooked_anvil")) -// .build(); -// event.register(cookedAnvilRecipe); + // Custom results dont work well in cooking recipes + final ItemStack anvil = ItemStack.of(ItemTypes.DAMAGED_ANVIL); + final RecipeRegistration cookedAnvilRecipe = CookingRecipe.builder().type(RecipeTypes.BLASTING) + .ingredient(ItemTypes.IRON_BLOCK) + .result(inv -> anvil.copy(), anvil.copy()) + .key(ResourceKey.of(this.plugin, "cooked_anvil")) + .build(); + event.register(cookedAnvilRecipe); final RecipeRegistration cutPlanksRecipe = StoneCutterRecipe.builder() .ingredient(ItemTypes.OAK_PLANKS) @@ -341,26 +339,26 @@ private void onRecipeRegistry(final RegisterDataPackValueEvent { if (inv.capacity() != 9) { return false; } - final ItemType stick = inv.asGrid().peek(2,1).get().type(); + final var grid = inv.asGrid(); + final ItemType stick = grid.peek(1, 2).get().type(); if (!stick.isAnyOf(ItemTypes.STICK)) { return false; } - final ItemStack middleItem = inv.peekAt(1).get(); + final ItemStack middleItem = grid.peekAt(1).get(); - final ItemType type00 = inv.asGrid().peek(0,0).get().type(); - final ItemType type10 = inv.asGrid().peek(0,1).get().type(); - final ItemType type20 = inv.asGrid().peek(0,2).get().type(); + final ItemType type00 = grid.peek(0, 0).get().type(); + final ItemType type10 = grid.peek(1, 0).get().type(); + final ItemType type20 = grid.peek(2, 0).get().type(); - final ItemType type01 = inv.asGrid().peek(1,0).get().type(); - final ItemType type11 = inv.asGrid().peek(1,1).get().type(); - final ItemType type21 = inv.asGrid().peek(1,2).get().type(); + final ItemType type01 = grid.peek(0, 1).get().type(); + final ItemType type11 = grid.peek(1, 1).get().type(); + final ItemType type21 = grid.peek(2, 1).get().type(); if (type00 == type01 && type01 == type20 && type20 == type21 && type10 == type11) { if (type00.isAnyOf(ItemTypes.WHITE_WOOL)) { From cbafec869421b20352b464fdd1854f202921c401 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:29:27 +0200 Subject: [PATCH 045/226] Keys for auto spin attacks --- .../world/entity/LivingEntityAccessor.java | 2 ++ .../data/provider/entity/LivingData.java | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java index 34db3745efd..e759b0ff380 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java @@ -86,6 +86,8 @@ public interface LivingEntityAccessor { @Accessor("lastHurtByMob") @Nullable LivingEntity accessor$lastHurtByMob(); @Accessor("autoSpinAttackTicks") int accessor$autoSpinAttackTicks(); + @Accessor("autoSpinAttackDmg") float accessor$autoSpinAttackDmg(); + @Accessor("autoSpinAttackItemStack") ItemStack accessor$autoSpinAttackItemStack(); @Accessor("useItem") void accessor$useItem(final ItemStack useItem); diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java index 9ce8ade5d6b..3bcf5773cc6 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java @@ -82,7 +82,31 @@ public static void register(final DataProviderRegistrator registrator) { return false; } if (h instanceof final Player p) { - p.startAutoSpinAttack(SpongeTicks.toSaturatedIntOrInfinite(v)); + final var dmg = ((LivingEntityAccessor)h).accessor$autoSpinAttackDmg(); + final var stack = ((LivingEntityAccessor)h).accessor$autoSpinAttackItemStack(); + p.startAutoSpinAttack(SpongeTicks.toSaturatedIntOrInfinite(v), dmg == 0 ? 8.0F : dmg, stack); + return true; + } + return false; + }) + .create(Keys.AUTO_SPIN_ATTACK_DAMAGE) + .get(h -> (double) ((LivingEntityAccessor)h).accessor$autoSpinAttackDmg()) + .setAnd((h, v) -> { + if (h instanceof final Player p) { + final var stack = ((LivingEntityAccessor)h).accessor$autoSpinAttackItemStack(); + final var ticks = ((LivingEntityAccessor)h).accessor$autoSpinAttackTicks(); + p.startAutoSpinAttack(ticks, v.floatValue(), stack); + return true; + } + return false; + }) + .create(Keys.AUTO_SPIN_ATTACK_WEAPON) + .get(h -> ItemStackUtil.snapshotOf(((LivingEntityAccessor)h).accessor$autoSpinAttackItemStack())) + .setAnd((h, v) -> { + if (h instanceof final Player p) { + final var ticks = ((LivingEntityAccessor)h).accessor$autoSpinAttackTicks(); + final var dmg = ((LivingEntityAccessor)h).accessor$autoSpinAttackDmg(); + p.startAutoSpinAttack(ticks, dmg, ItemStackUtil.fromSnapshotToNative(v)); return true; } return false; From f5e9261428f051000350542f2feb63ccb18bc5a1 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 30 May 2024 16:27:13 +0200 Subject: [PATCH 046/226] arrow custom knockback --- .../resources/mixins.sponge.accessors.json | 1 - .../projectile/AbstractArrowBridge.java} | 13 +++---- .../provider/entity/AbstractArrowData.java | 7 ++-- .../entity/projectile/AbstractArrowMixin.java | 38 ++++++++++++++++--- 4 files changed, 41 insertions(+), 18 deletions(-) rename src/{accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractArrowAccessor.java => main/java/org/spongepowered/common/bridge/world/entity/projectile/AbstractArrowBridge.java} (78%) diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 1ba75a1b31d..59690c89180 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -110,7 +110,6 @@ "world.entity.npc.AbstractVillagerAccessor", "world.entity.player.AbilitiesAccessor", "world.entity.player.PlayerAccessor", - "world.entity.projectile.AbstractArrowAccessor", "world.entity.projectile.ArrowAccessor", "world.entity.projectile.EyeOfEnderAccessor", "world.entity.projectile.FireworkRocketEntityAccessor", diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractArrowAccessor.java b/src/main/java/org/spongepowered/common/bridge/world/entity/projectile/AbstractArrowBridge.java similarity index 78% rename from src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractArrowAccessor.java rename to src/main/java/org/spongepowered/common/bridge/world/entity/projectile/AbstractArrowBridge.java index abf2e59b4c5..3301fbc9a4c 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/projectile/AbstractArrowAccessor.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/projectile/AbstractArrowBridge.java @@ -22,15 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.accessor.world.entity.projectile; +package org.spongepowered.common.bridge.world.entity.projectile; -import net.minecraft.world.entity.projectile.AbstractArrow; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.checkerframework.checker.nullness.qual.Nullable; -@Mixin(AbstractArrow.class) -public interface AbstractArrowAccessor { - - @Accessor("knockback") int accessor$knockback(); +public interface AbstractArrowBridge { + double bridge$getKnockback(); + void bridge$setKnockback(@Nullable Double knockback); } diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractArrowData.java b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractArrowData.java index 582c3f42069..2ee80e000ee 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractArrowData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractArrowData.java @@ -27,7 +27,7 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.PickupRule; -import org.spongepowered.common.accessor.world.entity.projectile.AbstractArrowAccessor; +import org.spongepowered.common.bridge.world.entity.projectile.AbstractArrowBridge; import org.spongepowered.common.data.provider.DataProviderRegistrator; public final class AbstractArrowData { @@ -46,8 +46,9 @@ public static void register(final DataProviderRegistrator registrator) { .get(AbstractArrow::isCritArrow) .set(AbstractArrow::setCritArrow) .create(Keys.KNOCKBACK_STRENGTH) - .get(h -> (double) ((AbstractArrowAccessor) h).accessor$knockback()) - .set((h, v) -> h.setKnockback((int) Math.round(v))) + // TODO calculating the knockback strength now requires the target entity and damage source + .get(h -> ((AbstractArrowBridge) h).bridge$getKnockback()) + .set((h, v) -> ((AbstractArrowBridge) h).bridge$setKnockback(v)) .create(Keys.PICKUP_RULE) .get(h -> (PickupRule) (Object) h.pickup) .set((h, v) -> h.pickup = ((AbstractArrow.Pickup) (Object) v)); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/AbstractArrowMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/AbstractArrowMixin.java index 5796f8ed7da..6f91c80b19a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/AbstractArrowMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/AbstractArrowMixin.java @@ -25,6 +25,8 @@ package org.spongepowered.common.mixin.core.world.entity.projectile; import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; @@ -39,11 +41,12 @@ 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.common.bridge.world.entity.projectile.AbstractArrowBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; @Mixin(AbstractArrow.class) -public abstract class AbstractArrowMixin extends ProjectileMixin { +public abstract class AbstractArrowMixin extends ProjectileMixin implements AbstractArrowBridge { // @formatter:off @Shadow private int life; @@ -54,17 +57,30 @@ public abstract class AbstractArrowMixin extends ProjectileMixin { @Shadow public abstract void shadow$setCritArrow(boolean critical); @Shadow public abstract void shadow$setPierceLevel(byte level); - @Shadow public abstract void shadow$setShotFromCrossbow(boolean fromCrossbow); @Shadow protected abstract ItemStack shadow$getPickupItem(); @Shadow protected abstract void resetPiercedEntities(); - // @formatter:on + // @formatter:on + @Nullable private Double impl$customKnockback; // Not all ProjectileSources are entities (e.g. BlockProjectileSource). // This field is used to store a ProjectileSource that isn't an entity. @Nullable public ProjectileSource projectileSource; + @Override + public double bridge$getKnockback() { + if (this.impl$customKnockback != null) { + return this.impl$customKnockback; + } + return 0; + } + + @Override + public void bridge$setKnockback(@Nullable final Double knockback) { + this.impl$customKnockback = knockback; + } + /** * Collide impact event post for plugins to cancel impact. */ @@ -81,19 +97,29 @@ private void onProjectileHit(final BlockHitResult hitResult, final CallbackInfo final Vec3 vec3d = blockraytraceresult.getLocation().subtract(this.shadow$getX(), this.shadow$getY(), this.shadow$getZ()); this.shadow$setDeltaMovement(vec3d); final Vec3 vec3d1 = vec3d.normalize().scale(0.05F); - this.shadow$setPos(this.shadow$getX() - vec3d1.x, this.shadow$getY() - vec3d1.y, this.shadow$getZ() - - vec3d1.z); + this.shadow$setPos(this.shadow$getX() - vec3d1.x, this.shadow$getY() - vec3d1.y, this.shadow$getZ() - vec3d1.z); this.inGround = true; this.shakeTime = 7; this.shadow$setCritArrow(false); this.shadow$setPierceLevel((byte)0); - this.shadow$setShotFromCrossbow(false); this.resetPiercedEntities(); ci.cancel(); } } } + + @Inject(method = "doKnockback", at = @At("HEAD"), cancellable = true) + private void onProjectileHit(final LivingEntity hitEntity, final DamageSource $$1, final CallbackInfo ci) { + if (this.impl$customKnockback != null) { + Vec3 knockBackVector = this.shadow$getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(this.impl$customKnockback * 0.6); + if (knockBackVector.lengthSqr() > 0.0) { + hitEntity.push(knockBackVector.x, 0.1, knockBackVector.z); + } + ci.cancel(); + } + } + /** * Collide impact event post for plugins to cancel impact. */ From f1b9b62c328a53994b2b54aae59dd4067a4112b2 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Mon, 10 Jun 2024 16:16:32 +0200 Subject: [PATCH 047/226] Bump MC to 1.21-rc1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c75c62774b2..260c526f4c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21-pre4 +minecraftVersion=1.21-rc1 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose From 65ea727e1737e34f7aef47275e678082bb0c0673 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 13 Jun 2024 17:20:54 +0200 Subject: [PATCH 048/226] Bump MC to 1.21 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 260c526f4c6..b624ba50c6c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21-rc1 +minecraftVersion=1.21 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose From 93f63db735830c3b4ea6ca39719a8a829dfd1a14 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 13 Jun 2024 18:57:15 +0200 Subject: [PATCH 049/226] fix Enchantments loading later --- SpongeAPI | 2 +- .../common/item/recipe/SpongeRecipeRegistration.java | 4 +++- .../common/item/recipe/ingredient/SpongeIngredient.java | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index c72f815e30d..8dde7d606d8 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit c72f815e30dd3ac69f174a86ee5990c6579b9c4a +Subproject commit 8dde7d606d8e870243c9e04a7ebefbe298a23173 diff --git a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java index ea711e4797e..7688025bf6a 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java +++ b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeRegistration.java @@ -36,6 +36,7 @@ import net.minecraft.core.NonNullList; import net.minecraft.core.RegistryAccess; import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; @@ -152,7 +153,8 @@ public static JsonObject encode(RecipeRegistration template, RegistryAccess acce if (template instanceof SpongeRecipeRegistration srr) { srr.ensureCached(); } - final DataResult encoded = Recipe.CODEC.encodeStart(JsonOps.INSTANCE, (Recipe) template.recipe()); + final var ops = RegistryOps.create(JsonOps.INSTANCE, access); + final DataResult encoded = Recipe.CODEC.encodeStart(ops, (Recipe) template.recipe()); if (encoded.result().isPresent()) { return encoded.result().get().getAsJsonObject(); } diff --git a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java index e0c5ba23f01..8f3cbb0ef54 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java +++ b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java @@ -190,7 +190,8 @@ public void setPredicate(final Predicate predicate) { @Override public boolean test(final ItemStack itemStack) { if (this.predicate == null) { - throw new IllegalStateException(key + " predicate was not registered. Is the plugin loaded?"); + SpongeCommon.logger().error(key + " ingredient predicate was not registered. Is the plugin loaded?"); + return false; } return this.predicate.test(itemStack); } From de14abf9f0da72486c29e41c22972b144fde5c4d Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 14 Jun 2024 21:09:47 +0200 Subject: [PATCH 050/226] TrialSpawner and Crafter --- SpongeAPI | 2 +- .../world/level/BaseSpawnerAccessor.java | 1 + .../level/block/CrafterBlockAccessor.java | 43 ++++++++ .../entity/CrafterBlockEntityAccessor.java | 36 ++++++ .../trialspawner/TrialSpawnerAccessor.java | 38 +++++++ .../TrialSpawnerDataAccessor.java | 53 +++++++++ .../resources/mixins.sponge.accessors.json | 6 +- .../entity/BlockEntityDataProviders.java | 2 + .../provider/block/entity/CrafterData.java | 47 ++++++++ .../provider/block/entity/MobSpawnerData.java | 104 +----------------- .../entity/TrialSpawnerDataProvider.java | 102 +++++++++++++++++ .../common/entity/EntityUtil.java | 76 +++++++++++++ .../block/entity/BlockEntityMixin_API.java | 5 +- .../TrialSpawnerBlockEntityMixin_API.java | 69 ++++++++++++ ...erBlockBlockEntityMixin_Inventory_API.java | 61 +++++++++- src/mixins/resources/mixins.sponge.api.json | 1 + 16 files changed, 543 insertions(+), 103 deletions(-) create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/block/CrafterBlockAccessor.java create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/CrafterBlockEntityAccessor.java create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerAccessor.java create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerDataAccessor.java create mode 100644 src/main/java/org/spongepowered/common/data/provider/block/entity/CrafterData.java create mode 100644 src/main/java/org/spongepowered/common/data/provider/block/entity/TrialSpawnerDataProvider.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/TrialSpawnerBlockEntityMixin_API.java diff --git a/SpongeAPI b/SpongeAPI index 8dde7d606d8..a24c980aa55 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 8dde7d606d8e870243c9e04a7ebefbe298a23173 +Subproject commit a24c980aa5541cd876670a535d78331ae0dcde37 diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/BaseSpawnerAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/BaseSpawnerAccessor.java index 5b9e555e51d..594ce45ca9d 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/level/BaseSpawnerAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/BaseSpawnerAccessor.java @@ -42,6 +42,7 @@ public interface BaseSpawnerAccessor { @Accessor("spawnPotentials") void accessor$spawnPotentials(SimpleWeightedRandomList newData); @Accessor("nextSpawnData") SpawnData accessor$nextSpawnData(); + @Accessor("nextSpawnData") void accessor$nextSpawnData(SpawnData spawnData); @Accessor("minSpawnDelay") int accessor$minSpawnDelay(); diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/CrafterBlockAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/CrafterBlockAccessor.java new file mode 100644 index 00000000000..9ce9a5a2cb2 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/CrafterBlockAccessor.java @@ -0,0 +1,43 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.level.block.CrafterBlock; +import net.minecraft.world.level.block.entity.CrafterBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(CrafterBlock.class) +public interface CrafterBlockAccessor { + + @Invoker("dispenseItem") void invoker$dispenseItem(ServerLevel $$0, BlockPos $$1, CrafterBlockEntity $$2, ItemStack $$3, BlockState $$4, RecipeHolder $$5); + +} diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/CrafterBlockEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/CrafterBlockEntityAccessor.java new file mode 100644 index 00000000000..11890e69737 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/CrafterBlockEntityAccessor.java @@ -0,0 +1,36 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.block.entity; + +import net.minecraft.world.level.block.entity.CrafterBlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CrafterBlockEntity.class) +public interface CrafterBlockEntityAccessor { + + @Accessor("craftingTicksRemaining") int accessor$craftingTicksRemaining(); + +} diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerAccessor.java new file mode 100644 index 00000000000..2b34f3284d2 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerAccessor.java @@ -0,0 +1,38 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.block.entity.trialspawner; + +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(TrialSpawner.class) +public interface TrialSpawnerAccessor { + + @Mutable @Accessor("normalConfig") void accessor$normalConfig(TrialSpawnerConfig normalConfig); + @Mutable @Accessor("ominousConfig") void accessor$ominousConfig(TrialSpawnerConfig ominousConfig); +} diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerDataAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerDataAccessor.java new file mode 100644 index 00000000000..f5de3ae6590 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/block/entity/trialspawner/TrialSpawnerDataAccessor.java @@ -0,0 +1,53 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.block.entity.trialspawner; + +import net.minecraft.world.level.SpawnData; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +@Mixin(TrialSpawnerData.class) +public interface TrialSpawnerDataAccessor { + + @Accessor("nextSpawnData") Optional accessor$nextSpawnData(); + + @Accessor("nextSpawnData") void accessor$nextSpawnData(Optional nextSpawnData); + + @Accessor("nextMobSpawnsAt") long accessor$nextMobSpawnsAt(); + + @Accessor("nextMobSpawnsAt") void accessor$nextMobSpawnsAt(long nextMobSpawnsAt); + + + @Accessor("currentMobs") Set accessor$currentMobs(); + @Accessor("totalMobsSpawned") int accessor$totalMobsSpawned(); + + @Accessor("totalMobsSpawned") void accessor$totalMobsSpawned(int totalMobsSpawned); + +} diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 59690c89180..d27fcfb8463 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -138,7 +138,7 @@ "world.inventory.StonecutterMenuAccessor", "world.item.AdventureModePredicateAccessor", "world.item.ItemCooldowns_CooldownInstanceAccessor", - "world.item.component.CustomDataAccessor", + "world.item.component.CustomDataAccessor", "world.item.enchantment.ItemEnchantmentsAccessor", "world.item.trading.MerchantOfferAccessor", "world.level.BaseCommandBlockAccessor", @@ -159,6 +159,7 @@ "world.level.block.AbstractSkullBlockAccessor", "world.level.block.BaseFireBlockAccessor", "world.level.block.BedBlockAccessor", + "world.level.block.CrafterBlockAccessor", "world.level.block.CropBlockAccessor", "world.level.block.DispenserBlockAccessor", "world.level.block.EnderChestBlockAccessor", @@ -168,6 +169,7 @@ "world.level.block.entity.BlockEntityAccessor", "world.level.block.entity.BrewingStandBlockEntityAccessor", "world.level.block.entity.ConduitBlockEntityAccessor", + "world.level.block.entity.CrafterBlockEntityAccessor", "world.level.block.entity.EnchantingTableBlockEntityAccessor", "world.level.block.entity.HopperBlockEntityAccessor", "world.level.block.entity.LecternBlockEntity_Accessor", @@ -175,6 +177,8 @@ "world.level.block.entity.SpawnerBlockEntityAccessor", "world.level.block.entity.StructureBlockEntityAccessor", "world.level.block.entity.TheEndGatewayBlockEntityAccessor", + "world.level.block.entity.trialspawner.TrialSpawnerAccessor", + "world.level.block.entity.trialspawner.TrialSpawnerDataAccessor", "world.level.block.piston.PistonBaseBlockAccessor", "world.level.block.state.BlockBehaviour_PropertiesAccessor", "world.level.block.state.BlockBehaviourAccessor", diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/BlockEntityDataProviders.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/BlockEntityDataProviders.java index a38a73a0fa7..4b52eafe371 100644 --- a/src/main/java/org/spongepowered/common/data/provider/block/entity/BlockEntityDataProviders.java +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/BlockEntityDataProviders.java @@ -42,8 +42,10 @@ public void registerProviders() { LecternData.register(this.registrator); LockableData.register(this.registrator); MobSpawnerData.register(this.registrator); + TrialSpawnerDataProvider.register(this.registrator); SignData.register(this.registrator); SkullData.register(this.registrator); StructureBlockData.register(this.registrator); + CrafterData.register(this.registrator); } } diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/CrafterData.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/CrafterData.java new file mode 100644 index 00000000000..39bb846a058 --- /dev/null +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/CrafterData.java @@ -0,0 +1,47 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.data.provider.block.entity; + +import net.minecraft.world.level.block.entity.CrafterBlockEntity; +import org.spongepowered.api.data.Keys; +import org.spongepowered.common.accessor.world.level.block.entity.CrafterBlockEntityAccessor; +import org.spongepowered.common.data.provider.DataProviderRegistrator; +import org.spongepowered.common.util.SpongeTicks; + +public final class CrafterData { + + private CrafterData() { + } + + // @formatter:off + public static void register(final DataProviderRegistrator registrator) { + registrator + .asMutable(CrafterBlockEntity.class) + .create(Keys.COOLDOWN) + .get(h -> new SpongeTicks(((CrafterBlockEntityAccessor)h).accessor$craftingTicksRemaining())) + .set((h, v) -> h.setCraftingTicksRemaining(SpongeTicks.toSaturatedIntOrInfinite(v))); + } + // @formatter:on +} diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java index 8188239c476..5fef8d45694 100644 --- a/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/MobSpawnerData.java @@ -24,36 +24,13 @@ */ package org.spongepowered.common.data.provider.block.entity; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.random.SimpleWeightedRandomList; -import net.minecraft.util.random.WeightedEntry; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.SpawnData; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import org.spongepowered.api.ResourceKey; import org.spongepowered.api.data.Keys; -import org.spongepowered.api.entity.EntityArchetype; -import org.spongepowered.api.entity.EntityType; -import org.spongepowered.api.entity.EntityTypes; -import org.spongepowered.api.util.weighted.TableEntry; -import org.spongepowered.api.util.weighted.WeightedObject; -import org.spongepowered.api.util.weighted.WeightedSerializableObject; -import org.spongepowered.api.util.weighted.WeightedTable; -import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.accessor.world.level.BaseSpawnerAccessor; import org.spongepowered.common.accessor.world.level.block.entity.SpawnerBlockEntityAccessor; -import org.spongepowered.common.bridge.world.level.BaseSpawnerBridge; -import org.spongepowered.common.data.persistence.NBTTranslator; import org.spongepowered.common.data.provider.DataProviderRegistrator; -import org.spongepowered.common.entity.SpongeEntityArchetypeBuilder; -import org.spongepowered.common.util.Constants; +import org.spongepowered.common.entity.EntityUtil; import org.spongepowered.common.util.SpongeTicks; -import java.util.Optional; - public final class MobSpawnerData { private MobSpawnerData() { @@ -85,8 +62,8 @@ public static void register(final DataProviderRegistrator registrator) { return true; }) .create(Keys.NEXT_ENTITY_TO_SPAWN) - .get(h -> MobSpawnerData.getNextEntity((BaseSpawnerAccessor) h.accessor$spawner())) - .set((h, v) -> MobSpawnerData.setNextEntity((SpawnerBlockEntity) h, v)) + .get(h -> EntityUtil.toArchetype(((BaseSpawnerAccessor) h.accessor$spawner()).accessor$nextSpawnData())) + .set((h, v) -> ((BaseSpawnerAccessor)h.accessor$spawner()).accessor$nextSpawnData(EntityUtil.toSpawnData(v))) .create(Keys.REMAINING_SPAWN_DELAY) .get(h -> new SpongeTicks(((BaseSpawnerAccessor) h.accessor$spawner()).accessor$spawnDelay())) .setAnd((h, v) -> { @@ -106,82 +83,13 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> (double) ((BaseSpawnerAccessor) h.accessor$spawner()).accessor$spawnRange()) .set((h, v) -> ((BaseSpawnerAccessor) h.accessor$spawner()).accessor$spawnRange(v.intValue())) .create(Keys.SPAWNABLE_ENTITIES) - .get(h -> MobSpawnerData.getEntities(h.accessor$spawner())) + .get(h -> EntityUtil.toWeightedArchetypes(((BaseSpawnerAccessor)h.accessor$spawner()).accessor$spawnPotentials())) .set((h, v) -> { final BaseSpawnerAccessor logic = (BaseSpawnerAccessor) h.accessor$spawner(); - MobSpawnerData.setEntities(logic, v); - MobSpawnerData.setNextEntity((SpawnerBlockEntity) h, MobSpawnerData.getNextEntity(logic)); + logic.accessor$spawnPotentials(EntityUtil.toSpawnPotentials(v)); + logic.accessor$nextSpawnData(null); // Reset next entity spawn }); } // @formatter:on - private static WeightedSerializableObject getNextEntity(final BaseSpawnerAccessor logic) { - //TODO next entity doesn't have a weight but the api key needs to be changed - final int weight = 1; //((WeighedRandom_WeighedRandomItemAccessor) logic.accessor$nextSpawnData()).accessor$weight(); - - final String resourceLocation = logic.accessor$nextSpawnData().entityToSpawn().getString(Constants.Entity.ENTITY_TYPE_ID); - final Registry> entityTypeRegistry = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE); - final EntityType type = entityTypeRegistry.getOptional(ResourceLocation.parse(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); - - final CompoundTag data = logic.accessor$nextSpawnData().entityToSpawn(); - - final EntityArchetype archetype = SpongeEntityArchetypeBuilder.pooled() - .type(type) - .entityData(NBTTranslator.INSTANCE.translateFrom(data)) - .build(); - - return new WeightedSerializableObject<>(archetype, weight); - } - - private static void setNextEntity(final SpawnerBlockEntity entity, final WeightedSerializableObject value) { - final CompoundTag compound = NBTTranslator.INSTANCE.translate(value.get().entityData()); - if (!compound.contains(Constants.Entity.ENTITY_TYPE_ID)) { - final ResourceKey key = (ResourceKey) (Object) net.minecraft.world.entity.EntityType.getKey((net.minecraft.world.entity.EntityType) value.get() - .type()); - compound.putString(Constants.Entity.ENTITY_TYPE_ID, key.toString()); - } - - ((BaseSpawnerBridge) entity.getSpawner()).bridge$setNextSpawnData(entity.getLevel(), entity.getBlockPos(), new SpawnData(compound, Optional.empty(), Optional.empty())); - } - - private static WeightedTable getEntities(final BaseSpawner logic) { - final WeightedTable possibleEntities = new WeightedTable<>(); - for (final WeightedEntry.Wrapper weightedEntity : ((BaseSpawnerAccessor) logic).accessor$spawnPotentials().unwrap()) { - - final CompoundTag nbt = weightedEntity.data().entityToSpawn(); - - final String resourceLocation = nbt.getString(Constants.Entity.ENTITY_TYPE_ID); - final Registry> entityTypeRegistry = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE); - final EntityType type = entityTypeRegistry.getOptional(ResourceLocation.parse(resourceLocation)).map(EntityType.class::cast).orElse(EntityTypes.PIG.get()); - - final EntityArchetype archetype = SpongeEntityArchetypeBuilder.pooled() - .type(type) - .entityData(NBTTranslator.INSTANCE.translateFrom(nbt)) - .build(); - - possibleEntities.add(new WeightedSerializableObject<>(archetype, weightedEntity.getWeight().asInt())); - } - - return possibleEntities; - } - - private static void setEntities(final BaseSpawnerAccessor logic, final WeightedTable table) { - final SimpleWeightedRandomList.Builder builder = SimpleWeightedRandomList.builder(); - for (final TableEntry entry : table) { - if (!(entry instanceof WeightedObject)) { - continue; - } - final WeightedObject object = (WeightedObject) entry; - - final CompoundTag compound = NBTTranslator.INSTANCE.translate(object.get().entityData()); - if (!compound.contains(Constants.Entity.ENTITY_TYPE_ID)) { - final ResourceKey key = (ResourceKey) (Object) net.minecraft.world.entity.EntityType.getKey((net.minecraft.world.entity.EntityType) object - .get().type()); - compound.putString(Constants.Entity.ENTITY_TYPE_ID, key.toString()); - } - - builder.add(new SpawnData(compound, Optional.empty(), Optional.empty()), (int) entry.weight()); - } - logic.accessor$spawnPotentials(builder.build()); - } } diff --git a/src/main/java/org/spongepowered/common/data/provider/block/entity/TrialSpawnerDataProvider.java b/src/main/java/org/spongepowered/common/data/provider/block/entity/TrialSpawnerDataProvider.java new file mode 100644 index 00000000000..2c8195bd761 --- /dev/null +++ b/src/main/java/org/spongepowered/common/data/provider/block/entity/TrialSpawnerDataProvider.java @@ -0,0 +1,102 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.data.provider.block.entity; + +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig; +import org.spongepowered.api.data.Keys; +import org.spongepowered.common.accessor.world.level.block.entity.trialspawner.TrialSpawnerAccessor; +import org.spongepowered.common.accessor.world.level.block.entity.trialspawner.TrialSpawnerDataAccessor; +import org.spongepowered.common.data.provider.DataProviderRegistrator; +import org.spongepowered.common.entity.EntityUtil; +import org.spongepowered.common.util.SpongeTicks; + +import java.util.Optional; + +public final class TrialSpawnerDataProvider { + + private TrialSpawnerDataProvider() { + } + + // @formatter:off + public static void register(final DataProviderRegistrator registrator) { + registrator + .asMutable(TrialSpawnerBlockEntity.class) + .create(Keys.MAX_NEARBY_ENTITIES) + .get(h -> h.getTrialSpawner().getConfig().calculateTargetSimultaneousMobs(h.getTrialSpawner().getData().countAdditionalPlayers(h.getBlockPos()))) + .create(Keys.NEXT_ENTITY_TO_SPAWN) + .get(h -> ((TrialSpawnerDataAccessor) h.getTrialSpawner().getData()).accessor$nextSpawnData().map(EntityUtil::toArchetype).orElse(null)) + .set((h, v) -> ((TrialSpawnerDataAccessor) h.getTrialSpawner().getData()).accessor$nextSpawnData(Optional.of(EntityUtil.toSpawnData(v)))) + .delete(h -> ((TrialSpawnerDataAccessor) h.getTrialSpawner().getData()).accessor$nextSpawnData(Optional.empty())) + .create(Keys.REMAINING_SPAWN_DELAY) + .get(h -> new SpongeTicks(((TrialSpawnerDataAccessor) h.getTrialSpawner().getData()).accessor$nextMobSpawnsAt() - h.getLevel().getGameTime())) + .setAnd((h, v) -> { + if (v.isInfinite()) { + return false; + } + ((TrialSpawnerDataAccessor) h.getTrialSpawner().getData()).accessor$nextMobSpawnsAt(h.getLevel().getGameTime() + v.ticks()); + return true; + }) + .create(Keys.SPAWN_RANGE) + .get(h -> (double) h.getTrialSpawner().getConfig().spawnRange()) + .set((h, v) -> { + final var normalConfig = h.getTrialSpawner().getNormalConfig(); + final var ominousConfig = h.getTrialSpawner().getOminousConfig(); + final var newNormalConfig = new TrialSpawnerConfig(v.intValue(), normalConfig.totalMobs(), normalConfig.simultaneousMobs(), normalConfig.totalMobsAddedPerPlayer(), normalConfig.simultaneousMobsAddedPerPlayer(), normalConfig.ticksBetweenSpawn(), normalConfig.spawnPotentialsDefinition(), normalConfig.lootTablesToEject(), normalConfig.itemsToDropWhenOminous()); + final var newOminiousConfig = new TrialSpawnerConfig(v.intValue(), ominousConfig.totalMobs(), ominousConfig.simultaneousMobs(), ominousConfig.totalMobsAddedPerPlayer(), ominousConfig.simultaneousMobsAddedPerPlayer(), ominousConfig.ticksBetweenSpawn(), ominousConfig.spawnPotentialsDefinition(), ominousConfig.lootTablesToEject(), ominousConfig.itemsToDropWhenOminous()); + + final var accessor = (TrialSpawnerAccessor) (Object) h.getTrialSpawner(); + accessor.accessor$normalConfig(newNormalConfig); + accessor.accessor$ominousConfig(newOminiousConfig); + }) + // TODO totalMobs + // TODO simultaneousMobs + // TODO totalMobsAddedPerPlayer + // TODO simultaneousMobsAddedPerPlayer + .create(Keys.MAX_SPAWN_DELAY) + .get(h -> new SpongeTicks(h.getTrialSpawner().getConfig().ticksBetweenSpawn())) + // TODO set ticksBetweenSpawn + .create(Keys.MIN_SPAWN_DELAY) + .get(h -> new SpongeTicks(h.getTrialSpawner().getConfig().ticksBetweenSpawn())) + .create(Keys.SPAWNABLE_ENTITIES) + .get(h -> EntityUtil.toWeightedArchetypes(h.getTrialSpawner().getConfig().spawnPotentialsDefinition())) + .set((h, v) -> { + final var spawnPotentials = EntityUtil.toSpawnPotentials(v); + + final var normalConfig = h.getTrialSpawner().getNormalConfig(); + final var ominousConfig = h.getTrialSpawner().getOminousConfig(); + final var newNormalConfig = new TrialSpawnerConfig(normalConfig.spawnRange(), normalConfig.totalMobs(), normalConfig.simultaneousMobs(), normalConfig.totalMobsAddedPerPlayer(), normalConfig.simultaneousMobsAddedPerPlayer(), normalConfig.ticksBetweenSpawn(), spawnPotentials, normalConfig.lootTablesToEject(), normalConfig.itemsToDropWhenOminous()); + final var newOminiousConfig = new TrialSpawnerConfig(ominousConfig.spawnRange(), ominousConfig.totalMobs(), ominousConfig.simultaneousMobs(), ominousConfig.totalMobsAddedPerPlayer(), ominousConfig.simultaneousMobsAddedPerPlayer(), ominousConfig.ticksBetweenSpawn(), spawnPotentials, ominousConfig.lootTablesToEject(), ominousConfig.itemsToDropWhenOminous()); + + final var accessor = (TrialSpawnerAccessor) (Object) h.getTrialSpawner(); + accessor.accessor$normalConfig(newNormalConfig); + accessor.accessor$ominousConfig(newOminiousConfig); + }); + // TODO lootTablesToEject + // TODO itemsToDropWhenOminous + } + // @formatter:on + +} diff --git a/src/main/java/org/spongepowered/common/entity/EntityUtil.java b/src/main/java/org/spongepowered/common/entity/EntityUtil.java index fc2b54c7df8..88f37ace57f 100644 --- a/src/main/java/org/spongepowered/common/entity/EntityUtil.java +++ b/src/main/java/org/spongepowered/common/entity/EntityUtil.java @@ -24,19 +24,35 @@ */ package org.spongepowered.common.entity; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; +import net.minecraft.util.random.SimpleWeightedRandomList; +import net.minecraft.util.random.WeightedEntry; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.SpawnData; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.EntityArchetype; +import org.spongepowered.api.entity.EntityTypes; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.entity.SpawnEntityEvent; +import org.spongepowered.api.util.weighted.WeightedObject; +import org.spongepowered.api.util.weighted.WeightedSerializableObject; +import org.spongepowered.api.util.weighted.WeightedTable; +import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.accessor.world.entity.EntityAccessor; import org.spongepowered.common.bridge.CreatorTrackedBridge; import org.spongepowered.common.bridge.data.VanishableBridge; +import org.spongepowered.common.data.persistence.NBTTranslator; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.hooks.PlatformHooks; +import org.spongepowered.common.util.Constants; import org.spongepowered.math.vector.Vector3d; import java.util.ArrayList; @@ -165,4 +181,64 @@ public static boolean isUntargetable(final Entity from, final Entity target) { // Temporary fix for https://bugs.mojang.com/browse/MC-149563 return from.level() != target.level(); } + + public static EntityArchetype toArchetype(final SpawnData logic) { + final var tag = logic.entityToSpawn(); + final var resourceLocation = tag.getString(Constants.Entity.ENTITY_TYPE_ID); + final var entityTypeRegistry = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE); + final var type = entityTypeRegistry.getOptional(ResourceLocation.parse(resourceLocation)) + .map(org.spongepowered.api.entity.EntityType.class::cast) + .orElse(EntityTypes.PIG.get()); + + return SpongeEntityArchetypeBuilder.pooled() + .type(type) + .entityData(NBTTranslator.INSTANCE.translateFrom(tag)) + .build(); + } + + public static SpawnData toSpawnData(final EntityArchetype value) { + final var tag = NBTTranslator.INSTANCE.translate(value.entityData()); + if (!tag.contains(Constants.Entity.ENTITY_TYPE_ID)) { + final ResourceKey key = (ResourceKey) (Object) EntityType.getKey((EntityType) value.type()); + tag.putString(Constants.Entity.ENTITY_TYPE_ID, key.toString()); + } + + // TODO customSpawnRules & equipment support + return new SpawnData(tag, Optional.empty(), Optional.empty()); + } + + public static WeightedTable toWeightedArchetypes(final SimpleWeightedRandomList spawnData) { + final WeightedTable possibleEntities = new WeightedTable<>(); + + for (final WeightedEntry.Wrapper weightedEntity : spawnData.unwrap()) { + final CompoundTag nbt = weightedEntity.data().entityToSpawn(); + final String resourceLocation = nbt.getString(Constants.Entity.ENTITY_TYPE_ID); + final var mcType = SpongeCommon.vanillaRegistry(Registries.ENTITY_TYPE).getOptional(ResourceLocation.parse(resourceLocation)); + final var type = mcType.map(org.spongepowered.api.entity.EntityType.class::cast).orElse(EntityTypes.PIG.get()); + + final EntityArchetype archetype = SpongeEntityArchetypeBuilder.pooled() + .type(type) + .entityData(NBTTranslator.INSTANCE.translateFrom(nbt)) + .build(); + + possibleEntities.add(new WeightedSerializableObject<>(archetype, weightedEntity.getWeight().asInt())); + } + return possibleEntities; + } + + public static SimpleWeightedRandomList toSpawnPotentials(final WeightedTable table) { + final SimpleWeightedRandomList.Builder builder = SimpleWeightedRandomList.builder(); + for (final var entry : table) { + if (entry instanceof final WeightedObject weightedObj) { + final var tag = NBTTranslator.INSTANCE.translate(weightedObj.get().entityData()); + if (!tag.contains(Constants.Entity.ENTITY_TYPE_ID)) { + final var key = EntityType.getKey((EntityType) weightedObj.get().type()); + tag.putString(Constants.Entity.ENTITY_TYPE_ID, key.toString()); + } + // TODO customSpawnRules & equipment support + builder.add(new SpawnData(tag, Optional.empty(), Optional.empty()), (int) entry.weight()); + } + } + return builder.build(); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java index e17fe5ef9a8..e8b754eeced 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java @@ -63,12 +63,13 @@ public abstract class BlockEntityMixin_API implements BlockEntity { @Shadow @Final private net.minecraft.world.level.block.entity.BlockEntityType type; @Shadow protected net.minecraft.world.level.Level level; @Shadow protected boolean remove; - @Shadow public abstract BlockPos shadow$getBlockPos(); @Shadow public abstract CompoundTag shadow$saveWithFullMetadata(HolderLookup.Provider $$0); + @Shadow @Final protected BlockPos worldPosition; + @Shadow public abstract net.minecraft.world.level.block.state.BlockState shadow$getBlockState(); + @Shadow public abstract void shadow$setChanged(); //@formatter:on - @Shadow @Final protected BlockPos worldPosition; @Nullable private LocatableBlock api$LocatableBlock; public ServerLocation location() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/TrialSpawnerBlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/TrialSpawnerBlockEntityMixin_API.java new file mode 100644 index 00000000000..28f49bdd338 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/TrialSpawnerBlockEntityMixin_API.java @@ -0,0 +1,69 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.level.block.entity; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import org.spongepowered.api.block.entity.TrialSpawner; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.accessor.world.level.block.entity.trialspawner.TrialSpawnerDataAccessor; + +import java.util.Optional; + +@Mixin(TrialSpawnerBlockEntity.class) +public abstract class TrialSpawnerBlockEntityMixin_API extends BlockEntityMixin_API implements TrialSpawner { + + @Shadow public abstract net.minecraft.world.level.block.entity.trialspawner.TrialSpawner getTrialSpawner(); + + @Override + public void spawnImmediately(final boolean force) { + if (this.level.isClientSide) { + return; + } + final var thisLevel = (ServerLevel) this.level; + final var spawner = this.getTrialSpawner(); + final var spawnerData = (TrialSpawnerDataAccessor) spawner.getData(); + final var spawnerConfig = spawner.getConfig(); + + final var additionalPlayers = spawner.getData().countAdditionalPlayers(this.worldPosition); + final var nextSpawnAt = spawnerData.accessor$nextMobSpawnsAt(); + spawnerData.accessor$nextMobSpawnsAt(0); + if (force || spawner.getData().isReadyToSpawnNextMob(thisLevel, spawnerConfig, additionalPlayers)) { + // See TrialSpawnerState#tickAndGetNext + spawner.spawnMob(thisLevel, this.worldPosition).ifPresent(spawned -> { + spawnerData.accessor$currentMobs().add(spawned); + spawnerData.accessor$totalMobsSpawned(spawnerData.accessor$totalMobsSpawned() + 1); + spawnerData.accessor$nextMobSpawnsAt(this.level.getGameTime() + (long) spawnerConfig.ticksBetweenSpawn()); + spawnerConfig.spawnPotentialsDefinition().getRandom(this.level.getRandom()).ifPresent(next -> { + spawnerData.accessor$nextSpawnData(Optional.of(next.data())); + spawner.markUpdated(); + }); + }); + } else { + ((TrialSpawnerDataAccessor) spawnerData).accessor$nextMobSpawnsAt(nextSpawnAt); + } + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java index acbe4cb35ae..a0ca6cfd4ed 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/CrafterBlockBlockEntityMixin_Inventory_API.java @@ -25,16 +25,32 @@ package org.spongepowered.common.mixin.inventory.api.world.inventory; +import net.minecraft.core.NonNullList; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.level.block.CrafterBlock; import net.minecraft.world.level.block.entity.CrafterBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.api.block.entity.carrier.Crafter; import org.spongepowered.api.item.inventory.crafting.CraftingGridInventory; import org.spongepowered.api.item.inventory.type.GridInventory; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.accessor.world.level.block.CrafterBlockAccessor; import org.spongepowered.common.inventory.adapter.InventoryAdapter; import org.spongepowered.common.inventory.fabric.Fabric; import org.spongepowered.common.inventory.lens.impl.comp.CraftingGridInventoryLens; +import org.spongepowered.common.mixin.api.minecraft.world.level.block.entity.RandomizableContainerBlockEntityMixin_API; @Mixin(CrafterBlockEntity.class) -public abstract class CrafterBlockBlockEntityMixin_Inventory_API implements CraftingGridInventory { +public abstract class CrafterBlockBlockEntityMixin_Inventory_API extends RandomizableContainerBlockEntityMixin_API implements CraftingGridInventory, Crafter { + + @Shadow public abstract void shadow$setCraftingTicksRemaining(final int $$0); + + @Shadow public abstract NonNullList shadow$getItems(); private GridInventory api$gridAdapter; @@ -48,4 +64,47 @@ public GridInventory asGrid() { return this.api$gridAdapter; } + + /** + * See CrafterBlock#dispenseFrom + */ + @Override + public boolean craftItem() { + final var input = ((CraftingContainer) this).asCraftInput(); + final var potentialResults = CrafterBlock.getPotentialResults(this.level, input); + if (potentialResults.isEmpty()) { + return false; + } + final var recipeHolder = potentialResults.get(); + final var recipe = recipeHolder.value(); + final var craftedStack = recipe.assemble(input, this.level.registryAccess()); + if (craftedStack.isEmpty()) { + return false; + } + this.shadow$setCraftingTicksRemaining(6); + final var state = this.shadow$getBlockState(); + this.level.setBlock(this.worldPosition, state.setValue(CrafterBlock.CRAFTING, true), 2); + craftedStack.onCraftedBySystem(this.level); + + this.impl$dispenseItem(state, craftedStack, recipeHolder); + + for (final ItemStack remainingStack : recipe.getRemainingItems(input)) { + if (!remainingStack.isEmpty()) { + this.impl$dispenseItem(state, remainingStack, recipeHolder); + } + } + + this.shadow$getItems().forEach(stack -> { + if (!stack.isEmpty()) { + stack.shrink(1); + } + }); + this.shadow$setChanged(); + return true; + } + + private void impl$dispenseItem(final BlockState state, final ItemStack craftedStack, final RecipeHolder recipeHolder) { + ((CrafterBlockAccessor) state.getBlock()).invoker$dispenseItem((ServerLevel) this.level, this.worldPosition, (CrafterBlockEntity)(Object) this, + craftedStack, state, recipeHolder); + } } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index c8cdb9fe8b6..cee72b67217 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -393,6 +393,7 @@ "minecraft.world.level.block.entity.TheEndGatewayBlockEntityMixin_API", "minecraft.world.level.block.entity.TheEndPortalBlockEntityMixin_API", "minecraft.world.level.block.entity.TrappedCheckBlockEntityMixin_API", + "minecraft.world.level.block.entity.TrialSpawnerBlockEntityMixin_API", "minecraft.world.level.block.entity.trialspawner.TrialSpawnerStateMixin_API", "minecraft.world.level.block.entity.vault.VaultStateMixin_API", "minecraft.world.level.block.piston.PistonMovingBlockEntityMixin_API", From b7f625bfcc9b86f01619b3e33f4cb7a7a160a50e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 14 Jun 2024 16:27:13 +0200 Subject: [PATCH 051/226] fix advancements and datapack folder --- SpongeAPI | 2 +- .../org/spongepowered/common/datapack/SpongeDataPackType.java | 4 ++-- .../api/minecraft/advancements/AdvancementMixin_API.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index a24c980aa55..da2a717f246 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit a24c980aa5541cd876670a535d78331ae0dcde37 +Subproject commit da2a717f246bc34823f6390c8bce797de78183ea diff --git a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java index aabee127c9f..d0ec6b41602 100644 --- a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java +++ b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java @@ -95,7 +95,7 @@ public static > SpongeDataPackType custom(fi public static final class FactoryImpl implements DataPackType.Factory { private final SpongeDataPackType advancement = SpongeDataPackType.basic(AdvancementTemplate.class, - "advancements", SpongeAdvancementTemplate::encode, null, // TODO decoder + "advancement", SpongeAdvancementTemplate::encode, null, // TODO decoder true); private final SpongeDataPackType recipe = SpongeDataPackType.custom(RecipeRegistration.class, @@ -143,7 +143,7 @@ public static final class FactoryImpl implements DataPackType.Factory { false); private final SpongeDataPackType schematic = SpongeDataPackType.custom(SchematicTemplate.class, - "structures", new NbtDataPackSerializer<>(SpongeSchematicTemplate::encode, SpongeSchematicTemplate::decode), + "structure", new NbtDataPackSerializer<>(SpongeSchematicTemplate::encode, SpongeSchematicTemplate::decode), false); private final SpongeDataPackType processorList = SpongeDataPackType.basic(ProcessorListTemplate.class, diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/AdvancementMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/AdvancementMixin_API.java index 6e4c0b02377..79d4e5c2ac3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/AdvancementMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/AdvancementMixin_API.java @@ -73,7 +73,7 @@ public Optional parent() { @Override public Optional displayInfo() { - return Optional.ofNullable((org.spongepowered.api.advancement.DisplayInfo) (Object) this.display); + return this.display.map(org.spongepowered.api.advancement.DisplayInfo.class::cast); } @Override From 25db291b0dd5b8740de8a7a481789738641736a4 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sat, 15 Jun 2024 18:28:45 +0300 Subject: [PATCH 052/226] Cache block palette results in few hot paths --- .../world/schematic/CachingPalette.java | 119 ++++++++++++++++++ .../world/schematic/SchematicTranslator.java | 2 +- .../buffer/block/ArrayMutableBlockBuffer.java | 3 +- 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/world/schematic/CachingPalette.java diff --git a/src/main/java/org/spongepowered/common/world/schematic/CachingPalette.java b/src/main/java/org/spongepowered/common/world/schematic/CachingPalette.java new file mode 100644 index 00000000000..c114d875cb7 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/schematic/CachingPalette.java @@ -0,0 +1,119 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.schematic; + +import org.spongepowered.api.registry.RegistryHolder; +import org.spongepowered.api.world.schematic.Palette; +import org.spongepowered.api.world.schematic.PaletteReference; +import org.spongepowered.api.world.schematic.PaletteType; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.stream.Stream; + +public abstract class CachingPalette> implements Palette { + + protected final D delegate; + protected final Map> cache; + + protected CachingPalette(final D delegate) { + this.delegate = delegate; + this.cache = new HashMap<>(); + } + + @Override + public PaletteType type() { + return this.delegate.type(); + } + + @Override + public int highestId() { + return this.delegate.highestId(); + } + + @Override + public Optional> get(final int id) { + return this.delegate.get(id); + } + + @Override + public Optional get(final int id, final RegistryHolder holder) { + return this.cache.computeIfAbsent(id, $ -> this.delegate.get(id, holder)); + } + + @Override + public OptionalInt get(final T type) { + return this.delegate.get(type); + } + + @Override + public Stream stream() { + return this.delegate.stream(); + } + + @Override + public Stream> streamWithIds() { + return this.delegate.streamWithIds(); + } + + @Override + public Mutable asMutable(final RegistryHolder registry) { + return new MutableImpl<>(this.delegate.asMutable(registry)); + } + + @Override + public Immutable asImmutable() { + return new ImmutableImpl<>(this.delegate.asImmutable()); + } + + public static final class MutableImpl extends CachingPalette> implements Palette.Mutable { + + public MutableImpl(final Palette.Mutable delegate) { + super(delegate); + } + + @Override + public int orAssign(final T type) { + int id = this.delegate.orAssign(type); + this.cache.put(id, Optional.of(type)); + return id; + } + + @Override + public boolean remove(final T type) { + this.delegate.get(type).ifPresent(this.cache::remove); + return this.delegate.remove(type); + } + } + + public static final class ImmutableImpl extends CachingPalette> implements Palette.Immutable { + + public ImmutableImpl(final Palette.Immutable delegate) { + super(delegate); + } + } +} diff --git a/src/main/java/org/spongepowered/common/world/schematic/SchematicTranslator.java b/src/main/java/org/spongepowered/common/world/schematic/SchematicTranslator.java index eada1999b34..d3c32a85a77 100644 --- a/src/main/java/org/spongepowered/common/world/schematic/SchematicTranslator.java +++ b/src/main/java/org/spongepowered/common/world/schematic/SchematicTranslator.java @@ -305,7 +305,7 @@ private static void deserializeBlockContainer( final byte[] blockData = (byte[]) view.get(Constants.Sponge.Schematic.BLOCK_DATA) .orElseThrow(() -> new InvalidDataException("Missing BlockData for Schematic")); SchematicTranslator.readByteArrayData( - width, (width * length), offset, palette, blockData, archetypeVolume, + width, (width * length), offset, new CachingPalette.MutableImpl<>(palette), blockData, archetypeVolume, BlockVolume.Modifiable::setBlock ); view.getViewList(Constants.Sponge.Schematic.BLOCKENTITY_CONTAINER) diff --git a/src/main/java/org/spongepowered/common/world/volume/buffer/block/ArrayMutableBlockBuffer.java b/src/main/java/org/spongepowered/common/world/volume/buffer/block/ArrayMutableBlockBuffer.java index cdad4844220..faaa85e72b9 100644 --- a/src/main/java/org/spongepowered/common/world/volume/buffer/block/ArrayMutableBlockBuffer.java +++ b/src/main/java/org/spongepowered/common/world/volume/buffer/block/ArrayMutableBlockBuffer.java @@ -40,6 +40,7 @@ import org.spongepowered.api.world.volume.stream.StreamOptions; import org.spongepowered.api.world.volume.stream.VolumeElement; import org.spongepowered.api.world.volume.stream.VolumeStream; +import org.spongepowered.common.world.schematic.CachingPalette; import org.spongepowered.common.world.schematic.MutableBimapPalette; import org.spongepowered.common.world.volume.SpongeVolumeStream; import org.spongepowered.common.world.volume.VolumeStreamUtils; @@ -76,7 +77,7 @@ public ArrayMutableBlockBuffer(final Palette palette, fin final Vector3i start, final Vector3i size ) { super(start, size); - final Palette.Mutable mutablePalette = palette.asMutable(Sponge.game()); + final Palette.Mutable mutablePalette = new CachingPalette.MutableImpl<>(palette.asMutable(Sponge.game())); this.palette = mutablePalette; final int airId = mutablePalette.orAssign(ArrayMutableBlockBuffer.AIR); From 9e2531f78e71491c9c5a1a634bcfdbeddac02435 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sat, 15 Jun 2024 19:05:44 +0300 Subject: [PATCH 053/226] Fire rotation event on respawn --- .../core/server/players/PlayerListMixin.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java index 4d6fee0b67b..468e902e5e4 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java @@ -66,6 +66,7 @@ import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContext; import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.entity.RotateEntityEvent; import org.spongepowered.api.event.entity.living.player.RespawnPlayerEvent; import org.spongepowered.api.event.message.PlayerChatEvent; import org.spongepowered.api.event.message.SystemMessageEvent; @@ -102,6 +103,7 @@ import org.spongepowered.common.bridge.world.level.storage.PrimaryLevelDataBridge; import org.spongepowered.common.entity.player.LoginPermissions; import org.spongepowered.common.entity.player.SpongeUserView; +import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; @@ -524,6 +526,22 @@ public abstract class PlayerListMixin implements PlayerListBridge { this.impl$isRespawnWithPosition = false; newPlayer.setPos(event.destinationPosition().x(), event.destinationPosition().y(), event.destinationPosition().z()); + if (ShouldFire.ROTATE_ENTITY_EVENT) { + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(event); + + final RotateEntityEvent rotateEvent = SpongeEventFactory.createRotateEntityEvent( + frame.currentCause(), recreatedPlayer, originalPlayer.rotation(), recreatedPlayer.rotation()); + if (SpongeCommon.post(rotateEvent)) { + newPlayer.setXRot(player.getXRot()); + newPlayer.setYRot(player.getYRot()); + } else { + newPlayer.setXRot((float) rotateEvent.toRotation().x()); + newPlayer.setYRot((float) rotateEvent.toRotation().y()); + } + } + } + return newPlayer.getX(); } From f58b22cb2a40b435c23ace65139b0c109a229fc6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 10:32:30 +0200 Subject: [PATCH 054/226] fix custom data changes affecting itemstack copy --- src/main/java/org/spongepowered/common/data/DataUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/DataUtil.java b/src/main/java/org/spongepowered/common/data/DataUtil.java index 548b561fdb8..5ecf868056b 100644 --- a/src/main/java/org/spongepowered/common/data/DataUtil.java +++ b/src/main/java/org/spongepowered/common/data/DataUtil.java @@ -178,6 +178,7 @@ public static boolean se compound = new CompoundTag(); dataHolder.data$setCompound(compound); } + compound = compound.copy(); // do not modify the original as it might be shared compound.remove(Constants.Sponge.Data.V3.SPONGE_DATA_ROOT.asString(".")); // Remove all previous SpongeData final DataContainer allData = NBTTranslator.INSTANCE.translate(compound); From 7398cec471b902d2ce562851ea2ff3c26092b81b Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 11:49:09 +0200 Subject: [PATCH 055/226] fix new worlds not respecting custom seed --- .../world/server/SpongeWorldManager.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java b/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java index 6499c58c5a4..6d59b09c4ac 100644 --- a/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java +++ b/src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java @@ -756,15 +756,17 @@ public void loadLevel() { ((SpongeServer) SpongeCommon.server()).getPlayerDataManager().load(); } - private PrimaryLevelData getOrCreateLevelData(final Dynamic dynamicLevelData, final LevelStem levelStem, final String directoryName) { + private PrimaryLevelData getOrCreateLevelData(@Nullable final Dynamic dynamicLevelData, final LevelStem levelStem, final String directoryName) { final PrimaryLevelData defaultLevelData = (PrimaryLevelData) this.server.getWorldData(); - try { - @Nullable PrimaryLevelData levelData = this.loadLevelData(this.server.registryAccess(), defaultLevelData.getDataConfiguration(), dynamicLevelData); - if (levelData != null) { - return levelData; + if (dynamicLevelData != null) { + try { + @Nullable PrimaryLevelData levelData = this.loadLevelData(this.server.registryAccess(), defaultLevelData.getDataConfiguration(), dynamicLevelData); + if (levelData != null) { + return levelData; + } + } catch (Exception e) { + throw new RuntimeException("Failed to load level data from " + directoryName, e); } - } catch (Exception e) { - throw new RuntimeException("Failed to load level data from " + directoryName, e); } if (this.server.isDemo()) { @@ -783,10 +785,9 @@ private PrimaryLevelData getOrCreateLevelData(final Dynamic dynamicLevelData, return new PrimaryLevelData(levelSettings, defaultLevelData.worldGenOptions(), PrimaryLevelData.SpecialWorldProperty.NONE, Lifecycle.stable()); } - @Nullable private PrimaryLevelData loadLevelData(final RegistryAccess.Frozen access, final WorldDataConfiguration datapackConfig, final Dynamic dataTag) { final LevelDataAndDimensions levelData = LevelStorageSource.getLevelDataAndDimensions(dataTag, datapackConfig, access.registryOrThrow(Registries.LEVEL_STEM), access); - return levelData == null ? null : (PrimaryLevelData) levelData.worldData(); + return (PrimaryLevelData) levelData.worldData(); } // Do not call this for the default world, that is handled very special in loadLevel() @@ -802,7 +803,7 @@ private ServerLevel createNonDefaultLevel( try { dataTag = storageSource.getDataTag(); } catch (IOException e) { - dataTag = ((MinecraftServerAccessor) this.server).accessor$storageSource().getDataTag(); // Fallback to overworld level.dat + dataTag = null; // ((MinecraftServerAccessor) this.server).accessor$storageSource().getDataTag(); // Fallback to overworld level.dat } final PrimaryLevelData levelData = this.getOrCreateLevelData(dataTag, levelStem, directoryName); ((ResourceKeyBridge) levelData).bridge$setKey(worldKey); From 58e8b5fecff37bfb5cea1ef2df877300be006cbb Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 00:19:36 +0200 Subject: [PATCH 056/226] ArtType datapack --- SpongeAPI | 2 +- .../data/type/SpongeArtTypeTemplate.java | 139 ++++++++++++++++++ .../common/datapack/SpongeDataPackType.java | 10 ++ .../registry/SpongeBuilderProvider.java | 3 + 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java diff --git a/SpongeAPI b/SpongeAPI index da2a717f246..b96f91d06a7 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit da2a717f246bc34823f6390c8bce797de78183ea +Subproject commit b96f91d06a7a55b29c81ce3b9b86b496a0e1d43f diff --git a/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java b/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java new file mode 100644 index 00000000000..a9405f74bf3 --- /dev/null +++ b/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java @@ -0,0 +1,139 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.data.type; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.damagesource.DamageType; +import net.minecraft.world.entity.decoration.PaintingVariant; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataFormats; +import org.spongepowered.api.data.persistence.DataView; +import org.spongepowered.api.data.type.ArtType; +import org.spongepowered.api.data.type.ArtTypeTemplate; +import org.spongepowered.api.datapack.DataPack; +import org.spongepowered.api.event.cause.entity.damage.DamageTypeTemplate; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.event.cause.entity.damage.SpongeDamageTypeTemplate; +import org.spongepowered.common.util.AbstractDataPackEntryBuilder; +import org.spongepowered.common.util.Preconditions; + +import java.io.IOException; +import java.util.Objects; +import java.util.function.Function; + +public record SpongeArtTypeTemplate(ResourceKey key, PaintingVariant representedType, DataPack pack) implements ArtTypeTemplate { + + @Override + public ArtType type() { + return (ArtType) (Object) this.representedType; + } + + @Override + public int contentVersion() { + return 0; + } + + @Override + public DataContainer toContainer() { + final JsonElement serialized = SpongeArtTypeTemplate.encode(this, SpongeCommon.server().registryAccess()); + try { + return DataFormats.JSON.get().read(serialized.toString()); + } catch (IOException e) { + throw new IllegalStateException("Could not read deserialized DamageType:\n" + serialized, e); + } + } + + public static JsonElement encode(final ArtTypeTemplate template, final RegistryAccess registryAccess) { + final RegistryOps ops = RegistryOps.create(JsonOps.INSTANCE, registryAccess); + return PaintingVariant.DIRECT_CODEC.encodeStart(ops, (PaintingVariant) (Object) template.type()).getOrThrow(); + } + + public static PaintingVariant decode(final JsonElement json, final RegistryAccess registryAccess) { + final RegistryOps ops = RegistryOps.create(JsonOps.INSTANCE, registryAccess); + return PaintingVariant.DIRECT_CODEC.parse(ops, json).getOrThrow(); + } + + public static SpongeArtTypeTemplate decode(final DataPack pack, final ResourceKey key, final JsonElement packEntry, final RegistryAccess registryAccess) { + final var parsed = SpongeArtTypeTemplate.decode(packEntry, registryAccess); + return new SpongeArtTypeTemplate(key, parsed, pack); + } + + public static final class BuilderImpl extends AbstractDataPackEntryBuilder implements Builder { + + private int width; + private int height; + private ResourceLocation assetId; + + @Override + public Builder dimensions(final int width, final int height) { + this.width = width; + this.height = height; + return this; + } + + @Override + public Builder asset(final ResourceKey assetId) { + this.assetId = (ResourceLocation) (Object) assetId; + return this; + } + + @Override + public Builder fromValue(final ArtType value) { + if ((Object) value instanceof PaintingVariant variant) { + this.width = variant.width(); + this.height = variant.height(); + this.assetId = variant.assetId(); + } + return this; + } + + @Override + public Builder fromDataPack(final DataView dataView) throws IOException { + final JsonElement json = JsonParser.parseString(DataFormats.JSON.get().write(dataView)); + final var damageType = SpongeArtTypeTemplate.decode(json, SpongeCommon.server().registryAccess()); + this.fromValue((ArtType) (Object) damageType); + return this; + } + + @Override + public Function valueExtractor() { + return ArtTypeTemplate::type; + } + + @Override + protected ArtTypeTemplate build0() { + Preconditions.checkArgument(this.width >= 0, "width must set"); + Preconditions.checkArgument(this.height >= 0, "height must set"); + Objects.requireNonNull(this.assetId, "assetId"); + return new SpongeArtTypeTemplate(this.key, new PaintingVariant(this.width, this.height, this.assetId), this.pack); + } + } +} diff --git a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java index d0ec6b41602..2ace0a97f7d 100644 --- a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java +++ b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java @@ -33,6 +33,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.advancement.AdvancementTemplate; import org.spongepowered.api.adventure.ChatTypeTemplate; +import org.spongepowered.api.data.type.ArtType; +import org.spongepowered.api.data.type.ArtTypeTemplate; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPackEntry; import org.spongepowered.api.datapack.DataPackType; @@ -57,6 +59,7 @@ import org.spongepowered.api.world.server.WorldTemplate; import org.spongepowered.common.advancement.SpongeAdvancementTemplate; import org.spongepowered.common.adventure.SpongeChatTypeTemplate; +import org.spongepowered.common.data.type.SpongeArtTypeTemplate; import org.spongepowered.common.datapack.recipe.RecipeDataPackSerializer; import org.spongepowered.common.event.cause.entity.damage.SpongeDamageTypeTemplate; import org.spongepowered.common.item.recipe.SpongeRecipeRegistration; @@ -167,6 +170,9 @@ public static final class FactoryImpl implements DataPackType.Factory { "damage_type", SpongeDamageTypeTemplate::encode, SpongeDamageTypeTemplate::decode, false); + private final SpongeDataPackType artType = SpongeDataPackType.basic(ArtTypeTemplate.class, + "damage_type", SpongeArtTypeTemplate::encode, SpongeArtTypeTemplate::decode, + false); @Override public DataPackType recipe() { @@ -266,6 +272,10 @@ public > DataPackType> tag(RegistryType true); } + @Override + public DataPackType artType() { + return this.artType; + } } public DataPack pack(final String name, final String description) { diff --git a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java index c59958d6122..726bb27bf8b 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java @@ -50,6 +50,7 @@ import org.spongepowered.api.data.MutableDataProviderBuilder; import org.spongepowered.api.data.meta.BannerPatternLayer; import org.spongepowered.api.data.persistence.DataStore; +import org.spongepowered.api.data.type.ArtTypeTemplate; import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.potion.PotionEffect; import org.spongepowered.api.effect.sound.SoundType; @@ -161,6 +162,7 @@ import org.spongepowered.common.data.key.SpongeKeyBuilder; import org.spongepowered.common.data.persistence.datastore.SpongeDataStoreBuilder; import org.spongepowered.common.data.provider.DataProviderRegistrator; +import org.spongepowered.common.data.type.SpongeArtTypeTemplate; import org.spongepowered.common.effect.particle.SpongeParticleEffectBuilder; import org.spongepowered.common.effect.potion.SpongePotionBuilder; import org.spongepowered.common.effect.sound.SpongeSoundBuilder; @@ -390,6 +392,7 @@ public void registerDefaultBuilders() { .register(JigsawPoolTemplate.Builder.class, SpongeJigsawPoolTemplate.BuilderImpl::new) .register(ChatTypeTemplate.Builder.class, SpongeChatTypeTemplate.BuilderImpl::new) .register(DamageTypeTemplate.Builder.class, SpongeDamageTypeTemplate.BuilderImpl::new) + .register(ArtTypeTemplate.Builder.class, SpongeArtTypeTemplate.BuilderImpl::new) .register(TicketType.Builder.class, SpongeTicketTypeBuilder::new) .register(PortalLogic.Builder.class, SpongePortalLogicBuilder::new) ; From 23ccb1678f3b9592e8cefc98e27266c53f2bd545 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 16:17:18 +0200 Subject: [PATCH 057/226] fix attack NPE also fix style issues --- SpongeAPI | 2 +- .../spongepowered/common/data/type/SpongeArtTypeTemplate.java | 3 --- .../org/spongepowered/common/datapack/SpongeDataPackType.java | 1 - .../core/world/entity/player/PlayerMixin_Attack_Impl.java | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index b96f91d06a7..dc4462dc6f6 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit b96f91d06a7a55b29c81ce3b9b86b496a0e1d43f +Subproject commit dc4462dc6f6c49a93b90589c05957043a3aa5717 diff --git a/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java b/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java index a9405f74bf3..b97360fe3d6 100644 --- a/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java +++ b/src/main/java/org/spongepowered/common/data/type/SpongeArtTypeTemplate.java @@ -30,7 +30,6 @@ import net.minecraft.core.RegistryAccess; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.entity.decoration.PaintingVariant; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.data.persistence.DataContainer; @@ -39,9 +38,7 @@ import org.spongepowered.api.data.type.ArtType; import org.spongepowered.api.data.type.ArtTypeTemplate; import org.spongepowered.api.datapack.DataPack; -import org.spongepowered.api.event.cause.entity.damage.DamageTypeTemplate; import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.event.cause.entity.damage.SpongeDamageTypeTemplate; import org.spongepowered.common.util.AbstractDataPackEntryBuilder; import org.spongepowered.common.util.Preconditions; diff --git a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java index 2ace0a97f7d..1b1b9aabe2e 100644 --- a/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java +++ b/src/main/java/org/spongepowered/common/datapack/SpongeDataPackType.java @@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.advancement.AdvancementTemplate; import org.spongepowered.api.adventure.ChatTypeTemplate; -import org.spongepowered.api.data.type.ArtType; import org.spongepowered.api.data.type.ArtTypeTemplate; import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPackEntry; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index b828f962de7..4d0fd08225e 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -235,7 +235,7 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i if (this.attackImpl$isStrongSprintAttack) { // Play prevented sprint attack sound - this.impl$playAttackSound(this.attackImpl$attack.sourceEntity(), SoundEvents.PLAYER_ATTACK_KNOCKBACK); + this.impl$playAttackSound((Player) (Object) this, SoundEvents.PLAYER_ATTACK_KNOCKBACK); } return targetEntity.hurt(damageSource, (float) this.attackImpl$attackEvent.finalOutputDamage()); From 71a5c9080e95035f65a430eafb052b7f755fe5bc Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 19:42:21 +0200 Subject: [PATCH 058/226] fix recipe advancements --- .../common/datapack/recipe/RecipeDataPackSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/datapack/recipe/RecipeDataPackSerializer.java b/src/main/java/org/spongepowered/common/datapack/recipe/RecipeDataPackSerializer.java index 7bc63d2b3d1..27588abbdb6 100644 --- a/src/main/java/org/spongepowered/common/datapack/recipe/RecipeDataPackSerializer.java +++ b/src/main/java/org/spongepowered/common/datapack/recipe/RecipeDataPackSerializer.java @@ -54,7 +54,7 @@ protected void serializeAdditional( final Path file = packDir.resolve("data") .resolve(entry.key().namespace()) - .resolve("advancements") + .resolve("advancement") .resolve(entry.key().value() + ".json"); Files.createDirectories(file.getParent()); From 1d8a79151bb65a966d655b755fab711ba34ed1bc Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 19:53:28 +0200 Subject: [PATCH 059/226] fix shapeless recipe matching --- .../recipe/crafting/shapeless/SpongeShapelessRecipe.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java index 02779a90f6d..8090a7189f6 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessRecipe.java @@ -157,9 +157,10 @@ public ItemStack getResultItem(final HolderLookup.Provider $$1) { return super.getResultItem($$1); } - private static boolean matches(List stacks, List ingredients) { + private static boolean + matches(List stacks, List ingredients) { final int elements = ingredients.size(); - if (stacks.size() != elements) { + if (stacks.size() < elements) { return false; } From e6baede04c5bd3ab5b22bb7b17970f0be5ba2854 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 20:07:10 +0200 Subject: [PATCH 060/226] fix attack NPE --- .../mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index 4d0fd08225e..522ed8d9a24 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -270,7 +270,7 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i public void attackImpl$onNoDamageSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, final SoundEvent $$4, final SoundSource $$5, final float $$6, final float $$7) { if (!this.attackImpl$attackEvent.isCancelled()) { - this.impl$playAttackSound($$0, SoundEvents.PLAYER_ATTACK_NODAMAGE); + this.impl$playAttackSound((Player) (Object) this, SoundEvents.PLAYER_ATTACK_NODAMAGE); } } From 4d90ce5f09c17bdb880528a38c656342f2e10dfe Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 20:23:04 +0200 Subject: [PATCH 061/226] fix custom data --- src/main/java/org/spongepowered/common/data/DataUtil.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/DataUtil.java b/src/main/java/org/spongepowered/common/data/DataUtil.java index 5ecf868056b..1ad411087e0 100644 --- a/src/main/java/org/spongepowered/common/data/DataUtil.java +++ b/src/main/java/org/spongepowered/common/data/DataUtil.java @@ -176,9 +176,10 @@ public static boolean se CompoundTag compound = dataHolder.data$getCompound(); if (compound == null) { compound = new CompoundTag(); - dataHolder.data$setCompound(compound); + } else { + compound = compound.copy(); // do not modify the original as it might be shared } - compound = compound.copy(); // do not modify the original as it might be shared + dataHolder.data$setCompound(compound); compound.remove(Constants.Sponge.Data.V3.SPONGE_DATA_ROOT.asString(".")); // Remove all previous SpongeData final DataContainer allData = NBTTranslator.INSTANCE.translate(compound); From d9349c5c974f9892a37da6cfd71a2dcc4c1aaf84 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 16 Jun 2024 23:39:26 +0200 Subject: [PATCH 062/226] fix merchantoffer second item --- .../common/item/merchant/SpongeTradeOfferBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java index d75913d6b22..69dd24557da 100644 --- a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java +++ b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java @@ -132,7 +132,7 @@ public TradeOffer build() throws IllegalStateException { final var selling = ItemStackUtil.fromSnapshotToNative(this.sellingItem); final MerchantOffer merchantOffer = new MerchantOffer(SpongeTradeOfferBuilder.itemCostOf(first), - Optional.ofNullable(second).map(SpongeTradeOfferBuilder::itemCostOf), + second.isEmpty() ? Optional.empty() : Optional.ofNullable(second).map(SpongeTradeOfferBuilder::itemCostOf), selling, this.useCount, this.maxUses, From 8f577b736f41640ec6a8d57b733e70af8e0fce5c Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 20 Jun 2024 00:16:52 +0200 Subject: [PATCH 063/226] massive performance improvements --- .../spongepowered/common/event/tracking/TrackingUtil.java | 2 +- .../java/org/spongepowered/common/util/Preconditions.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/event/tracking/TrackingUtil.java b/src/main/java/org/spongepowered/common/event/tracking/TrackingUtil.java index be7eb9e437f..8ad0399038d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/TrackingUtil.java +++ b/src/main/java/org/spongepowered/common/event/tracking/TrackingUtil.java @@ -104,7 +104,7 @@ public final class TrackingUtil { public static final int WIDTH = 40; public static void tickEntity(final Consumer consumer, final net.minecraft.world.entity.Entity entity) { - Preconditions.checkArgument(entity instanceof Entity, String.format("Entity %s is not an instance of SpongeAPI's Entity!", entity)); + Preconditions.checkArgument(entity instanceof Entity, () -> String.format("Entity %s is not an instance of SpongeAPI's Entity!", entity)); Objects.requireNonNull(entity, "Cannot capture on a null ticking entity!"); if (!((TrackableBridge) entity).bridge$shouldTick()) { return; diff --git a/src/main/java/org/spongepowered/common/util/Preconditions.java b/src/main/java/org/spongepowered/common/util/Preconditions.java index 97a9b8fedd6..845cfd5bfd9 100644 --- a/src/main/java/org/spongepowered/common/util/Preconditions.java +++ b/src/main/java/org/spongepowered/common/util/Preconditions.java @@ -24,6 +24,8 @@ */ package org.spongepowered.common.util; +import java.util.function.Supplier; + public class Preconditions { public static void checkState(final boolean expression, final String errorMessage) { @@ -45,6 +47,12 @@ public static void checkArgument(final boolean expression, final String errorMes } } + public static void checkArgument(final boolean expression, final Supplier errorMessage) { + if (!expression) { + throw new IllegalArgumentException(errorMessage.get()); + } + } + public static void checkArgument(final boolean expression) { if (!expression) { // TODO we should ideally always have a message From 5215e26ea2c6447c56338a7473e50a7d354ea23a Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 21 Jun 2024 17:56:11 +0200 Subject: [PATCH 064/226] fix damage cancellation --- .../entity/player/PlayerMixin_Attack_Impl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index 522ed8d9a24..0a7a07f5927 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -387,6 +387,19 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i return false; } + /** + * Set original damage after calling {@link Player#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 0, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", + shift = At.Shift.AFTER), argsOnly = true) + public float attackImpl$setOriginalDamage(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return value; + } + /** * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event */ From d3b24c034498f3a9428d94efa9078e293842bcd2 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 20 Jun 2024 23:52:24 +0200 Subject: [PATCH 065/226] improve chunk-position stream performance by making one big read instead of 1024 smaller ones --- .../chunk/storage/RegionFileAccessor.java | 49 ++++++++ .../resources/mixins.sponge.accessors.json | 1 + .../level/chunk/storage/RegionFileBridge.java | 32 +++++ .../server/level/ServerLevelMixin_API.java | 4 +- .../level/chunk/storage/RegionFileMixin.java | 112 ++++++++++++++++++ src/mixins/resources/mixins.sponge.core.json | 1 + 6 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/storage/RegionFileAccessor.java create mode 100644 src/main/java/org/spongepowered/common/bridge/world/level/chunk/storage/RegionFileBridge.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/RegionFileMixin.java diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/storage/RegionFileAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/storage/RegionFileAccessor.java new file mode 100644 index 00000000000..db55e1390a2 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/storage/RegionFileAccessor.java @@ -0,0 +1,49 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.chunk.storage; + +import net.minecraft.world.level.chunk.storage.RegionFile; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(RegionFile.class) +public interface RegionFileAccessor { + + @Invoker("getSectorNumber") static int invoker$getSectorNumber(final int $$0) { + return 0; + } + + @Invoker("getNumSectors") static int invoker$getNumSectors(final int $$0) { + return 0; + } + + @Invoker("isExternalStreamChunk") static boolean invoker$isExternalStreamChunk(final byte $$0) { + return false; + } + + @Invoker("getExternalChunkVersion") static byte invoker$getExternalChunkVersion(final byte $$0) { + return 0; + } +} diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index d27fcfb8463..9ed69355952 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -191,6 +191,7 @@ "world.level.chunk.LevelChunkAccessor", "world.level.chunk.storage.ChunkStorageAccessor", "world.level.chunk.storage.IOWorker$PendingStoreAccessor", + "world.level.chunk.storage.RegionFileAccessor", "world.level.chunk.storage.SimpleRegionStorageAccessor", "world.level.dimension.DimensionTypeAccessor", "world.level.entity.EntityTickListAccessor", diff --git a/src/main/java/org/spongepowered/common/bridge/world/level/chunk/storage/RegionFileBridge.java b/src/main/java/org/spongepowered/common/bridge/world/level/chunk/storage/RegionFileBridge.java new file mode 100644 index 00000000000..51824c8872f --- /dev/null +++ b/src/main/java/org/spongepowered/common/bridge/world/level/chunk/storage/RegionFileBridge.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.bridge.world.level.chunk.storage; + +import net.minecraft.world.level.ChunkPos; + +public interface RegionFileBridge { + + boolean bridge$doesChunkExist(ChunkPos chunkPos); +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java index c1d9d0ef8d9..5d13d9cea3f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java @@ -75,6 +75,7 @@ import org.spongepowered.common.accessor.world.entity.raid.RaidsAccessor; import org.spongepowered.common.bridge.server.level.ServerLevelBridge; import org.spongepowered.common.bridge.world.level.border.WorldBorderBridge; +import org.spongepowered.common.bridge.world.level.chunk.storage.RegionFileBridge; import org.spongepowered.common.bridge.world.level.storage.PrimaryLevelDataBridge; import org.spongepowered.common.data.holder.SpongeServerLocationBaseDataHolder; import org.spongepowered.common.mixin.api.minecraft.world.level.LevelMixin_API; @@ -367,7 +368,8 @@ public ChunkManager chunkManager() { @Override public Stream chunkPositions() { return this.api$chunkPosStream((regionFile, stream) -> - stream.filter(regionFile::doesChunkExist) // filter out non-existent chunks +// stream.filter(regionFile::doesChunkExist) // filter out non-existent chunks + stream.filter(cp -> ((RegionFileBridge) regionFile).bridge$doesChunkExist(cp)) // filter out non-existent chunks .map(cp -> new Vector3i(cp.x, 0, cp.z)) // map to API type ); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/RegionFileMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/RegionFileMixin.java new file mode 100644 index 00000000000..7ec08a12a81 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/chunk/storage/RegionFileMixin.java @@ -0,0 +1,112 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.world.level.chunk.storage; + +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.storage.RegionFile; +import net.minecraft.world.level.chunk.storage.RegionFileVersion; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.common.accessor.world.level.chunk.storage.RegionFileAccessor; +import org.spongepowered.common.bridge.world.level.chunk.storage.RegionFileBridge; + +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; + +@Mixin(RegionFile.class) +public abstract class RegionFileMixin implements RegionFileBridge { + + // @formatter:off + @Shadow @Final private Path path; + + @Shadow protected abstract int shadow$getOffset(final ChunkPos $$0); + @Shadow protected abstract Path shadow$getExternalChunkPath(final ChunkPos $$0); + // @formatter:on + + private ByteBuffer impl$allData; + + /** + * This caches the entire region file instead of just reading parts of it like {@link RegionFile#doesChunkExist}. + */ + @Override + public boolean bridge$doesChunkExist(final ChunkPos chunkPos) { + try { + + final var offset = this.shadow$getOffset(chunkPos); + if (offset == 0) { + return false; + } + + final var sectorNumber = RegionFileAccessor.invoker$getSectorNumber(offset); + final var numSectors = RegionFileAccessor.invoker$getNumSectors(offset); + + if (this.impl$allData == null) { + this.impl$allData = ByteBuffer.wrap(Files.readAllBytes(this.path)); + } + + final var chunkStart = sectorNumber * 4096; + this.impl$allData.position(chunkStart); + var size = this.impl$allData.getInt(); + var version = this.impl$allData.get(); + + + if (RegionFileAccessor.invoker$isExternalStreamChunk(version)) { + if (!RegionFileVersion.isValidVersion(RegionFileAccessor.invoker$getExternalChunkVersion(version))) { + return false; + } + if (!Files.isRegularFile(this.shadow$getExternalChunkPath(chunkPos))) { + return false; + } + } else { + if (!RegionFileVersion.isValidVersion(version)) { + return false; + } + if (size == 0) { + return false; + } + + var $$7 = size - 1; + if ($$7 < 0 || $$7 > 4096 * numSectors) { + return false; + } + } + } catch (Exception e) { + return false; + } + return true; + } + + @Inject(method = "close", at = @At("HEAD")) + public void impl$onClose(final CallbackInfo ci) { + this.impl$allData = null; + } + + +} diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index e7459b34a51..1e482eacbe7 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -250,6 +250,7 @@ "world.level.chunk.LevelChunkMixin", "world.level.chunk.storage.EntityStorageMixin", "world.level.chunk.storage.IOWorkerMixin", + "world.level.chunk.storage.RegionFileMixin", "world.level.dimension.DimensionTypeMixin", "world.level.dimension.LevelStemMixin", "world.level.entity.PersistentEntitySectionManagerMixin", From b62df0934e6ec86dca5b39d7c3c0780da72fd1e6 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 22 Jun 2024 00:07:56 +0200 Subject: [PATCH 066/226] fix Bogged --- .../api/minecraft/world/entity/monster/BoggedMixin_API.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java index 1adaf8b8328..6dc064db04e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/BoggedMixin_API.java @@ -24,10 +24,10 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; -import org.spongepowered.api.entity.living.monster.skeleton.Stray; +import org.spongepowered.api.entity.living.monster.skeleton.Bogged; import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.entity.monster.Bogged.class) -public abstract class BoggedMixin_API extends AbstractSkeletonMixin_API implements Stray { +public abstract class BoggedMixin_API extends AbstractSkeletonMixin_API implements Bogged { } From 5dcbff96b088a978fa6ca5b2d08516a33a3ef6ca Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:39:05 +0000 Subject: [PATCH 067/226] Add Difficulties generator (#4034) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 41c22eb2b78..8d684fe5b65 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -46,6 +46,7 @@ import net.minecraft.server.packs.repository.ServerPacksSource; import net.minecraft.server.packs.resources.CloseableResourceManager; import net.minecraft.server.packs.resources.MultiPackResourceManager; +import net.minecraft.world.Difficulty; import net.minecraft.world.damagesource.DamageEffects; import net.minecraft.world.damagesource.DamageScaling; import net.minecraft.world.entity.Display; @@ -259,6 +260,13 @@ private static List generators(final Context context) { "getName", "sponge" ), + new EnumEntriesValidator<>( + "world.difficulty", + "Difficulties", + Difficulty.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "FoxTypes", From efadd968de47995305101a78a3c372f8844d621b Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:43:32 +0000 Subject: [PATCH 068/226] Add ItemTiers generator (#4037) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 8d684fe5b65..260baeabeb8 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -60,6 +60,7 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.Tiers; import net.minecraft.world.item.component.FireworkExplosion; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.WorldDataConfiguration; @@ -705,6 +706,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "ItemTiers", + Tiers.class, + "name", + "sponge" + ), new EnumEntriesValidator<>( "entity.display", "BillboardTypes", From 4b669ef740c8893d254ec3e4784f0ec4740d8837 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:47:31 +0000 Subject: [PATCH 069/226] Add PandaGenes generator (#4038) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 260baeabeb8..01b52ed2b4f 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -52,6 +52,7 @@ import net.minecraft.world.entity.Display; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.animal.Fox; +import net.minecraft.world.entity.animal.Panda; import net.minecraft.world.entity.animal.TropicalFish; import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.animal.horse.Markings; @@ -268,6 +269,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "PandaGenes", + Panda.Gene.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "FoxTypes", From de6c1717826ebed98be3049102a285df74b78fcd Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:47:45 +0000 Subject: [PATCH 070/226] Add SpellTypes generator (#4041) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 01b52ed2b4f..c98516e5259 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -57,6 +57,7 @@ import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.animal.horse.Markings; import net.minecraft.world.entity.animal.horse.Variant; +import net.minecraft.world.entity.monster.SpellcasterIllager; import net.minecraft.world.entity.vehicle.Boat; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.ItemDisplayContext; @@ -276,6 +277,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "SpellTypes", + SpellcasterIllager.IllagerSpell.class, + "name", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "FoxTypes", From 94b8a7791a01d705e6923df1cd78726a7d09f5a4 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:53:52 +0000 Subject: [PATCH 071/226] Add MooshroomTypes generator (#4035) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index c98516e5259..d023f83488d 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -52,6 +52,7 @@ import net.minecraft.world.entity.Display; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.animal.Fox; +import net.minecraft.world.entity.animal.MushroomCow; import net.minecraft.world.entity.animal.Panda; import net.minecraft.world.entity.animal.TropicalFish; import net.minecraft.world.entity.animal.horse.Llama; @@ -284,6 +285,13 @@ private static List generators(final Context context) { "name", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "MooshroomTypes", + MushroomCow.MushroomType.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "FoxTypes", From 5b05543786bf5126044e47c3d4c3513ee2834c1a Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:54:19 +0000 Subject: [PATCH 072/226] Readd StatisticCategories generator (#4036) --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index d023f83488d..8e0b336264d 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -539,11 +539,11 @@ private static List generators(final Context context) { context.relativeClass("statistic", "Statistic"), Registries.CUSTOM_STAT ), - /*new RegistryEntriesValidator<>( // TODO: Needs to be updated + new RegistryEntriesValidator<>( "statistic", "StatisticCategories", - Registry.STAT_TYPE_REGISTRY - ), */ + Registries.STAT_TYPE + ), new RegistryEntriesGenerator<>( "world.generation.structure", "Structures", From 156c3ab7914b39ae42f618af137209ab9a33c024 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 16:58:13 +0000 Subject: [PATCH 073/226] Add EquipmentGroups generator (#4046) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 8e0b336264d..08dbb5c7e32 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -50,6 +50,7 @@ import net.minecraft.world.damagesource.DamageEffects; import net.minecraft.world.damagesource.DamageScaling; import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.animal.MushroomCow; @@ -730,6 +731,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "item.inventory.equipment", + "EquipmentGroups", + EquipmentSlot.Type.class, + "name", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "ItemTiers", From b51645059078f619fd352a8f62b99628d71c1244 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:00:05 +0000 Subject: [PATCH 074/226] Add ParrotTypes generator (#4039) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 08dbb5c7e32..7dc45939538 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -55,6 +55,7 @@ import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.animal.MushroomCow; import net.minecraft.world.entity.animal.Panda; +import net.minecraft.world.entity.animal.Parrot; import net.minecraft.world.entity.animal.TropicalFish; import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.animal.horse.Markings; @@ -286,6 +287,13 @@ private static List generators(final Context context) { "name", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "ParrotTypes", + Parrot.Variant.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "MooshroomTypes", From 491b54e2a18b191fa631a2944a2435870fa8b7ed Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:00:16 +0000 Subject: [PATCH 075/226] Update blockstate property and blockstate propery keys generators (#4033) --- .../vanilla/generator/BlockStatePropertiesGenerator.java | 4 ++++ .../generator/BlockStatePropertyKeysGenerator.java | 8 ++++---- .../spongepowered/vanilla/generator/GeneratorMain.java | 3 +-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertiesGenerator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertiesGenerator.java index ef89a2bb0e8..202e77ae676 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertiesGenerator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertiesGenerator.java @@ -32,6 +32,8 @@ import net.minecraft.core.FrontAndTop; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerState; +import net.minecraft.world.level.block.entity.vault.VaultState; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.level.block.state.properties.BambooLeaves; @@ -144,6 +146,8 @@ static PropertyType ofProperty(final Property prop) { vanillaEnumTypeMapping.put(DripstoneThickness.class, BlockStatePropertiesGenerator.inDataTypePkg("DripstoneSegment")); vanillaEnumTypeMapping.put(FrontAndTop.class, BlockStatePropertiesGenerator.inDataTypePkg("JigsawBlockOrientation")); vanillaEnumTypeMapping.put(ComparatorMode.class, BlockStatePropertiesGenerator.inDataTypePkg("ComparatorMode")); + vanillaEnumTypeMapping.put(TrialSpawnerState.class, BlockStatePropertiesGenerator.inDataTypePkg("TrialSpawnerState")); + vanillaEnumTypeMapping.put(VaultState.class, BlockStatePropertiesGenerator.inDataTypePkg("VaultState")); // Custom Mapping required see StateHolderMixin_API final ClassName portionTypeClass = BlockStatePropertiesGenerator.inDataTypePkg("PortionType"); diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertyKeysGenerator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertyKeysGenerator.java index 105708b57eb..d00816a08ce 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertyKeysGenerator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/BlockStatePropertyKeysGenerator.java @@ -33,6 +33,8 @@ import com.squareup.javapoet.TypeVariableName; import net.minecraft.core.Direction; import net.minecraft.core.FrontAndTop; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerState; +import net.minecraft.world.level.block.entity.vault.VaultState; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.level.block.state.properties.BambooLeaves; @@ -142,6 +144,8 @@ static BlockStatePropertyKeysGenerator.PropertyType ofProperty(final Property vanillaEnumTypeMapping.put(DripstoneThickness.class, BlockStatePropertyKeysGenerator.inDataTypePkg("DripstoneSegment")); vanillaEnumTypeMapping.put(FrontAndTop.class, BlockStatePropertyKeysGenerator.inDataTypePkg("JigsawBlockOrientation")); vanillaEnumTypeMapping.put(ComparatorMode.class, BlockStatePropertyKeysGenerator.inDataTypePkg("ComparatorMode")); + vanillaEnumTypeMapping.put(TrialSpawnerState.class, BlockStatePropertyKeysGenerator.inDataTypePkg("TrialSpawnerState")); + vanillaEnumTypeMapping.put(VaultState.class, BlockStatePropertyKeysGenerator.inDataTypePkg("VaultState")); // Custom Mapping required see StateHolderMixin_API final ClassName portionTypeClass = BlockStatePropertyKeysGenerator.inDataTypePkg("PortionType"); @@ -221,10 +225,6 @@ private static ClassName inDataValuePkg(final String name) { private Map> vanillaProperties() { final Map> vanillaMap = new TreeMap<>(); for (Field field : BlockStateProperties.class.getDeclaredFields()) { - if (field.getName().equals("TRIAL_SPAWNER_STATE")) { - // TODO add spawner states to API - continue; - } try { final Object property = field.get(null); if (property instanceof Property) { diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 7dc45939538..901a5b902f6 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -627,8 +627,7 @@ private static List generators(final Context context) { ), new BlockStateDataProviderGenerator(), new BlockStatePropertiesGenerator(), - // TODO fix me - //new BlockStatePropertyKeysGenerator(), + new BlockStatePropertyKeysGenerator(), new RegistryEntriesGenerator<>( "world.generation.feature", "PlacedFeatures", From 7f4952f6eb2fb6e06b99d95d393d58c37ea4686f Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:04:06 +0000 Subject: [PATCH 076/226] Sort generated fields by name and guard against invalid field names (#4045) --- .../vanilla/generator/RegistryEntriesGenerator.java | 2 +- .../java/org/spongepowered/vanilla/generator/Types.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesGenerator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesGenerator.java index 07eec53b5c8..769325db35d 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesGenerator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesGenerator.java @@ -140,8 +140,8 @@ public void generate(final Context ctx) throws IOException { final Registry finalRegistry = registry; registry.stream() .filter(this.filter) - .sorted(Comparator.comparing(registry::getKey)) .map(v -> this.makeField(this.targetClassSimpleName, fieldType, factoryMethod, finalRegistry.getKey(v), v instanceof FeatureElement fe ? fe.requiredFeatures() : null)) + .sorted(Comparator.comparing(f -> f.name)) .forEachOrdered(clazz::addField); clazz.addMethod(registryMethod); diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/Types.java b/generator/src/main/java/org/spongepowered/vanilla/generator/Types.java index 50c6224926a..518cbb2d6da 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/Types.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/Types.java @@ -101,7 +101,12 @@ public static TypeSpec.Builder utilityClass(final String name, final String clas } static String keyToFieldName(final String key) { - return Types.ILLEGAL_FIELD_CHARACTERS.matcher(key.toUpperCase(Locale.ROOT)).replaceAll("_"); + return switch (key) { + case "5" -> "FIVE"; + case "11" -> "ELEVEN"; + case "13" -> "THIRTEEN"; + default -> Types.ILLEGAL_FIELD_CHARACTERS.matcher(key.toUpperCase(Locale.ROOT)).replaceAll("_"); + }; } public static CodeBlock resourceKey(final ResourceLocation location) { From 5a8e348577a90fd09be733e9e3fe1db41fda0617 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:23:09 +0000 Subject: [PATCH 077/226] Add SculkSensorStates generator (#4047) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 901a5b902f6..7eb493661bb 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -71,6 +71,7 @@ import net.minecraft.world.level.WorldDataConfiguration; import net.minecraft.world.level.block.state.properties.BambooLeaves; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.block.state.properties.SculkSensorPhase; import org.tinylog.Logger; import java.io.IOException; @@ -759,6 +760,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "SculkSensorStates", + SculkSensorPhase.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "entity.display", "TextAlignments", From 28a643e7b5ff5ea98e902c734a097165d71e7ad0 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:23:21 +0000 Subject: [PATCH 078/226] Add MusicDics generator (#4044) --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 7eb493661bb..f0cfda3396e 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -530,6 +530,13 @@ private static List generators(final Context context) { context.relativeClass("data.type", "FrogType"), Registries.FROG_VARIANT ), + new RegistryEntriesGenerator<>( + "effect.sound.music", + "MusicDiscs", + "JUKEBOX_SONG", + context.relativeClass("effect.sound.music", "MusicDisc"), + Registries.JUKEBOX_SONG + ), new RegistryEntriesValidator<>( "item.recipe", "RecipeTypes", From 6096b2a9f249aa1d5d518a84a60a9f1560f742d4 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:23:30 +0000 Subject: [PATCH 079/226] Add MapDecorationType generator (#4043) --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index f0cfda3396e..0b3f8415ae2 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -253,6 +253,13 @@ private static List generators(final Context context) { context.relativeClass("data.type", "ArmorMaterial"), Registries.ARMOR_MATERIAL ), + new RegistryEntriesGenerator<>( + "map.decoration", + "MapDecorationTypes", + "MAP_DECORATION_TYPE", + context.relativeClass("map.decoration", "MapDecorationType"), + Registries.MAP_DECORATION_TYPE + ), new EnumEntriesValidator<>( "data.type", "BambooLeavesTypes", From fb9a737caa867608e39547e4b9445107d4899382 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:23:45 +0000 Subject: [PATCH 080/226] Add RabbitTypes generator (#4040) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 0b3f8415ae2..027226615b5 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -56,6 +56,7 @@ import net.minecraft.world.entity.animal.MushroomCow; import net.minecraft.world.entity.animal.Panda; import net.minecraft.world.entity.animal.Parrot; +import net.minecraft.world.entity.animal.Rabbit; import net.minecraft.world.entity.animal.TropicalFish; import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.animal.horse.Markings; @@ -295,6 +296,13 @@ private static List generators(final Context context) { "name", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "RabbitTypes", + Rabbit.Variant.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "ParrotTypes", From c1cc31fe80dd0101d3fef45240371271be58bdb1 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 17:43:59 +0000 Subject: [PATCH 081/226] Fix windcharge and Armadillo mixins (#4042) --- .../{ => armadillo}/ArmadilloMixin_API.java | 5 ++- .../AbstractWindChargeMixin_API.java | 33 +++++++++++++++++++ .../windcharge/BreezeWindChargeMixin_API.java | 3 +- .../windcharge/WindChargeMixin_API.java | 3 +- src/mixins/resources/mixins.sponge.api.json | 3 +- 5 files changed, 39 insertions(+), 8 deletions(-) rename src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/{ => armadillo}/ArmadilloMixin_API.java (93%) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/AbstractWindChargeMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/armadillo/ArmadilloMixin_API.java similarity index 93% rename from src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java rename to src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/armadillo/ArmadilloMixin_API.java index 53417095cf1..16b30768606 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/ArmadilloMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/armadillo/ArmadilloMixin_API.java @@ -22,12 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.common.mixin.api.minecraft.world.entity.animal; +package org.spongepowered.common.mixin.api.minecraft.world.entity.animal.armadillo; import org.spongepowered.api.entity.living.animal.Armadillo; import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.entity.animal.armadillo.Armadillo.class) -public abstract class ArmadilloMixin_API extends AnimalMixin_API implements Armadillo { - +public abstract class ArmadilloMixin_API implements Armadillo { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/AbstractWindChargeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/AbstractWindChargeMixin_API.java new file mode 100644 index 00000000000..360b9e610a0 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/AbstractWindChargeMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.windcharge; + +import net.minecraft.world.entity.projectile.windcharge.AbstractWindCharge; +import org.spongepowered.api.entity.projectile.windcharge.WindChargeLike; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(AbstractWindCharge.class) +public abstract class AbstractWindChargeMixin_API implements WindChargeLike { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java index 58cc04fea37..f5313aff01b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/BreezeWindChargeMixin_API.java @@ -26,8 +26,7 @@ import org.spongepowered.api.entity.projectile.windcharge.BreezeWindCharge; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.ProjectileMixin_API; @Mixin(net.minecraft.world.entity.projectile.windcharge.BreezeWindCharge.class) -public abstract class BreezeWindChargeMixin_API extends ProjectileMixin_API implements BreezeWindCharge { +public abstract class BreezeWindChargeMixin_API extends AbstractWindChargeMixin_API implements BreezeWindCharge { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java index 92aff8aebd6..5988ba9f4d0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/windcharge/WindChargeMixin_API.java @@ -26,8 +26,7 @@ import org.spongepowered.api.entity.projectile.windcharge.WindCharge; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.mixin.api.minecraft.world.entity.projectile.AbstractHurtingProjectileMixin_API; @Mixin(net.minecraft.world.entity.projectile.windcharge.WindCharge.class) -public abstract class WindChargeMixin_API extends AbstractHurtingProjectileMixin_API implements WindCharge { +public abstract class WindChargeMixin_API extends AbstractWindChargeMixin_API implements WindCharge { } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index cee72b67217..71f13dd293c 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -135,7 +135,6 @@ "minecraft.world.entity.animal.AbstractGolemMixin_API", "minecraft.world.entity.animal.AbstractSchoolingFishMixin_API", "minecraft.world.entity.animal.AnimalMixin_API", - "minecraft.world.entity.animal.ArmadilloMixin_API", "minecraft.world.entity.animal.BeeMixin_API", "minecraft.world.entity.animal.CatMixin_API", "minecraft.world.entity.animal.CatVariantMixin_API", @@ -169,6 +168,7 @@ "minecraft.world.entity.animal.WaterAnimalMixin_API", "minecraft.world.entity.animal.WolfMixin_API", "minecraft.world.entity.animal.allay.AllayMixin_API", + "minecraft.world.entity.animal.armadillo.ArmadilloMixin_API", "minecraft.world.entity.animal.camel.CamelMixin_API", "minecraft.world.entity.animal.frog.FrogMixin_API", "minecraft.world.entity.animal.frog.TadpoleMixin_API", @@ -257,6 +257,7 @@ "minecraft.world.entity.projectile.AbstractArrow_PickupMixin_API", "minecraft.world.entity.projectile.AbstractArrowMixin_API", "minecraft.world.entity.projectile.AbstractHurtingProjectileMixin_API", + "minecraft.world.entity.projectile.windcharge.AbstractWindChargeMixin_API", "minecraft.world.entity.projectile.ArrowMixin_API", "minecraft.world.entity.projectile.DragonFireballMixin_API", "minecraft.world.entity.projectile.EvokerFangsMixin_API", From fd74cc482d9ceca05f3b3942ca1fa2d1f5765f14 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 22 Jun 2024 20:51:46 +0200 Subject: [PATCH 082/226] fix DataDeserializer for numbers --- .../common/data/DataDeserializer.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/org/spongepowered/common/data/DataDeserializer.java b/src/main/java/org/spongepowered/common/data/DataDeserializer.java index bdd68b78112..8fd4974d359 100644 --- a/src/main/java/org/spongepowered/common/data/DataDeserializer.java +++ b/src/main/java/org/spongepowered/common/data/DataDeserializer.java @@ -95,6 +95,28 @@ public static BiFunction> deserializer(fina final BiFunction> valueDeserializer = DataDeserializer.deserializer(valueType); return (view, dataQuery) -> (Optional) DataDeserializer.deserializeMap(view, dataQuery, keyDeserializer, valueDeserializer); } + // Number Type Deserializers + if (rawType == Long.class) { + return (view, dataQuery) -> (Optional) view.getLong(dataQuery); + } + if (rawType == Integer.class) { + return (view, dataQuery) -> (Optional) view.getInt(dataQuery); + } + if (rawType == Short.class) { + return (view, dataQuery) -> (Optional) view.getShort(dataQuery); + } + if (rawType == Byte.class) { + return (view, dataQuery) -> (Optional) view.getByte(dataQuery); + } + if (rawType == Double.class) { + return (view, dataQuery) -> (Optional) view.getDouble(dataQuery); + } + if (rawType == Float.class) { + return (view, dataQuery) -> (Optional) view.getFloat(dataQuery); + } + if (rawType == Boolean.class) { + return (view, dataQuery) -> (Optional) view.getBoolean(dataQuery); + } return (view, dataQuery) -> (Optional) view.get(dataQuery); } From b9194b5c6875f53a3e5bbdf9f0f00c8d81d74021 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Sat, 22 Jun 2024 20:14:12 +0200 Subject: [PATCH 083/226] Keep old name for musicdics registry --- .../java/org/spongepowered/vanilla/generator/GeneratorMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 027226615b5..8a29eb7f428 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -548,7 +548,7 @@ private static List generators(final Context context) { new RegistryEntriesGenerator<>( "effect.sound.music", "MusicDiscs", - "JUKEBOX_SONG", + "MUSIC_DISC", context.relativeClass("effect.sound.music", "MusicDisc"), Registries.JUKEBOX_SONG ), From ad2f6ec1375e743b6e2b6ccd7b4951b430486dfc Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 22 Jun 2024 20:55:55 +0200 Subject: [PATCH 084/226] server scope MUSIC_DISC --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 8a29eb7f428..779c9d383e0 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -550,7 +550,9 @@ private static List generators(final Context context) { "MusicDiscs", "MUSIC_DISC", context.relativeClass("effect.sound.music", "MusicDisc"), - Registries.JUKEBOX_SONG + Registries.JUKEBOX_SONG, + $ -> true, + RegistryScope.SERVER ), new RegistryEntriesValidator<>( "item.recipe", From 81ab80a389e294e6fc9b8d323a59fe672fcc7a34 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 22 Jun 2024 21:56:10 +0000 Subject: [PATCH 085/226] Add registrytest testplugin (#4049) --- .../test/registry/RegistryTest.java | 175 ++++++++++++++++++ .../resources/META-INF/sponge_plugins.json | 6 + 2 files changed, 181 insertions(+) create mode 100644 testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java diff --git a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java new file mode 100644 index 00000000000..54a042a6cbf --- /dev/null +++ b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java @@ -0,0 +1,175 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.test.registry; + +import com.google.inject.Inject; +import net.kyori.adventure.text.Component; +import org.apache.logging.log4j.Logger; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.registry.DefaultedRegistryReference; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.util.annotation.CatalogedBy; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; +import org.spongepowered.test.LoadableModule; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; + +@Plugin("registrytest") +public final class RegistryTest implements LoadableModule { + + private final PluginContainer plugin; + private final Logger logger; + private boolean verbose; + + @Inject + public RegistryTest(final PluginContainer plugin, final Logger logger) { + this.plugin = plugin; + this.logger = logger; + } + + @Override + public void enable(final CommandContext ctx) { + } + + @Listener + private void onRegisterSpongeCommand(final RegisterCommandEvent event) { + event.register( + this.plugin, + Command.builder() + .executor(context -> { + this.verbose = !this.verbose; + context.sendMessage(Component.text("Verbose flag set to " + this.verbose)); + return CommandResult.success(); + }) + .build(), + "toggleverbose"); + event.register( + this.plugin, + Command.builder() + .executor(context -> { + for (final Field field : RegistryTypes.class.getDeclaredFields()) { + final Object registryField; + try { + registryField = field.get(null); + } catch (final IllegalAccessException e) { + this.logger.error("Failed to get field {}: {}", field.getName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (registryField instanceof DefaultedRegistryType registryType) { + if (registryType.find().isEmpty()) { + this.logger.error("Registry {} is empty", registryType.location()); + continue; + } + + final var typeArg = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + final Class catalogEntryClass; + switch (typeArg) { + case final ParameterizedType parameterizedTypeArg -> + catalogEntryClass = (Class) parameterizedTypeArg.getRawType(); + case final Class clazz -> catalogEntryClass = clazz; + case null, default -> { + this.logger.error("Unhandled catalog entry arg type: {}", typeArg); + continue; + } + } + + final var catalogedByAnnotation = catalogEntryClass.getDeclaredAnnotation(CatalogedBy.class); + + if (catalogedByAnnotation == null) { + this.logger.error("Class {} in registry {} is not annotated with CatalogedBy", catalogEntryClass.getSimpleName(), registryType.location()); + continue; + } + + final var catalogClass = catalogedByAnnotation.value()[0]; + final Method registryMethod; + try { + registryMethod = catalogClass.getDeclaredMethod("registry"); + } catch (final NoSuchMethodException e) { + this.logger.error("{}.registry() does not exist", catalogClass.getSimpleName()); + continue; + } + + final Object registryReturn; + try { + registryReturn = registryMethod.invoke(null); + } catch (final Throwable e) { + this.logger.error("{}.registry() failed: {}", catalogClass.getSimpleName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (registryReturn == null) { + this.logger.error("{}.registry() returned null", catalogClass.getSimpleName()); + continue; + } + + if (registryReturn != registryType.get()) { + this.logger.error("{}.registry() returned a different registry than the one specified in RegistryTypes", catalogClass.getSimpleName()); + continue; + } + + for (Field catalogField : catalogClass.getDeclaredFields()) { + final Object catalogObj; + try { + catalogObj = catalogField.get(null); + } catch (final Throwable e) { + this.logger.error("Failed to get field {}: {}", catalogField.getName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (catalogObj instanceof DefaultedRegistryReference reference) { + if (reference.find().isEmpty()) { + this.logger.error("{}.{}.find() is empty", catalogClass.getSimpleName(), catalogField.getName()); + } + } + } + + } else { + this.logger.error("{} is not a DefaultedRegistryType", field.getName()); + } + } + return CommandResult.success(); + }) + .build(), + "checkregistries"); + } +} diff --git a/testplugins/src/main/resources/META-INF/sponge_plugins.json b/testplugins/src/main/resources/META-INF/sponge_plugins.json index 1e06d977256..3e884bea207 100644 --- a/testplugins/src/main/resources/META-INF/sponge_plugins.json +++ b/testplugins/src/main/resources/META-INF/sponge_plugins.json @@ -115,6 +115,12 @@ "entrypoint": "org.spongepowered.test.recipe.RecipeTest", "description": "Testing recipes" }, + { + "id": "registrytest", + "name": "Registry Test", + "entrypoint": "org.spongepowered.test.registry.RegistryTest", + "description": "Testing registries" + }, { "id": "particletest", "name": "Particle Test", From c075da9b3d4c2e97bad21ca483b6ce6ecf250c78 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 11:37:40 +0000 Subject: [PATCH 086/226] Add DripstoneSegments generator (#4053) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 779c9d383e0..6adc4817804 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -71,6 +71,7 @@ import net.minecraft.world.level.GameRules; import net.minecraft.world.level.WorldDataConfiguration; import net.minecraft.world.level.block.state.properties.BambooLeaves; +import net.minecraft.world.level.block.state.properties.DripstoneThickness; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.SculkSensorPhase; import org.tinylog.Logger; @@ -770,6 +771,13 @@ private static List generators(final Context context) { "name", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "DripstoneSegments", + DripstoneThickness.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "ItemTiers", From e1fd53b1d134aa1f14a76ec176550c199f28c898 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 11:37:52 +0000 Subject: [PATCH 087/226] Add Tilts generator (#4052) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 6adc4817804..a7ce262c11f 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -74,6 +74,7 @@ import net.minecraft.world.level.block.state.properties.DripstoneThickness; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.SculkSensorPhase; +import net.minecraft.world.level.block.state.properties.Tilt; import org.tinylog.Logger; import java.io.IOException; @@ -792,6 +793,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "Tilts", + Tilt.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "SculkSensorStates", From ff527187f2a4e5bccc645e882c6da84d0ab5e7c1 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 11:38:06 +0000 Subject: [PATCH 088/226] Add TrialSpawnerStates generator (#4051) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index a7ce262c11f..2e88c3a0cc6 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -70,6 +70,7 @@ import net.minecraft.world.item.component.FireworkExplosion; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.WorldDataConfiguration; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerState; import net.minecraft.world.level.block.state.properties.BambooLeaves; import net.minecraft.world.level.block.state.properties.DripstoneThickness; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; @@ -807,6 +808,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "TrialSpawnerStates", + TrialSpawnerState.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "entity.display", "TextAlignments", From 4cbf122fe8d2fcc67286402fe0d32d15b9e2e84d Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 11:43:18 +0000 Subject: [PATCH 089/226] Add PushReactions generator (#4050) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 2e88c3a0cc6..a8c2754ce1f 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -76,6 +76,7 @@ import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.SculkSensorPhase; import net.minecraft.world.level.block.state.properties.Tilt; +import net.minecraft.world.level.material.PushReaction; import org.tinylog.Logger; import java.io.IOException; @@ -766,6 +767,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "data.type", + "PushReactions", + PushReaction.class, + "name", + "sponge" + ), new EnumEntriesValidator<>( "item.inventory.equipment", "EquipmentGroups", From 41b91d40b4e3ab20c724b8a6d035cbb1d67805ae Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 13 Jun 2024 20:31:44 +0300 Subject: [PATCH 090/226] fix particles --- SpongeAPI | 2 +- .../effect/particle/SpongeParticleHelper.java | 90 +++++++------------ .../registry/loader/SpongeRegistryLoader.java | 17 ++-- .../common/util/ParticleOptionUtil.java | 21 ++++- .../test/particle/ParticleTest.java | 4 - 5 files changed, 60 insertions(+), 74 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index dc4462dc6f6..0c9df112f0f 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit dc4462dc6f6c49a93b90589c05957043a3aa5717 +Subproject commit 0c9df112f0f90ef3096e9f39e473061a24c07f4b diff --git a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java index 3cc0a622f25..caf93a54f29 100644 --- a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java +++ b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java @@ -24,8 +24,8 @@ */ package org.spongepowered.common.effect.particle; -import net.minecraft.core.BlockPos; import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ColorParticleOption; import net.minecraft.core.particles.DustColorTransitionOptions; import net.minecraft.core.particles.DustParticleOptions; import net.minecraft.core.particles.ItemParticleOption; @@ -39,18 +39,17 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.players.PlayerList; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.gameevent.BlockPositionSource; +import net.minecraft.util.FastColor; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockState; -import org.spongepowered.api.block.BlockType; import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.particle.ParticleOptions; import org.spongepowered.api.effect.particle.ParticleType; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.util.Color; -import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.world.PositionSource; +import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3f; @@ -58,7 +57,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Random; public final class SpongeParticleHelper { @@ -153,7 +151,7 @@ private static CachedParticlePacket getNamedPacket(final ParticleEffect effect, final ItemStackSnapshot snapshot = effect.optionOrDefault(ParticleOptions.ITEM_STACK_SNAPSHOT).get(); final ItemParticleOption particleData = new ItemParticleOption( (net.minecraft.core.particles.ParticleType) internalType, - (net.minecraft.world.item.ItemStack) (Object) snapshot.createStack()); + ItemStackUtil.fromSnapshotToNative(snapshot)); return new NamedCachedPacket(particleData, offset, quantity, velocity); } else if (internalType == ParticleTypes.SCULK_CHARGE) { final double roll = effect.optionOrDefault(ParticleOptions.ROLL).get(); @@ -164,63 +162,26 @@ private static CachedParticlePacket getNamedPacket(final ParticleEffect effect, final ShriekParticleOption particleData = new ShriekParticleOption(delay); return new NamedCachedPacket(particleData, offset, quantity, velocity); } else if (internalType == ParticleTypes.VIBRATION) { + final PositionSource source = effect.optionOrDefault(ParticleOptions.DESTINATION).get(); final Ticks delay = effect.optionOrDefault(ParticleOptions.TRAVEL_TIME).get(); - // TODO add position source - final VibrationParticleOption particleData = new VibrationParticleOption(new BlockPositionSource(BlockPos.ZERO), (int) delay.ticks()); + final VibrationParticleOption particleData = new VibrationParticleOption( + (net.minecraft.world.level.gameevent.PositionSource) source, + (int) delay.ticks()); + return new NamedCachedPacket(particleData, offset, quantity, velocity); + } else if (internalType == ParticleTypes.ENTITY_EFFECT) { + // This particle type supports color and opacity options. + final Color color = effect.optionOrDefault(ParticleOptions.COLOR).get(); + final double opacity = effect.optionOrDefault(ParticleOptions.OPACITY).get(); + final ColorParticleOption particleData = ColorParticleOption.create( + (net.minecraft.core.particles.ParticleType) internalType, + FastColor.ARGB32.color(FastColor.as8BitChannel((float) opacity), color.red(), color.green(), color.blue())); return new NamedCachedPacket(particleData, offset, quantity, velocity); } - // Otherwise, we don't really know how to get a valid IParticleData. Sorry mods! + // Otherwise, we don't really know how to get a valid ParticleOptions. Sorry mods! return EmptyCachedPacket.INSTANCE; } - public static int getDirectionId(Direction direction) { - if (direction.isSecondaryOrdinal()) { - direction = Direction.closest(direction.asOffset(), Direction.Division.ORDINAL); - } - switch (direction) { - case SOUTHEAST: - return 0; - case SOUTH: - return 1; - case SOUTHWEST: - return 2; - case EAST: - return 3; - case WEST: - return 5; - case NORTHEAST: - return 6; - case NORTH: - return 7; - case NORTHWEST: - return 8; - default: - return 4; - } - } - - public static int getBlockStateId(final ParticleEffect effect, final Optional defaultBlockState) { - final Optional blockState = effect.option(ParticleOptions.BLOCK_STATE); - if (blockState.isPresent()) { - // Use the provided block state option. - return Block.getId((net.minecraft.world.level.block.state.BlockState) blockState.get()); - } - - final Optional itemSnapshot = effect.option(ParticleOptions.ITEM_STACK_SNAPSHOT); - if (itemSnapshot.isPresent()) { - // Try to convert the item into a usable block state. - final Optional blockType = itemSnapshot.get().type().block(); - // TODO: correct behavior? - return blockType.map(type -> Block.getId((net.minecraft.world.level.block.state.BlockState) type.defaultState())) - .orElse(0); - } - - // Otherwise, use the default block state option if available. - return defaultBlockState.map(state -> Block.getId((net.minecraft.world.level.block.state.BlockState) state)) - .orElse(0); - } - public static ParticleEffect spongeParticleOptions(final net.minecraft.core.particles.ParticleOptions effect) { final net.minecraft.core.particles.ParticleType type = effect.getType(); if (type instanceof SimpleParticleType) { @@ -246,14 +207,23 @@ public static ParticleEffect spongeParticleOptions(final net.minecraft.core.part )); } else if (effect instanceof ItemParticleOption itemOptions) { // This particle type supports an item option. - return new SpongeParticleEffect((ParticleType) type, Map.of(ParticleOptions.BLOCK_STATE.get(), itemOptions.getItem().copy())); + return new SpongeParticleEffect((ParticleType) type, Map.of(ParticleOptions.ITEM_STACK_SNAPSHOT.get(), ItemStackUtil.snapshotOf(itemOptions.getItem()))); } else if (effect instanceof SculkChargeParticleOptions sculkChargeOptions) { return new SpongeParticleEffect((ParticleType) type, Map.of(ParticleOptions.ROLL.get(), sculkChargeOptions.roll())); } else if (effect instanceof ShriekParticleOption shriekOption) { return new SpongeParticleEffect((ParticleType) type, Map.of(ParticleOptions.DELAY.get(), shriekOption.getDelay())); } else if (effect instanceof VibrationParticleOption vibrationOptions) { - // TODO add position source - return new SpongeParticleEffect((ParticleType) type, Map.of(ParticleOptions.TRAVEL_TIME.get(), Ticks.of(vibrationOptions.getArrivalInTicks()))); + return new SpongeParticleEffect((ParticleType) type, Map.of( + ParticleOptions.DESTINATION.get(), vibrationOptions.getDestination(), + ParticleOptions.TRAVEL_TIME.get(), Ticks.of(vibrationOptions.getArrivalInTicks()) + )); + } else if (effect instanceof ColorParticleOption colorOptions) { + // This particle type supports color and opacity options. + return new SpongeParticleEffect((ParticleType) type, Map.of( + ParticleOptions.COLOR.get(), Color.of( + Vector3f.from(colorOptions.getRed(), colorOptions.getGreen(), colorOptions.getBlue()).mul(255)), + ParticleOptions.OPACITY.get(), colorOptions.getAlpha() + )); } return new SpongeParticleEffect((ParticleType) type, Collections.emptyMap()); diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index fcc636dc77a..de3bfb4931a 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -48,7 +48,6 @@ import org.spongepowered.api.data.type.SkinParts; import org.spongepowered.api.effect.particle.ParticleOption; import org.spongepowered.api.effect.particle.ParticleOptions; -import org.spongepowered.api.effect.potion.PotionEffectType; import org.spongepowered.api.entity.ai.goal.GoalExecutorType; import org.spongepowered.api.entity.ai.goal.GoalExecutorTypes; import org.spongepowered.api.entity.ai.goal.GoalType; @@ -91,12 +90,12 @@ import org.spongepowered.api.service.economy.transaction.TransactionType; import org.spongepowered.api.service.economy.transaction.TransactionTypes; import org.spongepowered.api.util.Color; -import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.Ticks; import org.spongepowered.api.util.orientation.Orientation; import org.spongepowered.api.util.orientation.Orientations; import org.spongepowered.api.world.ChunkRegenerateFlag; import org.spongepowered.api.world.ChunkRegenerateFlags; +import org.spongepowered.api.world.PositionSource; import org.spongepowered.api.world.generation.config.flat.FlatGeneratorConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfigs; @@ -370,13 +369,17 @@ public static RegistryLoader> particleOption() { l.add(ParticleOptions.BLOCK_STATE, k -> new SpongeParticleOption<>(BlockState.class)); l.add(ParticleOptions.COLOR, k -> new SpongeParticleOption<>(Color.class)); l.add(ParticleOptions.DELAY, k -> new SpongeParticleOption<>(Double.class)); - l.add(ParticleOptions.DIRECTION, k -> new SpongeParticleOption<>(Direction.class)); - l.add(ParticleOptions.ITEM_STACK_SNAPSHOT, k -> new SpongeParticleOption<>(ItemStackSnapshot.class)); + l.add(ParticleOptions.DESTINATION, k -> new SpongeParticleOption<>(PositionSource.class)); + l.add(ParticleOptions.ITEM_STACK_SNAPSHOT, k -> new SpongeParticleOption<>(ItemStackSnapshot.class, + v -> v.isEmpty() ? new IllegalArgumentException("ItemStackSnapshot must not be empty") : null)); l.add(ParticleOptions.OFFSET, k -> new SpongeParticleOption<>(Vector3d.class)); - l.add(ParticleOptions.POTION_EFFECT_TYPE, k -> new SpongeParticleOption<>(PotionEffectType.class)); - l.add(ParticleOptions.QUANTITY, k -> new SpongeParticleOption<>(Integer.class, v -> v < 1 ? new IllegalArgumentException("Quantity must be at least one") : null)); + l.add(ParticleOptions.OPACITY, k -> new SpongeParticleOption<>(Double.class, + v -> v < 0 || v > 1 ? new IllegalArgumentException("Opacity must be between 0 and 1") : null)); + l.add(ParticleOptions.QUANTITY, k -> new SpongeParticleOption<>(Integer.class, + v -> v < 1 ? new IllegalArgumentException("Quantity must be at least one") : null)); l.add(ParticleOptions.ROLL, k -> new SpongeParticleOption<>(Double.class)); - l.add(ParticleOptions.SCALE, k -> new SpongeParticleOption<>(Double.class, v -> v < 0 ? new IllegalArgumentException("Scale must not be negative") : null)); + l.add(ParticleOptions.SCALE, k -> new SpongeParticleOption<>(Double.class, + v -> v < 0 ? new IllegalArgumentException("Scale must not be negative") : null)); l.add(ParticleOptions.TO_COLOR, k -> new SpongeParticleOption<>(Color.class)); l.add(ParticleOptions.TRAVEL_TIME, k -> new SpongeParticleOption<>(Ticks.class)); l.add(ParticleOptions.VELOCITY, k -> new SpongeParticleOption<>(Vector3d.class)); diff --git a/src/main/java/org/spongepowered/common/util/ParticleOptionUtil.java b/src/main/java/org/spongepowered/common/util/ParticleOptionUtil.java index 0bb53430fc5..f3c37309893 100644 --- a/src/main/java/org/spongepowered/common/util/ParticleOptionUtil.java +++ b/src/main/java/org/spongepowered/common/util/ParticleOptionUtil.java @@ -30,9 +30,12 @@ import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.effect.particle.ParticleOption; import org.spongepowered.api.effect.particle.ParticleOptions; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.ItemTypes; +import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.util.Color; +import org.spongepowered.api.world.PositionSource; import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; import java.util.HashMap; import java.util.Map; @@ -52,10 +55,24 @@ public static ImmutableMap, Object> generateDefaultsForNamed(P || type == ParticleTypes.FALLING_DUST || type == ParticleTypes.DUST_PILLAR) { options.put(ParticleOptions.BLOCK_STATE.get(), BlockTypes.AIR.get().defaultState()); } else if (type == ParticleTypes.ITEM) { - options.put(ParticleOptions.ITEM_STACK_SNAPSHOT.get(), ItemStackSnapshot.empty()); + options.put(ParticleOptions.ITEM_STACK_SNAPSHOT.get(), ItemStack.of(ItemTypes.STONE).createSnapshot()); } else if (type == ParticleTypes.DUST) { options.put(ParticleOptions.COLOR.get(), Color.RED); options.put(ParticleOptions.SCALE.get(), 1.0d); + } else if (type == ParticleTypes.DUST_COLOR_TRANSITION) { + options.put(ParticleOptions.COLOR.get(), Color.RED); + options.put(ParticleOptions.TO_COLOR.get(), Color.RED); + options.put(ParticleOptions.SCALE.get(), 1.0d); + } else if (type == ParticleTypes.SCULK_CHARGE) { + options.put(ParticleOptions.ROLL.get(), 0); + } else if (type == ParticleTypes.SHRIEK) { + options.put(ParticleOptions.DELAY.get(), 0); + } else if (type == ParticleTypes.VIBRATION) { + options.put(ParticleOptions.DESTINATION.get(), PositionSource.of(Vector3i.ZERO)); + options.put(ParticleOptions.TRAVEL_TIME.get(), 0); + } else if (type == ParticleTypes.ENTITY_EFFECT) { + options.put(ParticleOptions.COLOR.get(), Color.RED); + options.put(ParticleOptions.OPACITY.get(), 1.0d); } return ImmutableMap.copyOf(options); diff --git a/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java b/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java index b8b06c6a491..0a101f6c267 100644 --- a/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java @@ -37,7 +37,6 @@ import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.particle.ParticleOptions; import org.spongepowered.api.effect.particle.ParticleType; -import org.spongepowered.api.effect.potion.PotionEffectTypes; import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; @@ -45,7 +44,6 @@ import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.util.Color; -import org.spongepowered.api.util.Direction; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; @@ -90,8 +88,6 @@ private void spawnParticles(ServerPlayer serverPlayer, ParticleType type) { .option(ParticleOptions.BLOCK_STATE, BlockTypes.DIAMOND_BLOCK.get().defaultState()) .option(ParticleOptions.COLOR, Color.LIME) .option(ParticleOptions.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.GOLDEN_APPLE.get()).createSnapshot()) - .option(ParticleOptions.DIRECTION, Direction.EAST) - .option(ParticleOptions.POTION_EFFECT_TYPE, PotionEffectTypes.HASTE.get()) .offset(Vector3d.from(0, 1, 1)) .velocity(Vector3d.RIGHT.mul(0.5)) .quantity(20) From 10011f9e63d169caf99cd1820a4f20050c5da57b Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 13 Jun 2024 21:52:31 +0300 Subject: [PATCH 091/226] Implement PositionSource --- .../registry/SpongeFactoryProvider.java | 3 + .../world/SpongePositionSourceFactory.java | 59 +++++++++++++++++++ .../gameevent/PositionSourceMixin_API.java | 32 ++++++++++ src/mixins/resources/mixins.sponge.api.json | 3 +- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java diff --git a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java index f913eb04cb9..40359c793f3 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java @@ -81,6 +81,7 @@ import org.spongepowered.api.util.blockray.RayTrace; import org.spongepowered.api.world.BlockChangeFlag; import org.spongepowered.api.world.DefaultWorldKeys; +import org.spongepowered.api.world.PositionSource; import org.spongepowered.api.world.WorldTypeEffect; import org.spongepowered.api.world.biome.AttributedBiome; import org.spongepowered.api.world.biome.BiomeAttributes; @@ -149,6 +150,7 @@ import org.spongepowered.common.util.SpongeTransform; import org.spongepowered.common.util.raytrace.SpongeRayTraceFactory; import org.spongepowered.common.world.SpongeDefaultWorldKeysFactory; +import org.spongepowered.common.world.SpongePositionSourceFactory; import org.spongepowered.common.world.SpongeWorldTypeEffect; import org.spongepowered.common.world.biome.SpongeAttributedBiome; import org.spongepowered.common.world.biome.SpongeBiomeAttributesFactory; @@ -275,6 +277,7 @@ public void registerDefaultFactories() { .registerFactory(IntegerStateProperty.Factory.class, new BlockStatePropertyImpl.IntegerFactoryImpl()) .registerFactory(EnumStateProperty.Factory.class, new BlockStatePropertyImpl.EnumFactoryImpl()) .registerFactory(DefaultWorldKeys.Factory.class, new SpongeDefaultWorldKeysFactory()) + .registerFactory(PositionSource.Factory.class, new SpongePositionSourceFactory()) .registerFactory(JigsawPoolElement.Factory.class, new SpongeJigsawFactory()) .registerFactory(ParticleConfig.Factory.class, new SpongeParticleConfigFactory()) .registerFactory(SoundConfig.Factory.class, new SpongeSoundConfigFactory()) diff --git a/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java b/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java new file mode 100644 index 00000000000..34dbc468616 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java @@ -0,0 +1,59 @@ +/* + * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.gameevent.BlockPositionSource; +import net.minecraft.world.level.gameevent.EntityPositionSource; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.world.PositionSource; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Objects; + +public final class SpongePositionSourceFactory implements PositionSource.Factory { + + @Override + public PositionSource of(final Vector3i position) { + Objects.requireNonNull(position, "position"); + return this.of(position.x(), position.y(), position.z()); + } + + @Override + public PositionSource of(final int x, final int y, final int z) { + return (PositionSource) new BlockPositionSource(new BlockPos(x, y, z)); + } + + @Override + public PositionSource of(final Entity entity) { + return this.of(entity, entity.eyeHeight().get()); + } + + @Override + public PositionSource of(final Entity entity, final double yOffset) { + Objects.requireNonNull(entity, "entity"); + return (PositionSource) new EntityPositionSource((net.minecraft.world.entity.Entity) entity, (float) yOffset); + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java new file mode 100644 index 00000000000..dda9757cb41 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.level.gameevent; + +import org.spongepowered.api.world.PositionSource; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.level.gameevent.PositionSource.class) +public interface PositionSourceMixin_API extends PositionSource { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 71f13dd293c..95bc29cbd7e 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -428,6 +428,7 @@ "minecraft.world.level.chunk.LevelChunkMixin_API", "minecraft.world.level.chunk.ProtoChunkMixin_API", "minecraft.world.level.dimension.DimensionTypeMixin_API", + "minecraft.world.level.gameevent.PositionSourceMixin_API", "minecraft.world.level.levelgen.DensityFunctionMixin_API", "minecraft.world.level.levelgen.FlatLevelSourceMixin_API", "minecraft.world.level.levelgen.GenerationStep_CarvingMixin_API", @@ -501,5 +502,5 @@ ], "overwrites": { "conformVisibility": true - } + } } From f0d9a82a0a0c5a9baaf49ae76c7ab9b72bf93da4 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 17 Jun 2024 03:41:15 +0300 Subject: [PATCH 092/226] spotlessApply --- .../common/effect/particle/SpongeParticleHelper.java | 2 +- .../spongepowered/common/world/SpongePositionSourceFactory.java | 2 +- .../world/level/gameevent/PositionSourceMixin_API.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java index caf93a54f29..cc55602fbab 100644 --- a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java +++ b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java @@ -38,8 +38,8 @@ import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.server.players.PlayerList; -import net.minecraft.world.level.Level; import net.minecraft.util.FastColor; +import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.effect.particle.ParticleEffect; diff --git a/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java b/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java index 34dbc468616..338497401d6 100644 --- a/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java +++ b/src/main/java/org/spongepowered/common/world/SpongePositionSourceFactory.java @@ -1,5 +1,5 @@ /* - * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * This file is part of Sponge, licensed under the MIT License (MIT). * * Copyright (c) SpongePowered * Copyright (c) contributors diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java index dda9757cb41..dddb90a4194 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/gameevent/PositionSourceMixin_API.java @@ -1,5 +1,5 @@ /* - * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * This file is part of Sponge, licensed under the MIT License (MIT). * * Copyright (c) SpongePowered * Copyright (c) contributors From ae6f6c92be89708aef7b4b1c5fd623bfbf141265 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 11 Jun 2024 17:18:25 +0300 Subject: [PATCH 093/226] fix written book --- .../item/stack/BookItemStackData.java | 14 +++----- .../spongepowered/common/util/BookUtil.java | 35 +++++++------------ 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java index 94794386740..0ac24a25528 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java @@ -55,8 +55,7 @@ public static void register(final DataProviderRegistrator registrator) { return LegacyComponentSerializer.legacySection().deserialize(content.author()); }) .set((h, v) -> { - final WrittenBookContent content = h.get(DataComponents.WRITTEN_BOOK_CONTENT); - // TODO handle missing data? + final WrittenBookContent content = h.getOrDefault(DataComponents.WRITTEN_BOOK_CONTENT, WrittenBookContent.EMPTY); final String author = LegacyComponentSerializer.legacySection().serialize(v); h.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(content.title(), author, content.generation(), content.pages(), content.resolved())); @@ -71,11 +70,10 @@ public static void register(final DataProviderRegistrator registrator) { return content.generation(); }) .setAnd((h, v) -> { - if (v < 0) { + if (v < 0 || v > 3) { return false; } - final WrittenBookContent content = h.get(DataComponents.WRITTEN_BOOK_CONTENT); - // TODO handle missing data? + final WrittenBookContent content = h.getOrDefault(DataComponents.WRITTEN_BOOK_CONTENT, WrittenBookContent.EMPTY); h.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(content.title(), content.author(), v, content.pages(), content.resolved())); return true; @@ -90,15 +88,13 @@ public static void register(final DataProviderRegistrator registrator) { return content.pages().stream().map(Filterable::raw).map(SpongeAdventure::asAdventure).toList(); }) .set((h, v) -> { - final WrittenBookContent content = h.get(DataComponents.WRITTEN_BOOK_CONTENT); - // TODO handle missing data? + final WrittenBookContent content = h.getOrDefault(DataComponents.WRITTEN_BOOK_CONTENT, WrittenBookContent.EMPTY); var pages = v.stream().map(SpongeAdventure::asVanilla).map(Filterable::passThrough).toList(); h.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(content.title(), content.author(), content.generation(), pages, content.resolved())); }) .delete(h -> { - final WrittenBookContent content = h.get(DataComponents.WRITTEN_BOOK_CONTENT); - // TODO handle missing data? + final WrittenBookContent content = h.getOrDefault(DataComponents.WRITTEN_BOOK_CONTENT, WrittenBookContent.EMPTY); h.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(content.title(), content.author(), content.generation(), Collections.emptyList(), content.resolved())); }) diff --git a/src/main/java/org/spongepowered/common/util/BookUtil.java b/src/main/java/org/spongepowered/common/util/BookUtil.java index 9b1062e6afa..3d0349bf5d9 100644 --- a/src/main/java/org/spongepowered/common/util/BookUtil.java +++ b/src/main/java/org/spongepowered/common/util/BookUtil.java @@ -24,9 +24,7 @@ */ package org.spongepowered.common.util; -import com.google.common.collect.Lists; import net.kyori.adventure.inventory.Book; -import net.kyori.adventure.translation.GlobalTranslator; import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; import net.minecraft.network.protocol.game.ClientboundOpenBookPacket; import net.minecraft.server.level.ServerPlayer; @@ -40,44 +38,35 @@ import org.spongepowered.common.item.util.ItemStackUtil; import java.util.Collection; -import java.util.Locale; -import java.util.Objects; public final class BookUtil { - public static final int WINDOW_PLAYER_INVENTORY = 0; - private static final Locale STARTER_LOCALE = new Locale("placeholder", "LANG"); + public static final int PLAYER_INVENTORY = -2; public static void fakeBookView(final Book book, final Collection players) { - - // First we need to send a fake a Book ItemStack with the BookView's - // contents to the player's hand - // These values are localized since sending item NBT doesn't trigger translation - final ItemStack item = ItemStack.of(ItemTypes.WRITTEN_BOOK, 1); - Locale lastLocale = BookUtil.STARTER_LOCALE; + final ItemStack item = ItemStack.of(ItemTypes.WRITTEN_BOOK); + item.offer(Keys.CUSTOM_NAME, book.title()); + item.offer(Keys.AUTHOR, book.author()); + item.offer(Keys.PAGES, book.pages()); for (final Player player : players) { - if (!Objects.equals(player.locale(), lastLocale)) { - lastLocale = player.locale(); - item.offer(Keys.CUSTOM_NAME, GlobalTranslator.render(book.title(), lastLocale)); - item.offer(Keys.AUTHOR, GlobalTranslator.render(book.author(), lastLocale)); - final Locale finalLastLocale = lastLocale; - item.offer(Keys.PAGES, Lists.transform(book.pages(), page -> GlobalTranslator.render(page, finalLastLocale))); - } - final ServerPlayer mcPlayer = (ServerPlayer) player; final ServerGamePacketListenerImpl receiver = mcPlayer.connection; final Inventory inventory = mcPlayer.getInventory(); - final int bookSlot = inventory.items.size() + inventory.selected; - receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.WINDOW_PLAYER_INVENTORY, mcPlayer.containerMenu.getStateId(), bookSlot, ItemStackUtil.toNative(item))); + final int bookSlot = inventory.selected; + final net.minecraft.world.item.ItemStack oldItem = inventory.getSelected(); + + // First we need to send a fake a Book ItemStack with the BookView's + // contents to the player's hand + receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, ItemStackUtil.toNative(item))); // Next we tell the client to open the Book GUI receiver.send(new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND)); // Now we can remove the fake Book since it's contents will have already // been transferred to the GUI - receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.WINDOW_PLAYER_INVENTORY, mcPlayer.containerMenu.getStateId(), bookSlot, inventory.getSelected())); + receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, oldItem)); } } From 601a270f18872b9503a17c6d7a56566225215b9f Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 11 Jun 2024 17:10:01 +0300 Subject: [PATCH 094/226] fix Viewer#sendWorldType() --- .../accessor/client/multiplayer/ClientLevelAccessor.java | 4 ++++ .../common/network/packet/SpongePacketHandler.java | 5 +++-- .../mixin/core/client/multiplayer/ClientLevelMixin.java | 3 +-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/accessors/java/org/spongepowered/common/accessor/client/multiplayer/ClientLevelAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/client/multiplayer/ClientLevelAccessor.java index 03d805e3d44..d588cd5ff60 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/client/multiplayer/ClientLevelAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/client/multiplayer/ClientLevelAccessor.java @@ -25,13 +25,17 @@ package org.spongepowered.common.accessor.client.multiplayer; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.DimensionSpecialEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.entity.TransientEntitySectionManager; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(ClientLevel.class) public interface ClientLevelAccessor { @Accessor("entityStorage") TransientEntitySectionManager accessor$getEntityStorage(); + + @Mutable @Accessor("effects") void accessor$effects(DimensionSpecialEffects effects); } diff --git a/src/main/java/org/spongepowered/common/network/packet/SpongePacketHandler.java b/src/main/java/org/spongepowered/common/network/packet/SpongePacketHandler.java index d6822835665..a77808af907 100644 --- a/src/main/java/org/spongepowered/common/network/packet/SpongePacketHandler.java +++ b/src/main/java/org/spongepowered/common/network/packet/SpongePacketHandler.java @@ -27,6 +27,7 @@ import com.mojang.authlib.GameProfile; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.DimensionSpecialEffects; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.world.entity.Entity; @@ -37,8 +38,8 @@ import org.spongepowered.api.network.EngineConnectionStates; import org.spongepowered.api.network.channel.packet.PacketChannel; import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.accessor.client.multiplayer.ClientLevelAccessor; import org.spongepowered.common.bridge.CreatorTrackedBridge; -import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge; import org.spongepowered.common.network.channel.SpongeChannelManager; @@ -99,7 +100,7 @@ public static void init(final SpongeChannelManager registry) { } final DimensionType dimensionType = SpongeCommon.vanillaRegistry(Registries.DIMENSION_TYPE).get(packet.dimensionLogic); - ((LevelBridge) world).bridge$adjustDimensionLogic(dimensionType); + ((ClientLevelAccessor) world).accessor$effects(DimensionSpecialEffects.forType(dimensionType)); } ); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/client/multiplayer/ClientLevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/client/multiplayer/ClientLevelMixin.java index 2bd9896f95f..d32cb17ab05 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/client/multiplayer/ClientLevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/client/multiplayer/ClientLevelMixin.java @@ -27,11 +27,10 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.level.dimension.DimensionType; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.mixin.core.world.level.LevelMixin; @Mixin(ClientLevel.class) -public abstract class ClientLevelMixin extends LevelMixin implements LevelBridge { +public abstract class ClientLevelMixin extends LevelMixin { @Override public void bridge$adjustDimensionLogic(final DimensionType dimensionType) { From adc357d91c02a4076d08a173bb84279606b80fc7 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 2 Jun 2024 21:10:10 +0300 Subject: [PATCH 095/226] Implement Viewer#sendBlockProgress --- SpongeAPI | 2 +- .../spongepowered/common/SpongeServer.java | 6 ++++ .../server/MinecraftServerMixin_API.java | 20 ++++++++++++ .../server/level/ServerPlayerMixin_API.java | 22 +++++++++++++ .../minecraft/world/level/LevelMixin_API.java | 31 +++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 0c9df112f0f..7af48016d82 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 0c9df112f0f90ef3096e9f39e473061a24c07f4b +Subproject commit 7af48016d82b3b1e68180df327981a74096cd49a diff --git a/src/main/java/org/spongepowered/common/SpongeServer.java b/src/main/java/org/spongepowered/common/SpongeServer.java index e72d54960e5..717130c81d7 100644 --- a/src/main/java/org/spongepowered/common/SpongeServer.java +++ b/src/main/java/org/spongepowered/common/SpongeServer.java @@ -24,6 +24,8 @@ */ package org.spongepowered.common; +import net.minecraft.core.BlockPos; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Server; import org.spongepowered.common.command.manager.SpongeCommandManager; import org.spongepowered.common.profile.SpongeGameProfileManager; @@ -47,6 +49,10 @@ public interface SpongeServer extends SpongeEngine, Server { UsernameCache getUsernameCache(); + @Nullable Integer getBlockDestructionId(BlockPos pos); + + int getOrCreateBlockDestructionId(BlockPos pos); + SpongeUserManager userManager(); @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java index 7d149e1aebe..53b55dad3d5 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java @@ -24,6 +24,8 @@ */ package org.spongepowered.common.mixin.api.minecraft.server; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.mojang.datafixers.DataFixer; @@ -34,6 +36,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.commands.Commands; +import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.server.MinecraftServer; @@ -51,6 +54,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Game; import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; @@ -108,6 +112,8 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; @SuppressWarnings("rawtypes") @@ -159,6 +165,10 @@ public abstract class MinecraftServerMixin_API implements SpongeServer, SpongeRe private RegistryHolderLogic api$registryHolder; private SpongeUserManager api$userManager; private SpongeDataPackManager api$dataPackManager; + private Cache api$blockDestructionIdCache = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.MINUTES) + .build(); + private AtomicInteger api$blockDestructionIdCounter = new AtomicInteger(); @Inject(method = "", at = @At("TAIL")) public void api$initializeSpongeFieldsfinal(final Thread $$0, final LevelStorageSource.LevelStorageAccess $$1, final PackRepository $$2, final WorldStem $$3, final Proxy $$4, @@ -476,6 +486,16 @@ public UsernameCache getUsernameCache() { return this.api$usernameCache; } + @Override + public @Nullable Integer getBlockDestructionId(BlockPos pos) { + return this.api$blockDestructionIdCache.getIfPresent(pos); + } + + @Override + public int getOrCreateBlockDestructionId(BlockPos pos) { + return this.api$blockDestructionIdCache.get(pos, (blockPos) -> this.api$blockDestructionIdCounter.decrementAndGet()); + } + @Override public void sendMessage(final Identity identity, final Component message, final MessageType type) { this.shadow$getPlayerList().broadcastSystemMessage(SpongeAdventure.asVanilla(message), false); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java index 91379e7ee08..78f0652bfc3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java @@ -47,6 +47,7 @@ import net.minecraft.network.chat.MessageSignature; import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; import net.minecraft.network.protocol.game.ClientboundDeleteChatPacket; @@ -300,6 +301,27 @@ public void resetBlockChange(final int x, final int y, final int z) { this.connection.send(new ClientboundBlockUpdatePacket(this.shadow$getCommandSenderWorld(), new BlockPos(x, y, z))); } + @Override + public void sendBlockProgress(final int x, final int y, final int z, final double progress) { + if (progress < 0 || progress > 1) { + throw new IllegalArgumentException("Progress must be between 0 and 1"); + } + + final BlockPos pos = new BlockPos(x, y, z); + final int id = ((SpongeServer) this.server).getOrCreateBlockDestructionId(pos); + final int progressStage = progress == 1 ? 9 : (int) (progress * 10); + this.connection.send(new ClientboundBlockDestructionPacket(id, pos, progressStage)); + } + + @Override + public void resetBlockProgress(final int x, final int y, final int z) { + final BlockPos pos = new BlockPos(x, y, z); + final Integer id = ((SpongeServer) this.server).getBlockDestructionId(pos); + if (id != null) { + this.connection.send(new ClientboundBlockDestructionPacket(id, pos, -1)); + } + } + @Override public boolean respawn() { if (this.impl$isFake) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java index 76c5132f397..9e6489a0b8b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java @@ -29,6 +29,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.resources.ResourceKey; @@ -85,6 +86,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.SpongeServer; import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; import org.spongepowered.common.accessor.world.entity.EntityAccessor; import org.spongepowered.common.adventure.SpongeAdventure; @@ -298,6 +300,35 @@ public void resetBlockChange(final int x, final int y, final int z) { .forEach(p -> p.connection.send(packet)); } + @Override + public void sendBlockProgress(final int x, final int y, final int z, final double progress) { + if (progress < 0 || progress > 1) { + throw new IllegalArgumentException("Progress must be between 0 and 1"); + } + + final BlockPos pos = new BlockPos(x, y, z); + final int id = ((SpongeServer) this.shadow$getServer()).getOrCreateBlockDestructionId(pos); + final int progressStage = progress == 1 ? 9 : (int) (progress * 10); + final ClientboundBlockDestructionPacket packet = new ClientboundBlockDestructionPacket(id, pos, progressStage); + ((net.minecraft.world.level.Level) (Object) this).players().stream() + .filter(ServerPlayer.class::isInstance) + .map(ServerPlayer.class::cast) + .forEach(p -> p.connection.send(packet)); + } + + @Override + public void resetBlockProgress(final int x, final int y, final int z) { + final BlockPos pos = new BlockPos(x, y, z); + final Integer id = ((SpongeServer) this.shadow$getServer()).getBlockDestructionId(pos); + if (id != null) { + final ClientboundBlockDestructionPacket packet =new ClientboundBlockDestructionPacket(id, pos, -1); + ((net.minecraft.world.level.Level) (Object) this).players().stream() + .filter(ServerPlayer.class::isInstance) + .map(ServerPlayer.class::cast) + .forEach(p -> p.connection.send(packet)); + } + } + // ArchetypeVolumeCreator // Audience From 7c1c03302027a57624b9f580adfc2712ae6d52b6 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 13:52:54 +0000 Subject: [PATCH 096/226] Add DisplaySlots generator (#4055) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index a8c2754ce1f..399d3f25f38 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -77,6 +77,7 @@ import net.minecraft.world.level.block.state.properties.SculkSensorPhase; import net.minecraft.world.level.block.state.properties.Tilt; import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.scores.DisplaySlot; import org.tinylog.Logger; import java.io.IOException; @@ -809,6 +810,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "scoreboard.displayslot", + "DisplaySlots", + DisplaySlot.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "data.type", "SculkSensorStates", From 14c61c0852df0550ef11835c8f5df6559683918f Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 14:13:59 +0000 Subject: [PATCH 097/226] Use serialized name if available (#4057) --- .../spongepowered/vanilla/generator/GeneratorMain.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 399d3f25f38..44ec337da07 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -242,14 +242,14 @@ private static List generators(final Context context) { "entity", "EntityCategories", MobCategory.class, - "getName", + "getSerializedName", "sponge" ), new EnumEntriesValidator<>( "data.type", "BoatTypes", Boat.Type.class, - "getName", + "getSerializedName", "sponge" ), new RegistryEntriesGenerator<>( @@ -277,7 +277,7 @@ private static List generators(final Context context) { "data.type", "DyeColors", DyeColor.class, - "getName", + "getSerializedName", "sponge" ), new EnumEntriesValidator<>( @@ -361,7 +361,7 @@ private static List generators(final Context context) { "item", "ItemRarities", Rarity.class, - "name", + "getSerializedName", "sponge" ), new EnumEntriesValidator<>( From 439013b7027d4494c2704d15303b3fde98b3aec2 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 14:15:21 +0000 Subject: [PATCH 098/226] Log a warning if enum validator is not using serialized name when possible (#4058) --- .../vanilla/generator/EnumEntriesValidator.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java b/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java index 3c780058308..27618ec8527 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/EnumEntriesValidator.java @@ -38,6 +38,7 @@ import com.github.javaparser.javadoc.Javadoc; import com.github.javaparser.javadoc.description.JavadocDescription; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.StringRepresentable; import org.tinylog.Logger; import java.util.ArrayList; @@ -51,7 +52,7 @@ class EnumEntriesValidator implements Generator { private final String relativePackageName; private final String targetClassSimpleName; - private final Class clazz; + private final Class> clazz; private final String keyFunction; private final String namespace; @@ -59,7 +60,7 @@ class EnumEntriesValidator implements Generator { EnumEntriesValidator( final String targetRelativePackage, final String targetClassSimpleName, - final Class clazz, + final Class> clazz, final String keyFunction, final String namespace ) { @@ -83,7 +84,7 @@ public void generate(final Context ctx) { final var primaryTypeDeclaration = compilationUnit.getPrimaryType() .orElseThrow(() -> new IllegalStateException("Could not find primary type for registry type " + this.targetClassSimpleName)); - final Object[] map = this.clazz.getEnumConstants(); + final Enum[] map = this.clazz.getEnumConstants(); primaryTypeDeclaration.setJavadocComment(new Javadoc(JavadocDescription.parseText(Generator.GENERATED_FILE_JAVADOCS))); @@ -108,8 +109,11 @@ public void generate(final Context ctx) { // Now, iterate the registry, discovering which fields were added and removed final var added = new HashSet(); final var processedFields = new ArrayList(map.length); - for (final Object f : map) { + for (final Enum f : map) { final String name; + if (!this.keyFunction.equalsIgnoreCase("getSerializedName") && f instanceof StringRepresentable) { + Logger.warn("Using {} as keyFunction on a StringRepresentable object: {}.{}", this.keyFunction, this.clazz.getName(), f.name()); + } try { if (this.keyFunction.equals("name")) { name = ((String) Enum.class.getMethod("name").invoke(f)).toLowerCase(); From d44a497f974482ab55c281d0a715ad37439bf30c Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 23 Jun 2024 14:15:30 +0000 Subject: [PATCH 099/226] Log an error in registrytest if catalog class is not final (#4059) --- .../java/org/spongepowered/test/registry/RegistryTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java index 54a042a6cbf..b62ad14baca 100644 --- a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java @@ -42,6 +42,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; @Plugin("registrytest") @@ -115,6 +116,10 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent Date: Sun, 23 Jun 2024 14:56:57 +0000 Subject: [PATCH 100/226] Log an error in registrytest if catalog class has non private constructors (#4060) * Log an error in registrytest if catalog class has non private constructors * Update RegistryTest.java --- .../java/org/spongepowered/test/registry/RegistryTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java index b62ad14baca..78db4e2eaa6 100644 --- a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java @@ -44,6 +44,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.util.Arrays; @Plugin("registrytest") public final class RegistryTest implements LoadableModule { @@ -120,6 +121,10 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent !Modifier.isPrivate(ctor.getModifiers()))) { + this.logger.error("{} has non-private constructors", catalogClass.getSimpleName()); + } + final Method registryMethod; try { registryMethod = catalogClass.getDeclaredMethod("registry"); From 1a76feb31efb6f545fb31a373ddd55da96ccee60 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Mon, 24 Jun 2024 12:24:07 +0000 Subject: [PATCH 101/226] Add EquipmentTypes generator (#4056) --- .../org/spongepowered/vanilla/generator/GeneratorMain.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java index 44ec337da07..2b19277298e 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/GeneratorMain.java @@ -831,6 +831,13 @@ private static List generators(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "item.inventory.equipment", + "EquipmentTypes", + EquipmentSlot.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "entity.display", "TextAlignments", From 80324317b1bbb4a1c361dfb872acd272f5fabcae Mon Sep 17 00:00:00 2001 From: Morpheus Date: Tue, 25 Jun 2024 19:14:48 +0000 Subject: [PATCH 102/226] Remove hardcoded fields from VanillaRegistryLoader (#4061) * Remove hardcoded fields from VanillaRegistryLoader * Run spotlessApply --- .../loader/VanillaRegistryLoader.java | 127 +++++++----------- 1 file changed, 45 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java index 5da1997c44c..8dd24c87c8d 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java @@ -101,7 +101,6 @@ import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.scoreboard.criteria.Criteria; import org.spongepowered.api.scoreboard.criteria.Criterion; -import org.spongepowered.common.accessor.world.entity.animal.MushroomCow_MushroomTypeAccessor; import org.spongepowered.common.accessor.world.entity.boss.enderdragon.phases.EnderDragonPhaseAccessor; import org.spongepowered.common.accessor.world.level.GameRulesAccessor; import org.spongepowered.common.registry.RegistryLoader; @@ -147,102 +146,79 @@ private void loadInstanceRegistries() { } private void loadEnumRegistries() { - this.automaticSerializedName(RegistryTypes.ATTACHMENT_SURFACE, AttachFace.values()); - this.automaticSerializedName(RegistryTypes.BAMBOO_LEAVES_TYPE, BambooLeaves.values()); - this.automaticSerializedName(RegistryTypes.BELL_ATTACHMENT_TYPE, BellAttachType.values()); + this.automaticName(RegistryTypes.ATTACHMENT_SURFACE, AttachFace.values()); + this.automaticName(RegistryTypes.BAMBOO_LEAVES_TYPE, BambooLeaves.values()); + this.automaticName(RegistryTypes.BELL_ATTACHMENT_TYPE, BellAttachType.values()); this.manualName(RegistryTypes.ATTRIBUTE_OPERATION, AttributeModifier.Operation.values(), map -> { // names come from net.minecraft.world.level.storage.loot.functions.SetAttributesFunction.Modifier#operationFromString map.put(AttributeModifier.Operation.ADD_VALUE, "addition"); map.put(AttributeModifier.Operation.ADD_MULTIPLIED_BASE, "multiply_base"); map.put(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL, "multiply_total"); }); - this.knownName(RegistryTypes.BOAT_TYPE, Boat.Type.values(), Boat.Type::getName); - this.automaticSerializedName(RegistryTypes.CHEST_ATTACHMENT_TYPE, ChestType.values()); - this.manualName(RegistryTypes.COLLISION_RULE, Team.CollisionRule.values(), map -> { - map.put(Team.CollisionRule.ALWAYS, "always"); - map.put(Team.CollisionRule.NEVER, "never"); - map.put(Team.CollisionRule.PUSH_OTHER_TEAMS, "push_other_teams"); - map.put(Team.CollisionRule.PUSH_OWN_TEAM, "push_own_team"); - }); - this.automaticSerializedName(RegistryTypes.COMPARATOR_MODE, ComparatorMode.values()); - this.knownName(RegistryTypes.DIFFICULTY, Difficulty.values(), Difficulty::getKey); - this.automaticSerializedName(RegistryTypes.DYE_COLOR, DyeColor.values()); - this.automaticSerializedName(RegistryTypes.DOOR_HINGE, DoorHingeSide.values()); - this.automaticSerializedName(RegistryTypes.DRIPSTONE_SEGMENT, DripstoneThickness.values()); - this.manualName(RegistryTypes.EQUIPMENT_GROUP, EquipmentSlot.Type.values(), map -> { - map.put(EquipmentSlot.Type.HUMANOID_ARMOR, "worn"); - map.put(EquipmentSlot.Type.HAND, "held"); - map.put(EquipmentSlot.Type.ANIMAL_ARMOR, "animal_armor"); - }); - this.manualName(RegistryTypes.EQUIPMENT_TYPE, EquipmentSlot.values(), map -> { - map.put(EquipmentSlot.CHEST, "chest"); - map.put(EquipmentSlot.FEET, "feet"); - map.put(EquipmentSlot.HEAD, "head"); - map.put(EquipmentSlot.LEGS, "legs"); - map.put(EquipmentSlot.MAINHAND, "main_hand"); - map.put(EquipmentSlot.OFFHAND, "off_hand"); - map.put(EquipmentSlot.BODY, "body"); - }); - this.knownName(RegistryTypes.FOX_TYPE, Fox.Type.values(), Fox.Type::getSerializedName); - this.knownName(RegistryTypes.GAME_MODE, GameType.values(), GameType::getName); + this.automaticName(RegistryTypes.BOAT_TYPE, Boat.Type.values()); + this.automaticName(RegistryTypes.CHEST_ATTACHMENT_TYPE, ChestType.values()); + this.automaticName(RegistryTypes.COLLISION_RULE, Team.CollisionRule.values()); + this.automaticName(RegistryTypes.COMPARATOR_MODE, ComparatorMode.values()); + this.automaticName(RegistryTypes.DIFFICULTY, Difficulty.values()); + this.automaticName(RegistryTypes.DYE_COLOR, DyeColor.values()); + this.automaticName(RegistryTypes.DOOR_HINGE, DoorHingeSide.values()); + this.automaticName(RegistryTypes.DRIPSTONE_SEGMENT, DripstoneThickness.values()); + this.automaticName(RegistryTypes.EQUIPMENT_GROUP, EquipmentSlot.Type.values()); + this.automaticName(RegistryTypes.EQUIPMENT_TYPE, EquipmentSlot.values()); + this.automaticName(RegistryTypes.FOX_TYPE, Fox.Type.values()); + this.automaticName(RegistryTypes.GAME_MODE, GameType.values()); this.automaticName(RegistryTypes.HAND_PREFERENCE, HumanoidArm.values()); this.automaticName(RegistryTypes.HAND_TYPE, InteractionHand.values()); - this.automaticSerializedName(RegistryTypes.INSTRUMENT_TYPE, NoteBlockInstrument.values()); + this.automaticName(RegistryTypes.INSTRUMENT_TYPE, NoteBlockInstrument.values()); this.automaticName(RegistryTypes.ITEM_RARITY, Rarity.values()); this.automaticName(RegistryTypes.ITEM_TIER, Tiers.values()); - this.automaticSerializedName(RegistryTypes.JIGSAW_BLOCK_ORIENTATION, FrontAndTop.values()); - this.knownName(RegistryTypes.MOOSHROOM_TYPE, MushroomCow.MushroomType.values(), type -> ((MushroomCow_MushroomTypeAccessor) (Object) type).accessor$type()); - this.knownName(RegistryTypes.OBJECTIVE_DISPLAY_MODE, ObjectiveCriteria.RenderType.values(), ObjectiveCriteria.RenderType::getId); - this.knownName(RegistryTypes.PANDA_GENE, Panda.Gene.values(), Panda.Gene::getSerializedName); + this.automaticName(RegistryTypes.JIGSAW_BLOCK_ORIENTATION, FrontAndTop.values()); + this.automaticName(RegistryTypes.MOOSHROOM_TYPE, MushroomCow.MushroomType.values()); + this.automaticName(RegistryTypes.OBJECTIVE_DISPLAY_MODE, ObjectiveCriteria.RenderType.values()); + this.automaticName(RegistryTypes.PANDA_GENE, Panda.Gene.values()); this.automaticName(RegistryTypes.PHANTOM_PHASE, Phantom.AttackPhase.values()); this.automaticName(RegistryTypes.PICKUP_RULE, AbstractArrow.Pickup.values()); this.automaticName(RegistryTypes.MIRROR, Mirror.values()); this.automaticName(RegistryTypes.CHAT_VISIBILITY, ChatVisiblity.values()); - this.automaticSerializedName(RegistryTypes.PISTON_TYPE, PistonType.values()); - this.automaticSerializedName(RegistryTypes.PORTION_TYPE, Half.values()); + this.automaticName(RegistryTypes.PISTON_TYPE, PistonType.values()); + this.automaticName(RegistryTypes.PORTION_TYPE, Half.values()); this.automaticName(RegistryTypes.RAID_STATUS, Raid.RaidStatus.values()); this.automaticName(RegistryTypes.ROTATION, Rotation.values()); - this.automaticSerializedName(RegistryTypes.RAIL_DIRECTION, RailShape.values()); - this.automaticSerializedName(RegistryTypes.SCULK_SENSOR_STATE, SculkSensorPhase.values()); - this.automaticSerializedName(RegistryTypes.SLAB_PORTION, SlabType.values()); + this.automaticName(RegistryTypes.RAIL_DIRECTION, RailShape.values()); + this.automaticName(RegistryTypes.SCULK_SENSOR_STATE, SculkSensorPhase.values()); + this.automaticName(RegistryTypes.SLAB_PORTION, SlabType.values()); this.automaticName(RegistryTypes.SPELL_TYPE, SpellcasterIllager.IllagerSpell.values()); - this.automaticSerializedName(RegistryTypes.STAIR_SHAPE, StairsShape.values()); - this.automaticSerializedName(RegistryTypes.STRUCTURE_MODE, StructureMode.values()); - this.automaticSerializedName(RegistryTypes.TILT, Tilt.values()); + this.automaticName(RegistryTypes.STAIR_SHAPE, StairsShape.values()); + this.automaticName(RegistryTypes.STRUCTURE_MODE, StructureMode.values()); + this.automaticName(RegistryTypes.TILT, Tilt.values()); this.automaticName(RegistryTypes.TASK_PRIORITY, TickPriority.values()); - this.manualName(RegistryTypes.VISIBILITY, Team.Visibility.values(), map -> { - map.put(Team.Visibility.ALWAYS, "always"); - map.put(Team.Visibility.NEVER, "never"); - map.put(Team.Visibility.HIDE_FOR_OTHER_TEAMS, "hide_for_other_teams"); - map.put(Team.Visibility.HIDE_FOR_OWN_TEAM, "hide_for_own_team"); - }); - this.automaticSerializedName(RegistryTypes.WIRE_ATTACHMENT_TYPE, RedstoneSide.values()); - this.automaticSerializedName(RegistryTypes.ADVANCEMENT_TYPE, AdvancementType.values()); - // TODO banner patterns are in registry now this.knownName(RegistryTypes.BANNER_PATTERN_SHAPE, BannerPattern.values(), b -> ((BannerPatternAccessor) (Object) b).accessor$filename()); + this.automaticName(RegistryTypes.VISIBILITY, Team.Visibility.values()); + this.automaticName(RegistryTypes.WIRE_ATTACHMENT_TYPE, RedstoneSide.values()); + this.automaticName(RegistryTypes.ADVANCEMENT_TYPE, AdvancementType.values()); this.automaticName(RegistryTypes.TROPICAL_FISH_SHAPE, TropicalFish.Pattern.values()); this.automaticName(RegistryTypes.HEIGHT_TYPE, Heightmap.Types.values()); - this.knownName(RegistryTypes.ENTITY_CATEGORY, MobCategory.values(), VanillaRegistryLoader.sanitizedName(MobCategory::getName)); - this.automaticSerializedName(RegistryTypes.WALL_CONNECTION_STATE, WallSide.values()); + this.automaticName(RegistryTypes.ENTITY_CATEGORY, MobCategory.values()); + this.automaticName(RegistryTypes.WALL_CONNECTION_STATE, WallSide.values()); this.automaticName(RegistryTypes.GRASS_COLOR_MODIFIER, BiomeSpecialEffects.GrassColorModifier.values()); this.automaticName(RegistryTypes.PRECIPITATION, Biome.Precipitation.values()); this.automaticName(RegistryTypes.TEMPERATURE_MODIFIER, Biome.TemperatureModifier.values()); this.automaticName(RegistryTypes.CARVING_STEP, GenerationStep.Carving.values()); this.automaticName(RegistryTypes.DECORATION_STEP, GenerationStep.Decoration.values()); - this.automaticSerializedName(RegistryTypes.PARROT_TYPE, Parrot.Variant.values()); - this.automaticSerializedName(RegistryTypes.RABBIT_TYPE, Rabbit.Variant.values()); - this.automaticSerializedName(RegistryTypes.LLAMA_TYPE, Llama.Variant.values()); - this.automaticSerializedName(RegistryTypes.HORSE_COLOR, Variant.values()); + this.automaticName(RegistryTypes.PARROT_TYPE, Parrot.Variant.values()); + this.automaticName(RegistryTypes.RABBIT_TYPE, Rabbit.Variant.values()); + this.automaticName(RegistryTypes.LLAMA_TYPE, Llama.Variant.values()); + this.automaticName(RegistryTypes.HORSE_COLOR, Variant.values()); this.automaticName(RegistryTypes.HORSE_STYLE, Markings.values()); this.automaticName(RegistryTypes.DAMAGE_SCALING, DamageScaling.values()); this.automaticName(RegistryTypes.DAMAGE_EFFECT, DamageEffects.values()); - this.automaticSerializedName(RegistryTypes.ITEM_DISPLAY_TYPE, ItemDisplayContext.values()); - this.automaticSerializedName(RegistryTypes.BILLBOARD_TYPE, Display.BillboardConstraints.values()); - this.automaticSerializedName(RegistryTypes.TEXT_ALIGNMENT, Display.TextDisplay.Align.values()); + this.automaticName(RegistryTypes.ITEM_DISPLAY_TYPE, ItemDisplayContext.values()); + this.automaticName(RegistryTypes.BILLBOARD_TYPE, Display.BillboardConstraints.values()); + this.automaticName(RegistryTypes.TEXT_ALIGNMENT, Display.TextDisplay.Align.values()); this.automaticName(RegistryTypes.LIGHT_TYPE, LightLayer.values()); - this.naming(RegistryTypes.DISPLAY_SLOT, DisplaySlot.values(), d -> d.getSerializedName().replace(".", "_")); + this.automaticName(RegistryTypes.DISPLAY_SLOT, DisplaySlot.values()); this.automaticName(RegistryTypes.PUSH_REACTION, PushReaction.values()); - this.automaticSerializedName(RegistryTypes.TRIAL_SPAWNER_STATE, TrialSpawnerState.values()); - this.automaticSerializedName(RegistryTypes.VAULT_STATE, VaultState.values()); + this.automaticName(RegistryTypes.TRIAL_SPAWNER_STATE, TrialSpawnerState.values()); + this.automaticName(RegistryTypes.VAULT_STATE, VaultState.values()); } private static RegistryLoader criterion() { @@ -276,17 +252,8 @@ private static RegistryLoader fireworkShape() { @SuppressWarnings("UnusedReturnValue") private > Registry
automaticName(final RegistryType type, final I[] values) { - return this.naming(type, values, VanillaRegistryLoader.sanitizedName(Enum::name)); - } - - @SuppressWarnings("UnusedReturnValue") - private & StringRepresentable> Registry automaticSerializedName(final RegistryType type, final I[] values) { - return this.naming(type, values, StringRepresentable::getSerializedName); // not using method reference as ECJ bug workaround - } - - @SuppressWarnings("UnusedReturnValue") - private > Registry knownName(final RegistryType type,final I[] values, final Function name) { - return this.naming(type, values, name); + final Function keyFunction = i -> i instanceof final StringRepresentable s ? s.getSerializedName() : i.name(); + return this.naming(type, values, keyFunction.andThen(i -> i.toLowerCase(Locale.ROOT))); } @SuppressWarnings("UnusedReturnValue") @@ -358,8 +325,4 @@ private Registry naming(final RegistryType type, final int values, private interface Manual { void put(final I value, final String key); } - - private static Function sanitizedName(final Function original) { - return original.andThen(s -> s.toLowerCase(Locale.ROOT)); - } } From 2e4303a754eeb11ddbb807c81ac33e17bf980b96 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Tue, 25 Jun 2024 20:01:19 +0000 Subject: [PATCH 103/226] Bump SpongeAPI (#4063) * Update catalog fields references * Bump SpongeAPI --- SpongeAPI | 2 +- .../common/data/provider/entity/ArmorStandData.java | 12 ++++++------ .../common/entity/player/SpongeUserData.java | 8 ++++---- .../DropFromPlayerInventoryTransaction.java | 2 +- .../lens/impl/minecraft/PlayerInventoryLens.java | 6 +++--- .../container/ContainerPlayerInventoryLens.java | 2 +- .../inventory/lens/impl/slot/HeldHandSlotLens.java | 2 +- .../java/org/spongepowered/test/data/DataTest.java | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 7af48016d82..446aa5e0266 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 7af48016d82b3b1e68180df327981a74096cd49a +Subproject commit 446aa5e0266be80240b0de98262fa3556110d812 diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/ArmorStandData.java b/src/main/java/org/spongepowered/common/data/provider/entity/ArmorStandData.java index 46d9d2ed731..2398a2d8aa3 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/ArmorStandData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/ArmorStandData.java @@ -115,12 +115,12 @@ public static void register(final DataProviderRegistrator registrator) { disabledSlots ^= 0b1111_1111; } - if (v.get(EquipmentTypes.MAIN_HAND.get())) chunk |= 1 << 0; + if (v.get(EquipmentTypes.MAINHAND.get())) chunk |= 1 << 0; if (v.get(EquipmentTypes.FEET.get())) chunk |= 1 << 1; if (v.get(EquipmentTypes.LEGS.get())) chunk |= 1 << 2; if (v.get(EquipmentTypes.CHEST.get())) chunk |= 1 << 3; if (v.get(EquipmentTypes.HEAD.get())) chunk |= 1 << 4; - if (v.get(EquipmentTypes.OFF_HAND.get())) chunk |= 1 << 5; + if (v.get(EquipmentTypes.OFFHAND.get())) chunk |= 1 << 5; disabledSlots |= (chunk << 16); ((ArmorStandAccessor) h).accessor$disabledSlots(disabledSlots); @@ -136,12 +136,12 @@ public static void register(final DataProviderRegistrator registrator) { final ImmutableMap.Builder builder = ImmutableMap.builder(); return builder - .put(EquipmentTypes.MAIN_HAND.get(), (resultantChunk & (1 << 0)) != 0) + .put(EquipmentTypes.MAINHAND.get(), (resultantChunk & (1 << 0)) != 0) .put(EquipmentTypes.FEET.get(), (resultantChunk & (1 << 1)) != 0) .put(EquipmentTypes.LEGS.get(), (resultantChunk & (1 << 2)) != 0) .put(EquipmentTypes.CHEST.get(), (resultantChunk & (1 << 3)) != 0) .put(EquipmentTypes.HEAD.get(), (resultantChunk & (1 << 4)) != 0) - .put(EquipmentTypes.OFF_HAND.get(), (resultantChunk & (1 << 5)) != 0) + .put(EquipmentTypes.OFFHAND.get(), (resultantChunk & (1 << 5)) != 0) .build(); }) .set((h, v) -> { @@ -156,12 +156,12 @@ public static void register(final DataProviderRegistrator registrator) { ((ArmorStandAccessor) h).accessor$disabledSlots(disabledSlots); } - if (v.get(EquipmentTypes.MAIN_HAND.get())) chunk |= 1 << 0; + if (v.get(EquipmentTypes.MAINHAND.get())) chunk |= 1 << 0; if (v.get(EquipmentTypes.FEET.get())) chunk |= 1 << 1; if (v.get(EquipmentTypes.LEGS.get())) chunk |= 1 << 2; if (v.get(EquipmentTypes.CHEST.get())) chunk |= 1 << 3; if (v.get(EquipmentTypes.HEAD.get())) chunk |= 1 << 4; - if (v.get(EquipmentTypes.OFF_HAND.get())) chunk |= 1 << 5; + if (v.get(EquipmentTypes.OFFHAND.get())) chunk |= 1 << 5; disabledSlots |= (chunk << 8); ((ArmorStandAccessor) h).accessor$disabledSlots(disabledSlots); diff --git a/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java b/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java index c006fdd3369..4b24f5ddcda 100644 --- a/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java +++ b/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java @@ -317,9 +317,9 @@ public EquipmentInventory equipment() { @Override public ItemStack itemInHand(final HandType handType) { if (handType == HandTypes.MAIN_HAND.get()) { - this.equipped(EquipmentTypes.MAIN_HAND.get()).orElseThrow(IllegalStateException::new); + this.equipped(EquipmentTypes.MAINHAND.get()).orElseThrow(IllegalStateException::new); } else if (handType == HandTypes.OFF_HAND.get()) { - this.equipped(EquipmentTypes.OFF_HAND.get()).orElseThrow(IllegalStateException::new); + this.equipped(EquipmentTypes.OFFHAND.get()).orElseThrow(IllegalStateException::new); } throw new IllegalArgumentException("Invalid hand " + handType); } @@ -367,9 +367,9 @@ public void setFeet(final ItemStack boots) { @Override public void setItemInHand(final HandType handType, final @Nullable ItemStack itemInHand) { if (handType == HandTypes.MAIN_HAND.get()) { - this.setEquippedItem(EquipmentTypes.MAIN_HAND, itemInHand); + this.setEquippedItem(EquipmentTypes.MAINHAND, itemInHand); } else if (handType == HandTypes.OFF_HAND.get()) { - this.setEquippedItem(EquipmentTypes.OFF_HAND, itemInHand); + this.setEquippedItem(EquipmentTypes.OFFHAND, itemInHand); } else { throw new IllegalArgumentException("Invalid hand " + handType); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/DropFromPlayerInventoryTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/DropFromPlayerInventoryTransaction.java index 071c3e1ad91..d0101fb5ac1 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/DropFromPlayerInventoryTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/DropFromPlayerInventoryTransaction.java @@ -55,7 +55,7 @@ public DropFromPlayerInventoryTransaction(final ServerPlayer player, final boole super((Inventory) player.getInventory()); this.player = player; this.dropAll = dropAll; - this.slot = ((PlayerInventory) player.getInventory()).equipment().slot(EquipmentTypes.MAIN_HAND).orElse(null); + this.slot = ((PlayerInventory) player.getInventory()).equipment().slot(EquipmentTypes.MAINHAND).orElse(null); } @Override diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/PlayerInventoryLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/PlayerInventoryLens.java index 420e4e6007c..a3c93605dce 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/PlayerInventoryLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/PlayerInventoryLens.java @@ -96,7 +96,7 @@ protected void init(SlotLensProvider slots) { this.offhand = slots.getSlotLens(base); base += PlayerInventoryLens.OFFHAND; - equipmentLenses.put(EquipmentTypes.OFF_HAND.get(), this.offhand); + equipmentLenses.put(EquipmentTypes.OFFHAND.get(), this.offhand); this.addSpanningChild(this.armor); this.addSpanningChild(this.primary); @@ -116,14 +116,14 @@ protected void init(SlotLensProvider slots) { this.offhand = slots.getSlotLens(base); base += PlayerInventoryLens.OFFHAND; - equipmentLenses.put(EquipmentTypes.OFF_HAND.get(), this.offhand); + equipmentLenses.put(EquipmentTypes.OFFHAND.get(), this.offhand); this.addSpanningChild(this.primary); this.addSpanningChild(this.armor); this.addSpanningChild(this.offhand); } - equipmentLenses.put(EquipmentTypes.MAIN_HAND.get(), new HeldHandSlotLens(this.primary.getHotbar())); + equipmentLenses.put(EquipmentTypes.MAINHAND.get(), new HeldHandSlotLens(this.primary.getHotbar())); this.equipment = new EquipmentInventoryLens(equipmentLenses); for (Map.Entry entry : equipmentLenses.entrySet()) { diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/container/ContainerPlayerInventoryLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/container/ContainerPlayerInventoryLens.java index 828f72e0c62..9a9fbb35577 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/container/ContainerPlayerInventoryLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/minecraft/container/ContainerPlayerInventoryLens.java @@ -62,7 +62,7 @@ protected void init(SlotLensProvider slots) { this.addChild(slots.getSlotLens(this.base + 1), KeyValuePair.of(Keys.EQUIPMENT_TYPE, EquipmentTypes.CHEST.get())); this.addChild(slots.getSlotLens(this.base + 2), KeyValuePair.of(Keys.EQUIPMENT_TYPE, EquipmentTypes.LEGS.get())); this.addChild(slots.getSlotLens(this.base + 3), KeyValuePair.of(Keys.EQUIPMENT_TYPE, EquipmentTypes.FEET.get())); - this.addChild(slots.getSlotLens(this.base + 4 + 4 * 9), KeyValuePair.of(Keys.EQUIPMENT_TYPE, EquipmentTypes.OFF_HAND.get())); + this.addChild(slots.getSlotLens(this.base + 4 + 4 * 9), KeyValuePair.of(Keys.EQUIPMENT_TYPE, EquipmentTypes.OFFHAND.get())); } } diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java index 0c223f6f011..17e5e74d0cc 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java @@ -148,7 +148,7 @@ public SlotLens getSlotLens(Fabric fabric, int ordinal) { } public Predicate getEquipmentTypeFilter() { - return (e) -> e == EquipmentTypes.MAIN_HAND.get(); + return (e) -> e == EquipmentTypes.MAINHAND.get(); } public Predicate getItemStackFilter() { diff --git a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java index cd05a8b9e40..5d472934aa0 100644 --- a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java @@ -324,8 +324,8 @@ public void testData(final ServerPlayer player) { armorStand.equip(EquipmentTypes.FEET.get(), ItemStack.of(ItemTypes.CHAINMAIL_BOOTS)); armorStand.equip(EquipmentTypes.HEAD.get(), ItemStack.of(ItemTypes.GOLDEN_HELMET)); armorStand.equip(EquipmentTypes.LEGS.get(), ItemStack.of(ItemTypes.DIAMOND_LEGGINGS)); - armorStand.equip(EquipmentTypes.MAIN_HAND.get(), ItemStack.of(ItemTypes.DIAMOND)); - armorStand.equip(EquipmentTypes.OFF_HAND.get(), ItemStack.of(ItemTypes.DIAMOND)); + armorStand.equip(EquipmentTypes.MAINHAND.get(), ItemStack.of(ItemTypes.DIAMOND)); + armorStand.equip(EquipmentTypes.OFFHAND.get(), ItemStack.of(ItemTypes.DIAMOND)); armorStand.offer(Keys.BODY_ROTATIONS, Map.of(BodyParts.CHEST.get(), Vector3d.RIGHT)); From 310dfd49324ccf5b7dad33a7bd446413227082f7 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 23 Jun 2024 02:29:54 +0200 Subject: [PATCH 104/226] Implement ForwardingViewer Closes #4054 --- SpongeAPI | 2 +- .../spongepowered/common/SpongeEngine.java | 3 + .../spongepowered/common/SpongeServer.java | 6 - .../common/bridge/effect/ViewerBridge.java | 39 +++ .../server/level/ServerPlayerBridge.java | 7 - .../effect/SpongeCustomForwardingViewer.java | 106 ++++++++ .../common/effect/SpongeForwardingViewer.java | 104 ++++++++ .../common/effect/SpongeViewer.java | 121 +++++++++ .../effect/particle/CachedParticlePacket.java | 4 +- .../effect/particle/SpongeParticleHelper.java | 43 +-- .../common/effect/util/ViewerPacketUtil.java | 195 ++++++++++++++ .../registry/SpongeFactoryProvider.java | 3 + .../common/util/BlockDestructionIdCache.java | 58 +++++ .../spongepowered/common/util/BookUtil.java | 39 +-- .../minecraft/client/MinecraftMixin_API.java | 8 + .../multiplayer/ClientLevelMixin_API.java | 6 + .../server/MinecraftServerMixin_API.java | 20 +- .../server/level/ServerPlayerMixin_API.java | 246 ------------------ .../world/entity/player/PlayerMixin_API.java | 62 ++++- .../minecraft/world/level/LevelMixin_API.java | 112 +------- .../core/client/player/LocalPlayerMixin.java | 45 ++++ .../core/server/level/ServerPlayerMixin.java | 23 ++ .../core/world/entity/player/PlayerMixin.java | 3 +- src/mixins/resources/mixins.sponge.core.json | 1 + .../level/ServerPlayerMixin_Vanilla.java | 12 - 25 files changed, 830 insertions(+), 438 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/bridge/effect/ViewerBridge.java create mode 100644 src/main/java/org/spongepowered/common/effect/SpongeCustomForwardingViewer.java create mode 100644 src/main/java/org/spongepowered/common/effect/SpongeForwardingViewer.java create mode 100644 src/main/java/org/spongepowered/common/effect/SpongeViewer.java create mode 100644 src/main/java/org/spongepowered/common/effect/util/ViewerPacketUtil.java create mode 100644 src/main/java/org/spongepowered/common/util/BlockDestructionIdCache.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/client/player/LocalPlayerMixin.java diff --git a/SpongeAPI b/SpongeAPI index 446aa5e0266..54f7a877272 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 446aa5e0266be80240b0de98262fa3556110d812 +Subproject commit 54f7a8772720e9e0c818eddb5fee9644574a18e8 diff --git a/src/main/java/org/spongepowered/common/SpongeEngine.java b/src/main/java/org/spongepowered/common/SpongeEngine.java index 022176b128c..625ec4a1683 100644 --- a/src/main/java/org/spongepowered/common/SpongeEngine.java +++ b/src/main/java/org/spongepowered/common/SpongeEngine.java @@ -25,6 +25,9 @@ package org.spongepowered.common; import org.spongepowered.api.Engine; +import org.spongepowered.common.util.BlockDestructionIdCache; public interface SpongeEngine extends Engine { + + BlockDestructionIdCache getBlockDestructionIdCache(); } diff --git a/src/main/java/org/spongepowered/common/SpongeServer.java b/src/main/java/org/spongepowered/common/SpongeServer.java index 717130c81d7..e72d54960e5 100644 --- a/src/main/java/org/spongepowered/common/SpongeServer.java +++ b/src/main/java/org/spongepowered/common/SpongeServer.java @@ -24,8 +24,6 @@ */ package org.spongepowered.common; -import net.minecraft.core.BlockPos; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Server; import org.spongepowered.common.command.manager.SpongeCommandManager; import org.spongepowered.common.profile.SpongeGameProfileManager; @@ -49,10 +47,6 @@ public interface SpongeServer extends SpongeEngine, Server { UsernameCache getUsernameCache(); - @Nullable Integer getBlockDestructionId(BlockPos pos); - - int getOrCreateBlockDestructionId(BlockPos pos); - SpongeUserManager userManager(); @Override diff --git a/src/main/java/org/spongepowered/common/bridge/effect/ViewerBridge.java b/src/main/java/org/spongepowered/common/bridge/effect/ViewerBridge.java new file mode 100644 index 00000000000..297bbeffc56 --- /dev/null +++ b/src/main/java/org/spongepowered/common/bridge/effect/ViewerBridge.java @@ -0,0 +1,39 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.bridge.effect; + +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; + +public interface ViewerBridge { + + // Used to send sponge custom packets + default void bridge$sendSpongePacketToViewer(final org.spongepowered.api.network.channel.packet.Packet packet) { + } + + default void bridge$sendToViewer(final Packet packet) { + } + +} diff --git a/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java b/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java index 4344c6b3ee8..ac2c724af1a 100644 --- a/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java @@ -25,7 +25,6 @@ package org.spongepowered.common.bridge.server.level; import net.kyori.adventure.text.Component; -import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundRespawnPacket; @@ -34,7 +33,6 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.dimension.DimensionType; import org.checkerframework.checker.nullness.qual.Nullable; @@ -65,8 +63,6 @@ public interface ServerPlayerBridge extends ServerPlayerEntityHealthScaleBridge void bridge$setLanguage(Locale language); - void bridge$sendBlockChange(BlockPos pos, BlockState state); - void bridge$initScoreboard(); void bridge$removeScoreboardOnRespawn(); @@ -100,9 +96,6 @@ public interface ServerPlayerBridge extends ServerPlayerEntityHealthScaleBridge isFlat, ((ServerPlayer) this).getLastDeathLocation(), ((ServerPlayer) this).getPortalCooldown()), dataToKeepMask)); } - default void bridge$sendViewerEnvironment(final DimensionType dimensionType) { - } - boolean bridge$kick(final Component message); boolean bridge$sleepingIgnored(); diff --git a/src/main/java/org/spongepowered/common/effect/SpongeCustomForwardingViewer.java b/src/main/java/org/spongepowered/common/effect/SpongeCustomForwardingViewer.java new file mode 100644 index 00000000000..8ed94b0deed --- /dev/null +++ b/src/main/java/org/spongepowered/common/effect/SpongeCustomForwardingViewer.java @@ -0,0 +1,106 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.effect; + +import org.spongepowered.api.effect.ForwardingViewer; +import org.spongepowered.api.effect.Viewer; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +public final class SpongeCustomForwardingViewer implements SpongeForwardingViewer { + + private final Supplier> viewersSupplier; + + private SpongeCustomForwardingViewer(final Supplier> viewersSupplier) { + this.viewersSupplier = viewersSupplier; + } + + @Override + public Iterable audiences() { + return this.viewersSupplier.get(); + } + + public static final class FactoryImpl implements ForwardingViewer.Factory { + + public FactoryImpl() { + } + + @Override + public ForwardingViewer of(final Supplier> viewersSupplier) { + Objects.requireNonNull(viewersSupplier, "viewersSupplier"); + return new SpongeCustomForwardingViewer(viewersSupplier); + } + + @Override + public ForwardingViewer of(final Collection viewers) { + Objects.requireNonNull(viewers, "viewers"); + final List list = List.copyOf(viewers); + return new SpongeCustomForwardingViewer(() -> list); + } + + @Override + public ForwardingViewer of(final Viewer... viewers) { + Objects.requireNonNull(viewers, "viewers"); + final List list = List.of(viewers); + return new SpongeCustomForwardingViewer(() -> list); + } + + @Override + public ForwardingViewer allAround(final World world, final Vector3i position, final int radius) { + Objects.requireNonNull(world, "world"); + Objects.requireNonNull(position, "position"); + if (radius <= 0) { + throw new IllegalArgumentException("The radius has to be greater then zero!"); + } + return new SpongeCustomForwardingViewer(() -> listAllAround(world, position, radius)); + } + + @Override + public ForwardingViewer allAround(final Entity entity, final int radius) { + Objects.requireNonNull(entity, "entity"); + if (radius <= 0) { + throw new IllegalArgumentException("The radius has to be greater then zero!"); + } + return new SpongeCustomForwardingViewer(() -> entity.isRemoved() + ? List.of() + : listAllAround(entity.world(), entity.blockPosition(), radius) + ); + } + + private static List listAllAround(final World world, final Vector3i position, final int radius) { + final int radiusSquared = radius * radius; + return world.players().stream() + .filter(player -> player.blockPosition().distanceSquared(position) <= radiusSquared) + .toList(); + } + } +} diff --git a/src/main/java/org/spongepowered/common/effect/SpongeForwardingViewer.java b/src/main/java/org/spongepowered/common/effect/SpongeForwardingViewer.java new file mode 100644 index 00000000000..74b7197b3c6 --- /dev/null +++ b/src/main/java/org/spongepowered/common/effect/SpongeForwardingViewer.java @@ -0,0 +1,104 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.effect; + +import net.kyori.adventure.sound.SoundStop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import net.kyori.adventure.title.TitlePart; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import org.spongepowered.api.effect.ForwardingViewer; +import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.common.bridge.effect.ViewerBridge; + +public interface SpongeForwardingViewer extends SpongeViewer, ForwardingViewer, ViewerBridge { + + // ViewerBridge + + @Override + default void bridge$sendSpongePacketToViewer(final org.spongepowered.api.network.channel.packet.Packet packet) { + this.audiences().forEach(viewer -> ((ViewerBridge) viewer).bridge$sendSpongePacketToViewer(packet)); + } + + @Override + default void bridge$sendToViewer(final Packet packet) { + this.audiences().forEach(viewer -> ((ViewerBridge) viewer).bridge$sendToViewer(packet)); + } + + // Viewer + + @Override + default void playMusicDisc(final int x, final int y, final int z, final MusicDisc musicDisc) { + this.audiences().forEach(viewer -> viewer.playMusicDisc(x, y, z, musicDisc)); + } + + @Override + default void resetBlockChange(final int x, final int y, final int z) { + this.audiences().forEach(viewer -> viewer.resetBlockChange(x, y, z)); + } + + @Override + default void sendBlockProgress(final int x, final int y, final int z, final double progress) { + this.audiences().forEach(viewer -> viewer.sendBlockProgress(x, y, z, progress)); + } + + @Override + default void resetBlockProgress(final int x, final int y, final int z) { + this.audiences().forEach(viewer -> viewer.resetBlockProgress(x, y, z)); + } + + // Audience + + @Override + default void stopSound(final SoundStop stop) { + SpongeViewer.super.stopSound(stop); + } + + @Override + default void sendActionBar(final Component message) { + SpongeViewer.super.sendActionBar(message); + } + + @Override + default void showTitle(final Title title) { + SpongeViewer.super.showTitle(title); + } + + @Override + default void sendTitlePart(final TitlePart part, final T value) { + SpongeViewer.super.sendTitlePart(part, value); + } + + @Override + default void clearTitle() { + SpongeViewer.super.clearTitle(); + } + + @Override + default void resetTitle() { + SpongeViewer.super.resetTitle(); + } +} diff --git a/src/main/java/org/spongepowered/common/effect/SpongeViewer.java b/src/main/java/org/spongepowered/common/effect/SpongeViewer.java new file mode 100644 index 00000000000..5a64f3c36ea --- /dev/null +++ b/src/main/java/org/spongepowered/common/effect/SpongeViewer.java @@ -0,0 +1,121 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.effect; + +import net.kyori.adventure.sound.SoundStop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import net.kyori.adventure.title.TitlePart; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.effect.Viewer; +import org.spongepowered.api.effect.particle.ParticleEffect; +import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.api.world.WorldType; +import org.spongepowered.common.bridge.effect.ViewerBridge; +import org.spongepowered.common.effect.util.ViewerPacketUtil; + +import java.util.Objects; + +public interface SpongeViewer extends Viewer { + + // Viewer + + @Override + default void sendWorldType(final WorldType worldType) { + ((ViewerBridge) this).bridge$sendSpongePacketToViewer(ViewerPacketUtil.changeEnvironment(worldType)); + } + + @Override + default void spawnParticles(final ParticleEffect particleEffect, final double x, final double y, final double z) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.spawnParticles(particleEffect, x, y, z)); + } + + @Override + default void playMusicDisc(final int x, final int y, final int z, final MusicDisc musicDisc) { + } + + @Override + default void stopMusicDisc(final int x, final int y, final int z) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.stopMusicDisc(x, y, z)); + } + + @Override + default void sendBlockChange(final int x, final int y, final int z, final BlockState state) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.blockUpdate(x, y, z, state)); + } + + @Override + default void resetBlockChange(final int x, final int y, final int z) { + } + + @Override + default void sendBlockProgress(final int x, final int y, final int z, final double progress) { + } + + @Override + default void resetBlockProgress(final int x, final int y, final int z) { + } + + // Audience + + @Override + default void stopSound(final SoundStop stop) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.stopSound(stop)); + } + + @Override + default void sendActionBar(final Component message) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.setActionBarText(message)); + } + + @Override + default void showTitle(final Title title) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.showTitle(title)); + } + + @Override + default void sendTitlePart(final TitlePart part, final T value) { + Objects.requireNonNull(value, "value"); + if (part == TitlePart.TITLE) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.setTitleText((Component) value)); + } else if (part == TitlePart.SUBTITLE) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.setSubtitleText((Component) value)); + } else if (part == TitlePart.TIMES) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.setTitlesAnimation((Title.Times) value)); + } else { + throw new IllegalArgumentException("Unknown TitlePart '" + part + "'"); + } + } + + @Override + default void clearTitle() { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.clearTitles(false)); + } + + @Override + default void resetTitle() { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.clearTitles(true)); + } +} diff --git a/src/main/java/org/spongepowered/common/effect/particle/CachedParticlePacket.java b/src/main/java/org/spongepowered/common/effect/particle/CachedParticlePacket.java index 0f07d8a9579..8d3c26a6dcb 100644 --- a/src/main/java/org/spongepowered/common/effect/particle/CachedParticlePacket.java +++ b/src/main/java/org/spongepowered/common/effect/particle/CachedParticlePacket.java @@ -26,14 +26,14 @@ import net.minecraft.core.particles.ParticleOptions; import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.math.vector.Vector3d; import java.util.List; interface CachedParticlePacket { - void process(Vector3d position, List> output); + void process(double x, double y, double z, List> output); @Nullable ParticleOptions particleOptions(); } diff --git a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java index cc55602fbab..3e582e1edab 100644 --- a/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java +++ b/src/main/java/org/spongepowered/common/effect/particle/SpongeParticleHelper.java @@ -35,11 +35,10 @@ import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.core.particles.VibrationParticleOption; import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.players.PlayerList; import net.minecraft.util.FastColor; -import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.effect.particle.ParticleEffect; @@ -61,25 +60,10 @@ public final class SpongeParticleHelper { - public static void sendPackets(final ParticleEffect particleEffect, final Vector3d position, final int radius, final ResourceKey type, - final PlayerList playerList) { - final List> packets = SpongeParticleHelper.toPackets(particleEffect, position); - - if (!packets.isEmpty()) { - final double x = position.x(); - final double y = position.y(); - final double z = position.z(); - - for (final Packet packet : packets) { - playerList.broadcast(null, x, y, z, radius, type, packet); - } - } - } - - public static List> toPackets(final ParticleEffect effect, final Vector3d position) { - final List> packets = new ArrayList<>(); - SpongeParticleHelper.getCachedPacket((SpongeParticleEffect) effect).process(position, packets); - return packets; + public static ClientboundBundlePacket createPacket(final ParticleEffect effect, final double x, final double y, final double z) { + final List> packets = new ArrayList<>(); + SpongeParticleHelper.getCachedPacket((SpongeParticleEffect) effect).process(x, y, z, packets); + return new ClientboundBundlePacket(packets); } public static net.minecraft.core.particles.@Nullable ParticleOptions vanillaParticleOptions(final ParticleEffect effect) { @@ -234,7 +218,7 @@ private static final class EmptyCachedPacket implements CachedParticlePacket { public static final EmptyCachedPacket INSTANCE = new EmptyCachedPacket(); @Override - public void process(final Vector3d position, final List> output) { + public void process(final double x, final double y, final double z, final List> output) { } @Override @@ -258,10 +242,10 @@ public NamedCachedPacket(final net.minecraft.core.particles.ParticleOptions part } @Override - public void process(final Vector3d position, final List> output) { - final float posX = (float) position.x(); - final float posY = (float) position.y(); - final float posZ = (float) position.z(); + public void process(final double x, final double y, final double z, final List> output) { + final float posX = (float) x; + final float posY = (float) y; + final float posZ = (float) z; final float offX = this.offset.x(); final float offY = this.offset.y(); @@ -288,14 +272,15 @@ public void process(final Vector3d position, final List> output) { final float py0 = posY + (random.nextFloat() * 2f - 1f) * offY; final float pz0 = posZ + (random.nextFloat() * 2f - 1f) * offZ; - final ClientboundLevelParticlesPacket message = new ClientboundLevelParticlesPacket( + final ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket( this.particleData, true, px0, py0, pz0, velocityX, velocityY, velocityZ, 1f, 0); - output.add(message); + + output.add(packet); } } } diff --git a/src/main/java/org/spongepowered/common/effect/util/ViewerPacketUtil.java b/src/main/java/org/spongepowered/common/effect/util/ViewerPacketUtil.java new file mode 100644 index 00000000000..96a9911c73c --- /dev/null +++ b/src/main/java/org/spongepowered/common/effect/util/ViewerPacketUtil.java @@ -0,0 +1,195 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.effect.util; + +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.sound.SoundStop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.JukeboxSong; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.dimension.DimensionType; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.Engine; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.effect.particle.ParticleEffect; +import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.WorldType; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.SpongeEngine; +import org.spongepowered.common.adventure.SpongeAdventure; +import org.spongepowered.common.effect.particle.SpongeParticleHelper; +import org.spongepowered.common.network.packet.ChangeViewerEnvironmentPacket; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public final class ViewerPacketUtil { + + public static ChangeViewerEnvironmentPacket changeEnvironment(final WorldType worldType) { + return new ChangeViewerEnvironmentPacket((DimensionType) (Object) Objects.requireNonNull(worldType, "worldType")); + } + + public static ClientboundBundlePacket spawnParticles(final ParticleEffect particleEffect, final double x, final double y, final double z) { + return SpongeParticleHelper.createPacket(particleEffect, x, y, z); + } + + public static ClientboundSoundEntityPacket playSound(final Sound sound, final Entity entity) { + Objects.requireNonNull(entity, "entity"); + final Holder event = resolveEvent(sound); + final SoundSource source = SpongeAdventure.asVanilla(sound.source()); + final net.minecraft.world.entity.Entity mcEntity = (net.minecraft.world.entity.Entity) entity; + final long random = sound.seed().orElseGet(() -> mcEntity.level().getRandom().nextLong()); + return new ClientboundSoundEntityPacket(event, source, mcEntity, sound.volume(), sound.pitch(), random); + } + + public static ClientboundSoundPacket playSound(final Sound sound, final RandomSource randomSource, final double x, final double y, final double z) { + final Holder event = resolveEvent(sound); + final SoundSource source = SpongeAdventure.asVanilla(sound.source()); + final long random = sound.seed().orElseGet(randomSource::nextLong); + return new ClientboundSoundPacket(event, source, x, y, z, sound.volume(), sound.pitch(), random); + } + + public static ClientboundStopSoundPacket stopSound(final SoundStop stop) { + Objects.requireNonNull(stop, "stop"); + final @Nullable ResourceLocation sound = SpongeAdventure.asVanillaNullable(stop.sound()); + final @Nullable SoundSource source = SpongeAdventure.asVanillaNullable(stop.source()); + return new ClientboundStopSoundPacket(sound, source); + } + + public static ClientboundLevelEventPacket playMusicDisc(final int x, final int y, final int z, final MusicDisc musicDisc, final RegistryAccess registryAccess) { + Objects.requireNonNull(musicDisc, "musicDisc"); + final int songId = registryAccess.registryOrThrow(Registries.JUKEBOX_SONG).getId((JukeboxSong) (Object) musicDisc); + return new ClientboundLevelEventPacket(1010, new BlockPos(x, y, z), songId, false); + } + + public static ClientboundLevelEventPacket stopMusicDisc(final int x, final int y, final int z) { + return new ClientboundLevelEventPacket(1011, new BlockPos(x, y, z), 0, false); + } + + public static ClientboundBlockUpdatePacket blockUpdate(final int x, final int y, final int z, final BlockState state) { + Objects.requireNonNull(state, "state"); + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), (net.minecraft.world.level.block.state.BlockState) state); + } + + public static ClientboundBlockUpdatePacket blockUpdate(final int x, final int y, final int z, final World world) { + return new ClientboundBlockUpdatePacket((BlockGetter) world, new BlockPos(x, y, z)); + } + + public static ClientboundBlockDestructionPacket blockProgress(final int x, final int y, final int z, final double progress, final Engine engine) { + if (progress < 0 || progress > 1) { + throw new IllegalArgumentException("Progress must be between 0 and 1"); + } + + final BlockPos pos = new BlockPos(x, y, z); + final int id = ((SpongeEngine) engine).getBlockDestructionIdCache().getOrCreate(pos); + final int progressStage = progress == 1 ? 9 : (int) (progress * 10); + return new ClientboundBlockDestructionPacket(id, pos, progressStage); + } + + public static Optional resetBlockProgress(final int x, final int y, final int z, final Engine engine) { + final BlockPos pos = new BlockPos(x, y, z); + return ((SpongeEngine) engine).getBlockDestructionIdCache().get(pos) + .map(id -> new ClientboundBlockDestructionPacket(id, pos, -1)); + } + + public static ClientboundSetActionBarTextPacket setActionBarText(final Component message) { + return new ClientboundSetActionBarTextPacket(SpongeAdventure.asVanilla(Objects.requireNonNull(message, "message"))); + } + + public static ClientboundBundlePacket showTitle(final Title title) { + final Title.Times times = Objects.requireNonNull(title, "title").times(); + final List> packets = new ArrayList<>(); + if (times != null) { + packets.add(ViewerPacketUtil.setTitlesAnimation(times)); + } + packets.add(ViewerPacketUtil.setSubtitleText(title.subtitle())); + packets.add(ViewerPacketUtil.setTitleText(title.title())); + return new ClientboundBundlePacket(packets); + } + + public static ClientboundSetTitleTextPacket setTitleText(final Component component) { + return new ClientboundSetTitleTextPacket(SpongeAdventure.asVanilla(component)); + } + + public static ClientboundSetSubtitleTextPacket setSubtitleText(final Component component) { + return new ClientboundSetSubtitleTextPacket(SpongeAdventure.asVanilla(component)); + } + + public static ClientboundSetTitlesAnimationPacket setTitlesAnimation(final Title.Times times) { + return new ClientboundSetTitlesAnimationPacket( + durationToTicks(times.fadeIn()), + durationToTicks(times.stay()), + durationToTicks(times.fadeOut())); + } + + public static ClientboundClearTitlesPacket clearTitles(final boolean resetTimes) { + return new ClientboundClearTitlesPacket(resetTimes); + } + + private static Holder resolveEvent(final @NonNull Sound sound) { + final ResourceLocation soundKey = SpongeAdventure.asVanilla(Objects.requireNonNull(sound, "sound").name()); + final var soundEventRegistry = SpongeCommon.vanillaRegistry(Registries.SOUND_EVENT); + final SoundEvent event = soundEventRegistry.getOptional(soundKey) + .orElseGet(() -> SoundEvent.createVariableRangeEvent(soundKey)); + + return soundEventRegistry.wrapAsHolder(event); + } + + private static int durationToTicks(final Duration duration) { + return (int) (duration.toMillis() / 50L); + } + + private ViewerPacketUtil() { + } +} diff --git a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java index 40359c793f3..7aed44d3ca1 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java @@ -44,6 +44,7 @@ import org.spongepowered.api.data.type.ToolRule; import org.spongepowered.api.data.value.Value; import org.spongepowered.api.datapack.DataPackType; +import org.spongepowered.api.effect.ForwardingViewer; import org.spongepowered.api.effect.VanishState; import org.spongepowered.api.event.EventListenerRegistration; import org.spongepowered.api.event.cause.entity.damage.source.DamageSource; @@ -121,6 +122,7 @@ import org.spongepowered.common.data.manipulator.MutableDataManipulatorFactory; import org.spongepowered.common.data.value.SpongeValueFactory; import org.spongepowered.common.datapack.SpongeDataPackType; +import org.spongepowered.common.effect.SpongeCustomForwardingViewer; import org.spongepowered.common.entity.effect.SpongeVanishState; import org.spongepowered.common.event.SpongeEventListenerRegistration; import org.spongepowered.common.event.tracking.BlockChangeFlagManager; @@ -214,6 +216,7 @@ public void registerDefaultFactories() { this .registerFactory(ResourceKey.Factory.class, new SpongeResourceKeyFactory()) .registerFactory(Audiences.Factory.class, new AudiencesFactory()) + .registerFactory(ForwardingViewer.Factory.class, new SpongeCustomForwardingViewer.FactoryImpl()) .registerFactory(AABB.Factory.class, new SpongeAABB.FactoryImpl()) .registerFactory(AdvancementCriterion.Factory.class, new SpongeAdvancementCriterionFactory()) .registerFactory(CommandCause.Factory.class, new SpongeCommandCauseFactory()) diff --git a/src/main/java/org/spongepowered/common/util/BlockDestructionIdCache.java b/src/main/java/org/spongepowered/common/util/BlockDestructionIdCache.java new file mode 100644 index 00000000000..acea335d18a --- /dev/null +++ b/src/main/java/org/spongepowered/common/util/BlockDestructionIdCache.java @@ -0,0 +1,58 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.util; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import net.minecraft.core.BlockPos; + +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.IntSupplier; +import java.util.function.ToIntFunction; + +public final class BlockDestructionIdCache { + + private final Cache cache; + private final AtomicInteger counter; + private final IntSupplier idCreator; + + public BlockDestructionIdCache(final int counterBase, final ToIntFunction idFunction) { + this.cache = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.MINUTES) + .build(); + this.counter = new AtomicInteger(counterBase); + this.idCreator = () -> idFunction.applyAsInt(this.counter); + } + + public int getOrCreate(final BlockPos pos) { + return this.cache.get(pos, $ -> this.idCreator.getAsInt()); + } + + public Optional get(final BlockPos pos) { + return Optional.ofNullable(this.cache.getIfPresent(pos)); + } +} diff --git a/src/main/java/org/spongepowered/common/util/BookUtil.java b/src/main/java/org/spongepowered/common/util/BookUtil.java index 3d0349bf5d9..8297d48dae6 100644 --- a/src/main/java/org/spongepowered/common/util/BookUtil.java +++ b/src/main/java/org/spongepowered/common/util/BookUtil.java @@ -25,10 +25,11 @@ package org.spongepowered.common.util; import net.kyori.adventure.inventory.Book; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; import net.minecraft.network.protocol.game.ClientboundOpenBookPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Inventory; import org.spongepowered.api.data.Keys; @@ -37,37 +38,37 @@ import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.common.item.util.ItemStackUtil; -import java.util.Collection; +import java.util.ArrayList; +import java.util.List; public final class BookUtil { public static final int PLAYER_INVENTORY = -2; - public static void fakeBookView(final Book book, final Collection players) { + public static ClientboundBundlePacket createFakeBookViewPacket(final Player player, final Book book) { final ItemStack item = ItemStack.of(ItemTypes.WRITTEN_BOOK); item.offer(Keys.CUSTOM_NAME, book.title()); item.offer(Keys.AUTHOR, book.author()); item.offer(Keys.PAGES, book.pages()); - for (final Player player : players) { - final ServerPlayer mcPlayer = (ServerPlayer) player; - final ServerGamePacketListenerImpl receiver = mcPlayer.connection; + final Inventory inventory = ((net.minecraft.world.entity.player.Player) player).getInventory(); + final int bookSlot = inventory.selected; + final net.minecraft.world.item.ItemStack oldItem = inventory.getSelected(); - final Inventory inventory = mcPlayer.getInventory(); - final int bookSlot = inventory.selected; - final net.minecraft.world.item.ItemStack oldItem = inventory.getSelected(); + final List> packets = new ArrayList<>(); - // First we need to send a fake a Book ItemStack with the BookView's - // contents to the player's hand - receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, ItemStackUtil.toNative(item))); + // First we need to send a fake a Book ItemStack with the BookView's + // contents to the player's hand + packets.add(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, ItemStackUtil.toNative(item))); - // Next we tell the client to open the Book GUI - receiver.send(new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND)); + // Next we tell the client to open the Book GUI + packets.add(new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND)); - // Now we can remove the fake Book since it's contents will have already - // been transferred to the GUI - receiver.send(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, oldItem)); - } + // Now we can remove the fake Book since it's contents will have already + // been transferred to the GUI + packets.add(new ClientboundContainerSetSlotPacket(BookUtil.PLAYER_INVENTORY, 0, bookSlot, oldItem)); + + return new ClientboundBundlePacket(packets); } private BookUtil() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java index c0300eacaab..8c8b1b3f89e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java @@ -47,10 +47,12 @@ import org.spongepowered.common.registry.RegistryHolderLogic; import org.spongepowered.common.registry.SpongeRegistryHolder; import org.spongepowered.common.scheduler.ClientScheduler; +import org.spongepowered.common.util.BlockDestructionIdCache; import org.spongepowered.common.util.LocaleCache; import java.util.Locale; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; @Mixin(Minecraft.class) public abstract class MinecraftMixin_API implements SpongeClient, SpongeRegistryHolder { @@ -68,6 +70,7 @@ public abstract class MinecraftMixin_API implements SpongeClient, SpongeRegistry private final ClientScheduler api$scheduler = new ClientScheduler(); private final RegistryHolderLogic api$registryHolder = new RegistryHolderLogic(); + private final BlockDestructionIdCache api$blockDestructionIdCache = new BlockDestructionIdCache(Integer.MIN_VALUE, AtomicInteger::incrementAndGet); @Override public Optional player() { @@ -138,4 +141,9 @@ public Locale locale() { public RegistryHolderLogic registryHolder() { return this.api$registryHolder; } + + @Override + public BlockDestructionIdCache getBlockDestructionIdCache() { + return this.api$blockDestructionIdCache; + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientLevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientLevelMixin_API.java index 3caa1697822..12f66296e46 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientLevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientLevelMixin_API.java @@ -29,6 +29,7 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.world.level.entity.LevelEntityGetter; +import org.spongepowered.api.Client; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.living.player.client.ClientPlayer; import org.spongepowered.api.world.client.ClientLocation; @@ -55,6 +56,11 @@ public abstract class ClientLevelMixin_API extends LevelMixin_API shadow$getEntities(); // @formatter:on + @Override + public Client engine() { + return (Client) Minecraft.getInstance(); + } + @Override public boolean isLoaded() { return Minecraft.getInstance().level == (Object) this; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java index 53b55dad3d5..f6a97235086 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java @@ -24,8 +24,6 @@ */ package org.spongepowered.common.mixin.api.minecraft.server; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.mojang.datafixers.DataFixer; @@ -36,7 +34,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.commands.Commands; -import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.server.MinecraftServer; @@ -54,7 +51,6 @@ import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Game; import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; @@ -97,6 +93,7 @@ import org.spongepowered.common.registry.SpongeRegistryHolder; import org.spongepowered.common.scheduler.ServerScheduler; import org.spongepowered.common.user.SpongeUserManager; +import org.spongepowered.common.util.BlockDestructionIdCache; import org.spongepowered.common.util.UsernameCache; import org.spongepowered.common.world.server.SpongeWorldManager; import org.spongepowered.common.world.storage.SpongeChunkLayout; @@ -112,7 +109,6 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; @@ -165,10 +161,7 @@ public abstract class MinecraftServerMixin_API implements SpongeServer, SpongeRe private RegistryHolderLogic api$registryHolder; private SpongeUserManager api$userManager; private SpongeDataPackManager api$dataPackManager; - private Cache api$blockDestructionIdCache = Caffeine.newBuilder() - .expireAfterAccess(1, TimeUnit.MINUTES) - .build(); - private AtomicInteger api$blockDestructionIdCounter = new AtomicInteger(); + private final BlockDestructionIdCache api$blockDestructionIdCache = new BlockDestructionIdCache(0, AtomicInteger::decrementAndGet); @Inject(method = "", at = @At("TAIL")) public void api$initializeSpongeFieldsfinal(final Thread $$0, final LevelStorageSource.LevelStorageAccess $$1, final PackRepository $$2, final WorldStem $$3, final Proxy $$4, @@ -487,13 +480,8 @@ public UsernameCache getUsernameCache() { } @Override - public @Nullable Integer getBlockDestructionId(BlockPos pos) { - return this.api$blockDestructionIdCache.getIfPresent(pos); - } - - @Override - public int getOrCreateBlockDestructionId(BlockPos pos) { - return this.api$blockDestructionIdCache.get(pos, (blockPos) -> this.api$blockDestructionIdCounter.decrementAndGet()); + public BlockDestructionIdCache getBlockDestructionIdCache() { + return this.api$blockDestructionIdCache; } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java index 78f0652bfc3..28800796f00 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java @@ -28,59 +28,32 @@ import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.chat.SignedMessage; import net.kyori.adventure.identity.Identity; -import net.kyori.adventure.inventory.Book; import net.kyori.adventure.permission.PermissionChecker; import net.kyori.adventure.pointer.Pointers; import net.kyori.adventure.resource.ResourcePackRequest; -import net.kyori.adventure.sound.Sound; -import net.kyori.adventure.sound.SoundStop; import net.kyori.adventure.text.Component; -import net.kyori.adventure.title.Title; -import net.kyori.adventure.title.TitlePart; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.registries.Registries; import net.minecraft.network.Connection; import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.MessageSignature; import net.minecraft.network.chat.PlayerChatMessage; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; import net.minecraft.network.protocol.game.ClientboundDeleteChatPacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; -import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; -import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; -import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; -import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; -import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; -import net.minecraft.network.protocol.game.ClientboundSoundPacket; -import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.level.ServerBossEvent; import net.minecraft.server.network.ServerGamePacketListenerImpl; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.JukeboxSong; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.advancement.AdvancementProgress; import org.spongepowered.api.advancement.AdvancementTemplate; import org.spongepowered.api.advancement.AdvancementTree; -import org.spongepowered.api.block.BlockState; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.effect.particle.ParticleEffect; -import org.spongepowered.api.effect.sound.music.MusicDisc; import org.spongepowered.api.entity.living.player.CooldownTracker; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.entity.living.player.server.ServerPlayer; @@ -92,7 +65,6 @@ import org.spongepowered.api.network.ServerSideConnection; import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.scoreboard.Scoreboard; -import org.spongepowered.api.world.WorldType; import org.spongepowered.api.world.border.WorldBorder; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Final; @@ -111,24 +83,18 @@ import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; import org.spongepowered.common.bridge.server.network.ServerCommonPacketListenerImplBridge; import org.spongepowered.common.bridge.world.level.border.WorldBorderBridge; -import org.spongepowered.common.effect.particle.SpongeParticleHelper; import org.spongepowered.common.entity.player.SpongeUserView; import org.spongepowered.common.entity.player.tab.SpongeTabList; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.mixin.api.minecraft.world.entity.player.PlayerMixin_API; import org.spongepowered.common.profile.SpongeGameProfile; -import org.spongepowered.common.util.BookUtil; import org.spongepowered.common.util.NetworkUtil; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3d; -import org.spongepowered.math.vector.Vector3i; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; @@ -159,27 +125,6 @@ public ServerWorld world() { return (ServerWorld) this.shadow$serverLevel(); } - @Override - public void spawnParticles(final ParticleEffect particleEffect, final Vector3d position, final int radius) { - if (this.impl$isFake) { - return; - } - Objects.requireNonNull(particleEffect, "particleEffect"); - Objects.requireNonNull(position, "position"); - if (radius <= 0) { - throw new IllegalArgumentException("The radius has to be greater then zero!"); - } - final List> packets = SpongeParticleHelper.toPackets(particleEffect, position); - - if (!packets.isEmpty()) { - if (position.sub(this.shadow$getX(), this.shadow$getY(), this.shadow$getZ()).lengthSquared() < (long) radius * (long) radius) { - for (final Packet packet : packets) { - this.connection.send(packet); - } - } - } - } - @Override public User user() { return SpongeUserView.create(this.uuid); @@ -198,22 +143,6 @@ public GameProfile profile() { return SpongeGameProfile.of(this.shadow$getGameProfile()); } - @Override - public void sendWorldType(final WorldType worldType) { - if (this.impl$isFake) { - return; - } - ((ServerPlayerBridge) this).bridge$sendViewerEnvironment((DimensionType) (Object) Objects.requireNonNull(worldType, "worldType")); - } - - @Override - public void spawnParticles(final ParticleEffect particleEffect, final Vector3d position) { - if (this.impl$isFake) { - return; - } - this.spawnParticles(particleEffect, position, Integer.MAX_VALUE); - } - @Override public ServerSideConnection connection() { final Connection connection = ((ServerCommonPacketListenerImplAccessor) this.connection).accessor$connection(); @@ -264,19 +193,6 @@ public boolean kick(final Component message) { return ((ServerPlayerBridge) this).bridge$kick(Objects.requireNonNull(message, "message")); } - @Override - public void playMusicDisc(final Vector3i position, final MusicDisc recordType) { - Objects.requireNonNull(position, "position"); - Objects.requireNonNull(recordType, "recordType"); - int songId = this.shadow$level().registryAccess().registryOrThrow(Registries.JUKEBOX_SONG).getId((JukeboxSong) (Object) recordType); - this.connection.send(new ClientboundLevelEventPacket(1010, VecHelper.toBlockPos(position), songId, false)); - } - - @Override - public void stopMusicDisc(final Vector3i position) { - this.connection.send(new ClientboundLevelEventPacket(1011, VecHelper.toBlockPos(position), 0, false)); - } - @Override public TabList tabList() { return this.api$tabList; @@ -291,37 +207,6 @@ public boolean hasPlayedBefore() { return timeSinceFirstJoined.getSeconds() > 0; } - @Override - public void sendBlockChange(final int x, final int y, final int z, final BlockState state) { - this.connection.send(new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), (net.minecraft.world.level.block.state.BlockState) state)); - } - - @Override - public void resetBlockChange(final int x, final int y, final int z) { - this.connection.send(new ClientboundBlockUpdatePacket(this.shadow$getCommandSenderWorld(), new BlockPos(x, y, z))); - } - - @Override - public void sendBlockProgress(final int x, final int y, final int z, final double progress) { - if (progress < 0 || progress > 1) { - throw new IllegalArgumentException("Progress must be between 0 and 1"); - } - - final BlockPos pos = new BlockPos(x, y, z); - final int id = ((SpongeServer) this.server).getOrCreateBlockDestructionId(pos); - final int progressStage = progress == 1 ? 9 : (int) (progress * 10); - this.connection.send(new ClientboundBlockDestructionPacket(id, pos, progressStage)); - } - - @Override - public void resetBlockProgress(final int x, final int y, final int z) { - final BlockPos pos = new BlockPos(x, y, z); - final Integer id = ((SpongeServer) this.server).getBlockDestructionId(pos); - if (id != null) { - this.connection.send(new ClientboundBlockDestructionPacket(id, pos, -1)); - } - } - @Override public boolean respawn() { if (this.impl$isFake) { @@ -510,14 +395,6 @@ public void deleteMessage(final SignedMessage.@NonNull Signature signature) { .pack(((ServerGamePacketListenerImplAccessor) this.connection).accessor$messageSignatureCache()))); } - @Override - public void sendActionBar(final Component message) { - if (this.impl$isFake) { - return; - } - this.connection.send(new ClientboundSetActionBarTextPacket(SpongeAdventure.asVanilla(Objects.requireNonNull(message, "message")))); - } - @Override public void sendPlayerListHeader(final Component header) { this.api$tabList.setHeader(Objects.requireNonNull(header, "header")); @@ -533,57 +410,6 @@ public void sendPlayerListHeaderAndFooter(final Component header, final Componen this.api$tabList.setHeaderAndFooter(Objects.requireNonNull(header, "header"), Objects.requireNonNull(footer, "footer")); } - @Override - public void showTitle(final Title title) { - if (this.impl$isFake) { - return; - } - final Title.Times times = Objects.requireNonNull(title, "title").times(); - if (times != null) { - this.connection.send(new ClientboundSetTitlesAnimationPacket( - this.api$durationToTicks(times.fadeIn()), - this.api$durationToTicks(times.stay()), - this.api$durationToTicks(times.fadeOut()) - )); - } - this.connection.send(new ClientboundSetSubtitleTextPacket(SpongeAdventure.asVanilla(title.subtitle()))); - this.connection.send(new ClientboundSetTitleTextPacket(SpongeAdventure.asVanilla(title.title()))); - } - - @Override - public void sendTitlePart(final @NonNull TitlePart part, final @NonNull T value) { - if (this.impl$isFake) { - return; - } - Objects.requireNonNull(value, "value"); - if (part == TitlePart.TITLE) { - this.connection.send(new ClientboundSetTitleTextPacket(SpongeAdventure.asVanilla((Component) value))); - } else if (part == TitlePart.SUBTITLE) { - this.connection.send(new ClientboundSetSubtitleTextPacket(SpongeAdventure.asVanilla((Component) value))); - } else if (part == TitlePart.TIMES) { - final Title.Times times = (Title.Times) value; - this.connection.send(new ClientboundSetTitlesAnimationPacket(this.api$durationToTicks(times.fadeIn()), this.api$durationToTicks(times.stay()), this.api$durationToTicks(times.fadeOut()))); - } else { - throw new IllegalArgumentException("Unknown TitlePart '" + part + "'"); - } - } - - @Override - public void clearTitle() { - if (this.impl$isFake) { - return; - } - this.connection.send(new ClientboundClearTitlesPacket(false)); - } - - @Override - public void resetTitle() { - if (this.impl$isFake) { - return; - } - this.connection.send(new ClientboundClearTitlesPacket(true)); - } - @Override public void showBossBar(final BossBar bar) { if (this.impl$isFake) { @@ -602,83 +428,11 @@ public void hideBossBar(final BossBar bar) { vanilla.removePlayer((net.minecraft.server.level.ServerPlayer) (Object) this); } - @Override - public void playSound(final Sound sound) { - this.playSound(Objects.requireNonNull(sound, "sound"), this.shadow$getX(), this.shadow$getY(), this.shadow$getZ()); - } - - private Holder api$resolveEvent(final @NonNull Sound sound) { - final ResourceLocation eventId = SpongeAdventure.asVanilla(Objects.requireNonNull(sound, "sound").name()); - final var soundEventRegistry = SpongeCommon.vanillaRegistry(Registries.SOUND_EVENT); - final SoundEvent event = soundEventRegistry.getOptional(eventId) - .orElseGet(() -> SoundEvent.createVariableRangeEvent(eventId)); - - return soundEventRegistry.wrapAsHolder(event); - } - - @Override - public void playSound(final @NonNull Sound sound, final Sound.@NonNull Emitter emitter) { - Objects.requireNonNull(sound, "sound"); - Objects.requireNonNull(emitter, "emitter"); - if (this.impl$isFake) { - return; - } - - final Entity tracked; - if (emitter == Sound.Emitter.self()) { - tracked = (Entity) (Object) this; - } else if (emitter instanceof org.spongepowered.api.entity.Entity) { - tracked = (Entity) emitter; - } else { - throw new IllegalArgumentException("Specified emitter '" + emitter + "' is not a Sponge Entity or Emitter.self(), was of type '" + emitter.getClass() + "'"); - } - - this.connection.send(new ClientboundSoundEntityPacket( - this.api$resolveEvent(sound), - SpongeAdventure.asVanilla(sound.source()), - tracked, - sound.volume(), - sound.pitch(), - sound.seed().orElseGet(() -> tracked.level().getRandom().nextLong()) - )); - } - - @Override - public void playSound(final Sound sound, final double x, final double y, final double z) { - if (this.impl$isFake) { - return; - } - final SoundSource source = SpongeAdventure.asVanilla(sound.source()); - final Holder event = this.api$resolveEvent(sound); - final long random = sound.seed().orElseGet(() -> this.shadow$serverLevel().getRandom().nextLong()); - this.connection.send(new ClientboundSoundPacket(event, source, x, y, z, sound.volume(), sound.pitch(), random)); - } - - @Override - public void stopSound(final SoundStop stop) { - if (this.impl$isFake) { - return; - } - this.connection.send(new ClientboundStopSoundPacket(SpongeAdventure.asVanillaNullable(Objects.requireNonNull(stop, "stop").sound()), SpongeAdventure.asVanillaNullable(stop.source()))); - } - - @Override - public void openBook(@NonNull final Book book) { - if (this.impl$isFake) { - return; - } - BookUtil.fakeBookView(Objects.requireNonNull(book, "book"), Collections.singletonList(this)); - } - @Override public @NonNull Locale locale() { return ((ServerPlayerBridge) this).bridge$getLanguage(); } - private int api$durationToTicks(final Duration duration) { - return (int) (duration.toMillis() / 50L); - } - @Override public void sendResourcePacks(final @NonNull ResourcePackRequest request) { ((ServerCommonPacketListenerImplBridge) this.connection).bridge$sendResourcePacks(request); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java index 0e79e221569..afb59e418aa 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java @@ -27,25 +27,34 @@ import com.mojang.authlib.GameProfile; import net.kyori.adventure.identity.Identified; import net.kyori.adventure.identity.Identity; +import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.sound.Sound; import net.minecraft.network.chat.Component; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemCooldowns; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; import org.spongepowered.asm.mixin.Interface.Remap; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.bridge.effect.ViewerBridge; import org.spongepowered.common.bridge.world.entity.PlatformEntityBridge; +import org.spongepowered.common.effect.SpongeViewer; +import org.spongepowered.common.effect.util.ViewerPacketUtil; import org.spongepowered.common.mixin.api.minecraft.world.entity.LivingEntityMixin_API; +import org.spongepowered.common.util.BookUtil; +import java.util.Objects; import java.util.Set; @Mixin(net.minecraft.world.entity.player.Player.class) @Implements(@Interface(iface=Identified.class, prefix = "identified$", remap = Remap.NONE)) -public abstract class PlayerMixin_API extends LivingEntityMixin_API implements Player { +public abstract class PlayerMixin_API extends LivingEntityMixin_API implements Player, SpongeViewer { // @formatter:off @Shadow public AbstractContainerMenu containerMenu; @@ -96,4 +105,55 @@ public String name() { public Identity identified$identity() { return this.profile(); } + + // Viewer + + @Override + public void playMusicDisc(final int x, final int y, final int z, final MusicDisc musicDisc) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playMusicDisc(x, y, z, musicDisc, this.shadow$level().registryAccess())); + } + + @Override + public void resetBlockChange(final int x, final int y, final int z) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.blockUpdate(x, y, z, this.world())); + } + + @Override + public void sendBlockProgress(final int x, final int y, final int z, final double progress) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.blockProgress(x, y, z, progress, this.world().engine())); + } + + @Override + public void resetBlockProgress(final int x, final int y, final int z) { + ViewerPacketUtil.resetBlockProgress(x, y, z, this.world().engine()).ifPresent(((ViewerBridge) this)::bridge$sendToViewer); + } + + // Audience + + @Override + public void playSound(final Sound sound, final double x, final double y, final double z) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playSound(sound, this.shadow$level().random, x, y, z)); + } + + @Override + public void playSound(final Sound sound) { + this.playSound(sound, this.shadow$getX(), this.shadow$getY(), this.shadow$getZ()); + } + + @Override + public void playSound(final Sound sound, final Sound.Emitter emitter) { + Objects.requireNonNull(emitter, "emitter"); + if (emitter == Sound.Emitter.self()) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playSound(sound, this)); + } else if (emitter instanceof final Entity entityEmitter) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playSound(sound, entityEmitter)); + } else { + throw new IllegalArgumentException("Specified emitter '" + emitter + "' is not a Sponge Entity or Emitter.self(), was of type '" + emitter.getClass() + "'"); + } + } + + @Override + public void openBook(final Book book) { + ((ViewerBridge) this).bridge$sendToViewer(BookUtil.createFakeBookViewPacket(this, Objects.requireNonNull(book, "book"))); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java index 9e6489a0b8b..c214fad3db2 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java @@ -26,28 +26,16 @@ import net.kyori.adventure.sound.Sound; import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; import net.minecraft.util.Tuple; -import net.minecraft.world.item.JukeboxSong; -import net.minecraft.world.item.JukeboxSongPlayer; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ImposterProtoChunk; @@ -59,7 +47,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.entity.BlockEntity; import org.spongepowered.api.data.persistence.DataContainer; -import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.sound.music.MusicDisc; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.EntityType; @@ -85,13 +72,12 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.SpongeServer; import org.spongepowered.common.accessor.server.level.ChunkMapAccessor; import org.spongepowered.common.accessor.world.entity.EntityAccessor; -import org.spongepowered.common.adventure.SpongeAdventure; +import org.spongepowered.common.bridge.effect.ViewerBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; -import org.spongepowered.common.effect.particle.SpongeParticleHelper; +import org.spongepowered.common.effect.SpongeForwardingViewer; +import org.spongepowered.common.effect.util.ViewerPacketUtil; import org.spongepowered.common.entity.SpongeEntityTypes; import org.spongepowered.common.registry.RegistryHolderLogic; import org.spongepowered.common.registry.SpongeRegistryHolder; @@ -115,13 +101,12 @@ import java.util.stream.Stream; @Mixin(net.minecraft.world.level.Level.class) -public abstract class LevelMixin_API, L extends Location> implements World, SpongeRegistryHolder, AutoCloseable { +public abstract class LevelMixin_API, L extends Location> implements World, SpongeRegistryHolder, SpongeForwardingViewer, AutoCloseable { // @formatter:off @Shadow public @Final net.minecraft.util.RandomSource random; @Shadow @Nullable public abstract MinecraftServer shadow$getServer(); - @Shadow public abstract void shadow$playSound(net.minecraft.world.entity.player.@Nullable Player p_184148_1_, double p_184148_2_, double p_184148_4_, double p_184148_6_, SoundEvent p_184148_8_, SoundSource p_184148_9_, float p_184148_10_, float p_184148_11_); @Shadow public abstract LevelData shadow$getLevelData(); @Shadow public abstract ResourceKey shadow$dimension(); @Shadow public abstract void shadow$setBlockEntity(net.minecraft.world.level.block.entity.BlockEntity var1); @@ -257,100 +242,34 @@ public Context context() { // Viewer @Override - public void spawnParticles(final ParticleEffect particleEffect, final Vector3d position, final int radius) { - Objects.requireNonNull(particleEffect, "particleEffect"); - Objects.requireNonNull(position, "position"); - if (radius <= 0) { - throw new IllegalArgumentException("The radius has to be greater then zero!"); - } - - SpongeParticleHelper.sendPackets(particleEffect, position, radius, this.shadow$dimension(), this.shadow$getServer().getPlayerList()); - } - - @Override - public void playMusicDisc(final Vector3i position, final MusicDisc musicDisc) { - this.api$playRecord(Objects.requireNonNull(position, "position"), Objects.requireNonNull(musicDisc, "musicDisc")); - } - - @Override - public void stopMusicDisc(final Vector3i position) { - this.api$playRecord(Objects.requireNonNull(position, "position"), null); - } - - @Override - public void sendBlockChange(final int x, final int y, final int z, final org.spongepowered.api.block.BlockState state) { - Objects.requireNonNull(state, "state"); - - final ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), (BlockState) state); - - ((net.minecraft.world.level.Level) (Object) this).players() - .stream() - .filter(ServerPlayer.class::isInstance) - .map(ServerPlayer.class::cast) - .forEach(p -> p.connection.send(packet)); + public void playMusicDisc(final int x, final int y, final int z, final MusicDisc musicDisc) { + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playMusicDisc(x, y, z, musicDisc, ((LevelAccessor) this).registryAccess())); } @Override public void resetBlockChange(final int x, final int y, final int z) { - final ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket((LevelReader) this, new BlockPos(x, y, z)); - - ((net.minecraft.world.level.Level) (Object) this).players().stream() - .filter(ServerPlayer.class::isInstance) - .map(ServerPlayer.class::cast) - .forEach(p -> p.connection.send(packet)); + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.blockUpdate(x, y, z, this)); } @Override public void sendBlockProgress(final int x, final int y, final int z, final double progress) { - if (progress < 0 || progress > 1) { - throw new IllegalArgumentException("Progress must be between 0 and 1"); - } - - final BlockPos pos = new BlockPos(x, y, z); - final int id = ((SpongeServer) this.shadow$getServer()).getOrCreateBlockDestructionId(pos); - final int progressStage = progress == 1 ? 9 : (int) (progress * 10); - final ClientboundBlockDestructionPacket packet = new ClientboundBlockDestructionPacket(id, pos, progressStage); - ((net.minecraft.world.level.Level) (Object) this).players().stream() - .filter(ServerPlayer.class::isInstance) - .map(ServerPlayer.class::cast) - .forEach(p -> p.connection.send(packet)); + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.blockProgress(x, y, z, progress, this.engine())); } @Override public void resetBlockProgress(final int x, final int y, final int z) { - final BlockPos pos = new BlockPos(x, y, z); - final Integer id = ((SpongeServer) this.shadow$getServer()).getBlockDestructionId(pos); - if (id != null) { - final ClientboundBlockDestructionPacket packet =new ClientboundBlockDestructionPacket(id, pos, -1); - ((net.minecraft.world.level.Level) (Object) this).players().stream() - .filter(ServerPlayer.class::isInstance) - .map(ServerPlayer.class::cast) - .forEach(p -> p.connection.send(packet)); - } + ViewerPacketUtil.resetBlockProgress(x, y, z, this.engine()).ifPresent(((ViewerBridge) this)::bridge$sendToViewer); } - // ArchetypeVolumeCreator - // Audience @Override public void playSound(final Sound sound, final double x, final double y, final double z) { - // Check if the event is registered (ie has an integer ID) - final ResourceLocation soundKey = SpongeAdventure.asVanilla(sound.name()); - final Optional event = SpongeCommon.vanillaRegistry(Registries.SOUND_EVENT).getOptional(soundKey); - final SoundSource soundCategory = SpongeAdventure.asVanilla(sound.source()); - if (event.isPresent()) { - this.shadow$playSound(null,x, y, z, event.get(), soundCategory, sound.volume(), sound.pitch()); - } else { - // Otherwise send it as a custom sound - final float volume = sound.volume(); - final double radius = volume > 1.0f ? (16.0f * volume) : 16.0d; - final long random = this.random.nextLong(); - final ClientboundSoundPacket packet = new ClientboundSoundPacket(Holder.direct(SoundEvent.createVariableRangeEvent(soundKey)), soundCategory, x, y, z, volume, sound.pitch(), random); - this.shadow$getServer().getPlayerList().broadcast(null, x, y, z, radius, this.shadow$dimension(), packet); - } + ((ViewerBridge) this).bridge$sendToViewer(ViewerPacketUtil.playSound(sound, this.random, x, y, z)); } + // BlockEntityVolume + @Override public Collection blockEntities() { // TODO - Figure out a clean way to gather tickable block entities @@ -400,6 +319,8 @@ public Optional createEntity(final DataContainer container, final Vector return Optional.ofNullable(((LevelBridge) this).bridge$createEntity(container, position, null)); } + // ArchetypeVolumeCreator + @Override public ArchetypeVolume createArchetypeVolume(final Vector3i min, final Vector3i max, final Vector3i origin) { final Vector3i rawVolMin = Objects.requireNonNull(min, "min").min(Objects.requireNonNull(max, "max")); @@ -441,11 +362,6 @@ public ArchetypeVolume createArchetypeVolume(final Vector3i min, final Vector3i return volume; } - private void api$playRecord(final Vector3i position, @Nullable final MusicDisc recordType) { - var songPlayer = new JukeboxSongPlayer(() -> {}, VecHelper.toBlockPos(position)); - songPlayer.play((Level) (Object) this, Holder.direct((JukeboxSong) (Object) recordType)); - } - // EntityVolume @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/client/player/LocalPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/client/player/LocalPlayerMixin.java new file mode 100644 index 00000000000..78225a8dd8e --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/core/client/player/LocalPlayerMixin.java @@ -0,0 +1,45 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.core.client.player; + +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(LocalPlayer.class) +public abstract class LocalPlayerMixin extends AbstractClientPlayerMixin { + + @Shadow @Final public ClientPacketListener connection; + + @Override + public void bridge$sendToViewer(final Packet packet) { + packet.handle(this.connection); + } + +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index f28680c4acc..d55c5a50597 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -37,6 +37,8 @@ import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.OutgoingChatMessage; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBossEventPacket; import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; import net.minecraft.network.protocol.game.ClientboundGameEventPacket; @@ -133,6 +135,7 @@ import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; import org.spongepowered.common.data.DataUtil; import org.spongepowered.common.data.type.SpongeSkinPart; +import org.spongepowered.common.entity.player.ClientType; import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseTracker; @@ -140,6 +143,7 @@ import org.spongepowered.common.event.tracking.phase.entity.TeleportContext; import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.mixin.core.world.entity.player.PlayerMixin; +import org.spongepowered.common.network.packet.SpongePacketHandler; import org.spongepowered.common.util.LocaleCache; import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.border.PlayerOwnBorderListener; @@ -372,6 +376,25 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr this.impl$sleepingIgnored = sleepingIgnored; } + @Override + public void bridge$sendSpongePacketToViewer(final org.spongepowered.api.network.channel.packet.Packet packet) { + if (this.impl$isFake) { + return; + } + final ClientType clientType = this.bridge$getClientType(); + if (clientType == ClientType.SPONGE_VANILLA || clientType == ClientType.SPONGE_FORGE) { + SpongePacketHandler.getChannel().sendTo((ServerPlayer) this, packet); + } + } + + @Override + public void bridge$sendToViewer(final Packet packet) { + if (this.impl$isFake) { + return; + } + this.connection.send(packet); + } + /* @Inject(method = "markPlayerActive()V", at = @At("HEAD")) private void impl$onPlayerActive(final CallbackInfo ci) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java index 9878b73d664..6a3aa2c542f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java @@ -70,6 +70,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.bridge.authlib.GameProfileHolderBridge; +import org.spongepowered.common.bridge.effect.ViewerBridge; import org.spongepowered.common.bridge.server.level.ServerLevelBridge; import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; @@ -87,7 +88,7 @@ import java.util.List; @Mixin(net.minecraft.world.entity.player.Player.class) -public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBridge, GameProfileHolderBridge { +public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBridge, GameProfileHolderBridge, ViewerBridge { // @formatter: off @Shadow @Final protected static EntityDataAccessor DATA_PLAYER_MODE_CUSTOMISATION; diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 1e482eacbe7..be39f28615f 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -278,6 +278,7 @@ "client.multiplayer.ClientLevelMixin", "client.network.chat.TranslatableContentsMixin", "client.player.AbstractClientPlayerMixin", + "client.player.LocalPlayerMixin", "client.server.IntegratedPlayerListMixin", "client.server.IntegratedServerMixin", "server.network.MemoryServerHandshakePacketListenerImplMixin" diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java index 8897322b235..0718cf4e114 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/level/ServerPlayerMixin_Vanilla.java @@ -24,32 +24,20 @@ */ package org.spongepowered.vanilla.mixin.core.server.level; -import net.minecraft.world.level.dimension.DimensionType; import org.checkerframework.checker.nullness.qual.NonNull; -import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.common.bridge.server.level.ServerPlayerBridge; -import org.spongepowered.common.entity.player.ClientType; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.network.packet.ChangeViewerEnvironmentPacket; -import org.spongepowered.common.network.packet.SpongePacketHandler; import org.spongepowered.vanilla.mixin.core.world.entity.LivingEntityMixin_Vanilla; @Mixin(net.minecraft.server.level.ServerPlayer.class) public abstract class ServerPlayerMixin_Vanilla extends LivingEntityMixin_Vanilla implements ServerPlayerBridge { - @Override - public void bridge$sendViewerEnvironment(final DimensionType dimensionType) { - if (this.bridge$getClientType() == ClientType.SPONGE_VANILLA) { - SpongePacketHandler.getChannel().sendTo((ServerPlayer) this, new ChangeViewerEnvironmentPacket(dimensionType)); - } - } - // override from LivingEntityMixin_Vanilla @Override protected void vanilla$onElytraUse(final CallbackInfo ci) { From 1fb0554dc5f8175db8e7337d8a8fd1a04cbccc2f Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 22:02:02 +0200 Subject: [PATCH 105/226] Bump SpongeAPI --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 54f7a877272..1f3b8648d92 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 54f7a8772720e9e0c818eddb5fee9644574a18e8 +Subproject commit 1f3b8648d92fe27dd029fe2373fe61b185fdf5e0 From 3a7fdd7d8ecc9a15d7508a3abe8b7b50daa30e39 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 21:01:47 +0200 Subject: [PATCH 106/226] Add VehicleEntityMixin_API --- .../vehicle/VehicleEntityMixin_API.java | 33 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/vehicle/VehicleEntityMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/vehicle/VehicleEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/vehicle/VehicleEntityMixin_API.java new file mode 100644 index 00000000000..5f99c03e02c --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/vehicle/VehicleEntityMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.vehicle; + +import net.minecraft.world.entity.vehicle.VehicleEntity; +import org.spongepowered.api.entity.vehicle.Vehicle; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(VehicleEntity.class) +public abstract class VehicleEntityMixin_API implements Vehicle { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 95bc29cbd7e..9751aa6aef0 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -297,6 +297,7 @@ "minecraft.world.entity.vehicle.MinecartMixin_API", "minecraft.world.entity.vehicle.MinecartSpawnerMixin_API", "minecraft.world.entity.vehicle.MinecartTNTMixin_API", + "minecraft.world.entity.vehicle.VehicleEntityMixin_API", "minecraft.world.item.ArmorMaterialMixin_API", "minecraft.world.item.DyeColorMixin_API", "minecraft.world.item.FireworkExplosion_ShapeMixin_API", From 467527062cecc522b8e1af34f7fca7f351f51caa Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 21:46:54 +0200 Subject: [PATCH 107/226] Add missing GlowItemFrameMixin_API --- .../decoration/GlowItemFrameMixin_API.java | 32 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/GlowItemFrameMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/GlowItemFrameMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/GlowItemFrameMixin_API.java new file mode 100644 index 00000000000..5795a92b443 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/decoration/GlowItemFrameMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.decoration; + +import org.spongepowered.api.entity.hanging.GlowItemFrame; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.decoration.GlowItemFrame.class) +public abstract class GlowItemFrameMixin_API implements GlowItemFrame { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 9751aa6aef0..434128163c7 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -193,6 +193,7 @@ "minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseMixin_API", "minecraft.world.entity.decoration.ArmorStandMixin_API", "minecraft.world.entity.decoration.BlockAttachedEntityMixin_API", + "minecraft.world.entity.decoration.GlowItemFrameMixin_API", "minecraft.world.entity.decoration.HangingEntityMixin_API", "minecraft.world.entity.decoration.ItemFrameMixin_API", "minecraft.world.entity.decoration.LeashFenceKnotEntityMixin_API", From 21840915f89192ea254c168c128d87260afdee31 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 21:52:02 +0200 Subject: [PATCH 108/226] Add missing GlowSquidMixin_API --- .../world/entity/GlowSquidMixin_API.java | 32 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/GlowSquidMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/GlowSquidMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/GlowSquidMixin_API.java new file mode 100644 index 00000000000..de783fb269b --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/GlowSquidMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.living.aquatic.GlowSquid; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.GlowSquid.class) +public abstract class GlowSquidMixin_API implements GlowSquid { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 434128163c7..1ce59e0f779 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -101,6 +101,7 @@ "minecraft.world.entity.EntityTypeMixin_API", "minecraft.world.entity.ExperienceOrbMixin_API", "minecraft.world.entity.FlyingMobMixin_API", + "minecraft.world.entity.GlowSquidMixin_API", "minecraft.world.entity.HumanoidArmMixin_API", "minecraft.world.entity.InteractionMixin_API", "minecraft.world.entity.LightningBoltMixin_API", From 1cfbd5c15ab5b028c9dadc8a2fbaa4595d335dc0 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 21:57:25 +0200 Subject: [PATCH 109/226] Add missing GoatMixin_API --- .../entity/animal/goat/GoatMixin_API.java | 32 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/goat/GoatMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/goat/GoatMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/goat/GoatMixin_API.java new file mode 100644 index 00000000000..edf36d9e983 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/goat/GoatMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.animal.goat; + +import org.spongepowered.api.entity.living.animal.Goat; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.animal.goat.Goat.class) +public abstract class GoatMixin_API implements Goat { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 1ce59e0f779..539946cf0b7 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -173,6 +173,7 @@ "minecraft.world.entity.animal.camel.CamelMixin_API", "minecraft.world.entity.animal.frog.FrogMixin_API", "minecraft.world.entity.animal.frog.TadpoleMixin_API", + "minecraft.world.entity.animal.goat.GoatMixin_API", "minecraft.world.entity.animal.horse.AbstractChestedHorseMixin_API", "minecraft.world.entity.animal.horse.AbstractHorseMixin_API", "minecraft.world.entity.animal.horse.DonkeyMixin_API", From f71d0eadf6b1b1258a28c19b3652e1199db95f41 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 22:00:08 +0200 Subject: [PATCH 110/226] Add missing StriderMixin_API --- .../entity/monster/StriderMixin_API.java | 32 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java new file mode 100644 index 00000000000..c915884ae7a --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; + +import org.spongepowered.api.entity.living.monster.Strider; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.monster.Strider.class) +public abstract class StriderMixin_API implements Strider { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 539946cf0b7..ddc35315c70 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -240,6 +240,7 @@ "minecraft.world.entity.monster.SpellcasterIllagerMixin_API", "minecraft.world.entity.monster.SpiderMixin_API", "minecraft.world.entity.monster.StrayMixin_API", + "minecraft.world.entity.monster.StriderMixin_API", "minecraft.world.entity.monster.VexMixin_API", "minecraft.world.entity.monster.VindicatorMixin_API", "minecraft.world.entity.monster.WitchMixin_API", From 6d2debcce572ae4e8ad3f618147f7ccd38aecb47 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 21:55:17 +0200 Subject: [PATCH 111/226] Add missing AxolotlMixin_API --- .../animal/axolotl/AxolotlMixin_API.java | 32 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/axolotl/AxolotlMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/axolotl/AxolotlMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/axolotl/AxolotlMixin_API.java new file mode 100644 index 00000000000..c8fc3e0c555 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/axolotl/AxolotlMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.animal.axolotl; + +import org.spongepowered.api.entity.living.animal.Axolotl; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.animal.axolotl.Axolotl.class) +public abstract class AxolotlMixin_API implements Axolotl { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index ddc35315c70..1103908b900 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -169,6 +169,7 @@ "minecraft.world.entity.animal.WaterAnimalMixin_API", "minecraft.world.entity.animal.WolfMixin_API", "minecraft.world.entity.animal.allay.AllayMixin_API", + "minecraft.world.entity.animal.axolotl.AxolotlMixin_API", "minecraft.world.entity.animal.armadillo.ArmadilloMixin_API", "minecraft.world.entity.animal.camel.CamelMixin_API", "minecraft.world.entity.animal.frog.FrogMixin_API", From 3e1d96b44d13df7be8cd81db622e27ab06366e5b Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Thu, 27 Jun 2024 20:26:27 +0200 Subject: [PATCH 112/226] Rename RegistryTest to ValidationTest and add checkentities command --- .../test/registry/RegistryTest.java | 185 --------- .../test/validation/ValidationTest.java | 373 ++++++++++++++++++ .../resources/META-INF/sponge_plugins.json | 8 +- 3 files changed, 377 insertions(+), 189 deletions(-) delete mode 100644 testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java create mode 100644 testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java diff --git a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java b/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java deleted file mode 100644 index 78db4e2eaa6..00000000000 --- a/testplugins/src/main/java/org/spongepowered/test/registry/RegistryTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.test.registry; - -import com.google.inject.Inject; -import net.kyori.adventure.text.Component; -import org.apache.logging.log4j.Logger; -import org.spongepowered.api.command.Command; -import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.parameter.CommandContext; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; -import org.spongepowered.api.registry.DefaultedRegistryReference; -import org.spongepowered.api.registry.DefaultedRegistryType; -import org.spongepowered.api.registry.RegistryTypes; -import org.spongepowered.api.util.annotation.CatalogedBy; -import org.spongepowered.plugin.PluginContainer; -import org.spongepowered.plugin.builtin.jvm.Plugin; -import org.spongepowered.test.LoadableModule; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.util.Arrays; - -@Plugin("registrytest") -public final class RegistryTest implements LoadableModule { - - private final PluginContainer plugin; - private final Logger logger; - private boolean verbose; - - @Inject - public RegistryTest(final PluginContainer plugin, final Logger logger) { - this.plugin = plugin; - this.logger = logger; - } - - @Override - public void enable(final CommandContext ctx) { - } - - @Listener - private void onRegisterSpongeCommand(final RegisterCommandEvent event) { - event.register( - this.plugin, - Command.builder() - .executor(context -> { - this.verbose = !this.verbose; - context.sendMessage(Component.text("Verbose flag set to " + this.verbose)); - return CommandResult.success(); - }) - .build(), - "toggleverbose"); - event.register( - this.plugin, - Command.builder() - .executor(context -> { - for (final Field field : RegistryTypes.class.getDeclaredFields()) { - final Object registryField; - try { - registryField = field.get(null); - } catch (final IllegalAccessException e) { - this.logger.error("Failed to get field {}: {}", field.getName(), e.getMessage()); - if (this.verbose) { - this.logger.error("Exception", e); - } - continue; - } - - if (registryField instanceof DefaultedRegistryType registryType) { - if (registryType.find().isEmpty()) { - this.logger.error("Registry {} is empty", registryType.location()); - continue; - } - - final var typeArg = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; - final Class catalogEntryClass; - switch (typeArg) { - case final ParameterizedType parameterizedTypeArg -> - catalogEntryClass = (Class) parameterizedTypeArg.getRawType(); - case final Class clazz -> catalogEntryClass = clazz; - case null, default -> { - this.logger.error("Unhandled catalog entry arg type: {}", typeArg); - continue; - } - } - - final var catalogedByAnnotation = catalogEntryClass.getDeclaredAnnotation(CatalogedBy.class); - - if (catalogedByAnnotation == null) { - this.logger.error("Class {} in registry {} is not annotated with CatalogedBy", catalogEntryClass.getSimpleName(), registryType.location()); - continue; - } - - final var catalogClass = catalogedByAnnotation.value()[0]; - if (!Modifier.isFinal(catalogClass.getModifiers())) { - this.logger.error("{} is not final", catalogClass.getSimpleName()); - } - - if (Arrays.stream(catalogClass.getDeclaredConstructors()).anyMatch(ctor -> !Modifier.isPrivate(ctor.getModifiers()))) { - this.logger.error("{} has non-private constructors", catalogClass.getSimpleName()); - } - - final Method registryMethod; - try { - registryMethod = catalogClass.getDeclaredMethod("registry"); - } catch (final NoSuchMethodException e) { - this.logger.error("{}.registry() does not exist", catalogClass.getSimpleName()); - continue; - } - - final Object registryReturn; - try { - registryReturn = registryMethod.invoke(null); - } catch (final Throwable e) { - this.logger.error("{}.registry() failed: {}", catalogClass.getSimpleName(), e.getMessage()); - if (this.verbose) { - this.logger.error("Exception", e); - } - continue; - } - - if (registryReturn == null) { - this.logger.error("{}.registry() returned null", catalogClass.getSimpleName()); - continue; - } - - if (registryReturn != registryType.get()) { - this.logger.error("{}.registry() returned a different registry than the one specified in RegistryTypes", catalogClass.getSimpleName()); - continue; - } - - for (Field catalogField : catalogClass.getDeclaredFields()) { - final Object catalogObj; - try { - catalogObj = catalogField.get(null); - } catch (final Throwable e) { - this.logger.error("Failed to get field {}: {}", catalogField.getName(), e.getMessage()); - if (this.verbose) { - this.logger.error("Exception", e); - } - continue; - } - - if (catalogObj instanceof DefaultedRegistryReference reference) { - if (reference.find().isEmpty()) { - this.logger.error("{}.{}.find() is empty", catalogClass.getSimpleName(), catalogField.getName()); - } - } - } - - } else { - this.logger.error("{} is not a DefaultedRegistryType", field.getName()); - } - } - return CommandResult.success(); - }) - .build(), - "checkregistries"); - } -} diff --git a/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java b/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java new file mode 100644 index 00000000000..939cd396b8c --- /dev/null +++ b/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java @@ -0,0 +1,373 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.test.validation; + +import com.google.inject.Inject; +import net.kyori.adventure.text.Component; +import org.apache.logging.log4j.Logger; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.registry.DefaultedRegistryReference; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.util.annotation.CatalogedBy; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; +import org.spongepowered.test.LoadableModule; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Plugin("validationtest") +public final class ValidationTest implements LoadableModule { + + private final PluginContainer plugin; + private final Logger logger; + private boolean verbose; + + @Inject + public ValidationTest(final PluginContainer plugin, final Logger logger) { + this.plugin = plugin; + this.logger = logger; + } + + @Override + public void enable(final CommandContext ctx) { + } + + @Listener + private void onRegisterSpongeCommand(final RegisterCommandEvent event) { + event.register( + this.plugin, + Command.builder() + .executor(context -> { + this.verbose = !this.verbose; + context.sendMessage(Component.text("Verbose flag set to " + this.verbose)); + return CommandResult.success(); + }) + .build(), + "toggleverbose"); + event.register( + this.plugin, + Command.builder() + .executor(context -> { + for (final Field field : RegistryTypes.class.getDeclaredFields()) { + final Object registryField; + try { + registryField = field.get(null); + } catch (final IllegalAccessException e) { + this.logger.error("Failed to get field {}: {}", field.getName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (registryField instanceof DefaultedRegistryType registryType) { + if (registryType.find().isEmpty()) { + this.logger.error("Registry {} is empty", registryType.location()); + continue; + } + + final var typeArg = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + final Class catalogEntryClass; + switch (typeArg) { + case final ParameterizedType parameterizedTypeArg -> + catalogEntryClass = (Class) parameterizedTypeArg.getRawType(); + case final Class clazz -> catalogEntryClass = clazz; + case null, default -> { + this.logger.error("Unhandled catalog entry arg type: {}", typeArg); + continue; + } + } + + final var catalogedByAnnotation = catalogEntryClass.getDeclaredAnnotation(CatalogedBy.class); + + if (catalogedByAnnotation == null) { + this.logger.error("Class {} in registry {} is not annotated with CatalogedBy", catalogEntryClass.getSimpleName(), registryType.location()); + continue; + } + + final var catalogClass = catalogedByAnnotation.value()[0]; + if (!Modifier.isFinal(catalogClass.getModifiers())) { + this.logger.error("{} is not final", catalogClass.getSimpleName()); + } + + if (Arrays.stream(catalogClass.getDeclaredConstructors()).anyMatch(ctor -> !Modifier.isPrivate(ctor.getModifiers()))) { + this.logger.error("{} has non-private constructors", catalogClass.getSimpleName()); + } + + final Method registryMethod; + try { + registryMethod = catalogClass.getDeclaredMethod("registry"); + } catch (final NoSuchMethodException e) { + this.logger.error("{}.registry() does not exist", catalogClass.getSimpleName()); + continue; + } + + final Object registryReturn; + try { + registryReturn = registryMethod.invoke(null); + } catch (final Throwable e) { + this.logger.error("{}.registry() failed: {}", catalogClass.getSimpleName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (registryReturn == null) { + this.logger.error("{}.registry() returned null", catalogClass.getSimpleName()); + continue; + } + + if (registryReturn != registryType.get()) { + this.logger.error("{}.registry() returned a different registry than the one specified in RegistryTypes", catalogClass.getSimpleName()); + continue; + } + + for (Field catalogField : catalogClass.getDeclaredFields()) { + final Object catalogObj; + try { + catalogObj = catalogField.get(null); + } catch (final Throwable e) { + this.logger.error("Failed to get field {}: {}", catalogField.getName(), e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + continue; + } + + if (catalogObj instanceof DefaultedRegistryReference reference) { + if (reference.find().isEmpty()) { + this.logger.error("{}.{}.find() is empty", catalogClass.getSimpleName(), catalogField.getName()); + } + } + } + + } else { + this.logger.error("{} is not a DefaultedRegistryType", field.getName()); + } + } + return CommandResult.success(); + }) + .build(), + "checkregistries"); + event.register( + this.plugin, + Command.builder() + .executor(context -> { + final Class entityTypeClass; + try { + entityTypeClass = Class.forName("net.minecraft.world.entity.EntityType"); + } catch (final ClassNotFoundException e) { + this.logger.error("Failed to get EntityType class: {}", e.getMessage()); + if (this.verbose) { + this.logger.error("Exception", e); + } + return CommandResult.success(); + } + for (final Field field : entityTypeClass.getDeclaredFields()) { + if (!field.getType().getSimpleName().equals("EntityType")) { + if (this.verbose) { + this.logger.info("Skipping field {} of type {}", field.getName(), field.getType().getSimpleName()); + } + continue; + } + + if (!(field.getGenericType() instanceof ParameterizedType)) { + this.logger.error("Non ParameterizedType EntityType field: {}", field.getName()); + continue; + } + + final var typeArg = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + + if (!(typeArg instanceof Class)) { + this.logger.error("Non ParameterizedType EntityType field {}: {}", field.getName(), typeArg.getClass().getName()); + continue; + } + + final var mc = "minecraft"; + final var sponge = "sponge"; + + final var unknownClasses = Set.of( + "net.minecraft.world.entity.npc.InventoryCarrier", + "net.minecraft.world.entity.npc.VillagerDataHolder", + "net.minecraft.world.entity.Attackable", + "net.minecraft.world.entity.HasCustomInventoryScreen,", + "net.minecraft.world.entity.EquipmentUser", + "net.minecraft.world.entity.PlayerRideable", + "net.minecraft.world.entity.PlayerRideableJumping", + "net.minecraft.world.entity.Saddleable", + "net.minecraft.world.entity.Targeting", + "net.minecraft.world.entity.TraceableEntity", + "net.minecraft.world.entity.VariantHolder", + "net.minecraft.world.level.entity.EntityAccess", + "net.minecraft.world.scores.ScoreHolder", + "net.minecraft.world.Clearable", + "net.minecraft.world.ContainerListener", + "net.minecraft.world.Nameable", + "org.spongepowered.api.entity.attribute.AttributeHolder", + "org.spongepowered.api.entity.living.Humanoid", + "org.spongepowered.api.projectile.source.EntityProjectileSource", + "org.spongepowered.api.projectile.source.ProjectileSource", + "org.spongepowered.api.scoreboard.TeamMember", + "org.spongepowered.api.util.locale.LocaleSource", + "org.spongepowered.api.util.Identifiable", + "org.spongepowered.api.util.RandomProvider", + "org.spongepowered.api.world.Locatable" + ); + + final var interfaces = this.interfacesAndSuperclasses((Class) typeArg) + .filter(clazz -> clazz.getPackageName().startsWith("org.spongepowered.api") || clazz.getPackageName().startsWith("net.minecraft")) + .filter(clazz -> !clazz.getPackageName().startsWith("org.spongepowered.api.data")) + .filter(clazz -> !clazz.getPackageName().startsWith("org.spongepowered.api.item.inventory")) + .filter(clazz -> !clazz.getPackageName().startsWith("net.minecraft.commands")) + .filter(clazz -> !clazz.getPackageName().startsWith("net.minecraft.network")) + .filter(clazz -> !unknownClasses.contains(clazz.getName())) + .distinct() + .collect(Collectors.groupingBy( + clazz -> { + if (clazz.getPackageName().startsWith("net.minecraft")) { + return mc; + } + if (clazz.getPackageName().startsWith("org.spongepowered")) { + return sponge; + } + return ""; + } + )); + + final var mcInterfaces = interfaces.getOrDefault(mc, Collections.emptyList()); + mcInterfaces.sort(Comparator.comparing(Class::getSimpleName)); + + final var spongeInterfaces = interfaces.getOrDefault(sponge, Collections.emptyList()); + spongeInterfaces.sort(Comparator.comparing(Class::getSimpleName)); + + final var mcToSpongeMapping = Map.ofEntries( + Map.entry("AbstractArrow", "ArrowEntity"), + Map.entry("AbstractChestedHorse", "PackHorse"), + Map.entry("AbstractFish", "Fish"), + Map.entry("AbstractGolem", "Golem"), + Map.entry("AbstractHorse", "HorseLike"), + Map.entry("AbstractHurtingProjectile", "DamagingProjectile"), + Map.entry("AbstractIllager", "Illager"), + Map.entry("AbstractMinecart", "MinecartLike"), + Map.entry("AbstractMinecartContainer", "CarrierMinecart"), + Map.entry("AbstractSchoolingFish", "SchoolingFish"), + Map.entry("AbstractSkeleton", "SkeletonLike"), + Map.entry("AbstractVillager", "Trader"), + Map.entry("AbstractWindCharge", "WindChargeLike"), + Map.entry("AgeableMob", "Ageable"), + Map.entry("BlockAttachedEntity", "Hanging"), + Map.entry("Display", "DisplayEntity"), + Map.entry("FallingBlockEntity", "FallingBlock"), + Map.entry("Fireball", "FireballEntity"), + Map.entry("FireworkRocketEntity", "FireworkRocket"), + Map.entry("FishingHook", "FishingBobber"), + Map.entry("FlyingMob", "Aerial"), + Map.entry("ItemEntity", "Item"), + Map.entry("LargeFireball", "ExplosiveFireball"), + Map.entry("LeashFenceKnotEntity", "LeashKnot"), + Map.entry("LivingEntity", "Living"), + Map.entry("MinecartChest", "ChestMinecart"), + Map.entry("MinecartCommandBlock", "CommandBlockMinecart"), + Map.entry("MinecartFurnace", "FurnaceMinecart"), + Map.entry("MinecartHopper", "HopperMinecart"), + Map.entry("MinecartSpawner", "SpawnerMinecart"), + Map.entry("MinecartTNT", "TNTMinecart"), + Map.entry("Mob", "Agent"), + Map.entry("MushroomCow", "Mooshroom"), + Map.entry("PathfinderMob", "Creature"), + Map.entry("PatrollingMonster", "Patroller"), + Map.entry("SpellcasterIllager", "Spellcaster"), + Map.entry("TamableAnimal", "TameableAnimal"), + Map.entry("ThrownEgg", "Egg"), + Map.entry("ThrownEnderpearl", "EnderPearl"), + Map.entry("ThrownExperienceBottle", "ExperienceBottle"), + Map.entry("ThrownPotion", "Potion"), + Map.entry("ThrownTrident", "Trident"), + Map.entry("WaterAnimal", "Aquatic"), + Map.entry("WitherBoss", "Wither") + ); + + final AtomicBoolean brokenMapping = new AtomicBoolean(false); + mcToSpongeMapping.forEach((key, value) -> { + if (!mcToSpongeMapping.containsKey(value) && mcInterfaces.stream().anyMatch(c -> c.getSimpleName().equalsIgnoreCase(value))) { + this.logger.error("Duplicat mapping: {}->{} ; {}->{}", key, value, value, value); + brokenMapping.set(true); + } + }); + if (brokenMapping.get()) { + continue; + } + + final var baseClass = mcToSpongeMapping.getOrDefault(((Class) typeArg).getSimpleName(), ((Class) typeArg).getSimpleName()); + if (!spongeInterfaces.removeIf(spongeInterface -> spongeInterface.getSimpleName().equalsIgnoreCase(baseClass))) { + this.logger.error("{} does not implement matching Sponge interface", ((Class) typeArg).getName()); + continue; + } + + mcInterfaces.removeIf(mcInterface -> + spongeInterfaces.removeIf(spongeClass -> + spongeClass.getSimpleName().equals(mcToSpongeMapping.getOrDefault(mcInterface.getSimpleName(), mcInterface.getSimpleName())) + ) + ); + + if (this.verbose) { + if (!mcInterfaces.isEmpty()) { + this.logger.info("extra unmapped mc interfaces for {}: {}", ((Class) typeArg).getSimpleName(), mcInterfaces); + } + if (!spongeInterfaces.isEmpty()) { + this.logger.info("extra unmapped sponge interfaces for {}: {}", ((Class) typeArg).getSimpleName(), spongeInterfaces); + } + } + } + return CommandResult.success(); + }) + .build(), + "checkentities"); + } + + private Stream> interfacesAndSuperclasses(final Class clazz) { + return Stream.concat( + Stream.of(clazz.getInterfaces()).flatMap(interfaceType -> Stream.concat(Stream.of(interfaceType), this.interfacesAndSuperclasses(interfaceType))), + Stream.ofNullable(clazz.getSuperclass()).flatMap(superclass -> Stream.concat(Stream.of(superclass), this.interfacesAndSuperclasses(superclass))) + ); + } +} diff --git a/testplugins/src/main/resources/META-INF/sponge_plugins.json b/testplugins/src/main/resources/META-INF/sponge_plugins.json index 3e884bea207..011a37a4d89 100644 --- a/testplugins/src/main/resources/META-INF/sponge_plugins.json +++ b/testplugins/src/main/resources/META-INF/sponge_plugins.json @@ -116,10 +116,10 @@ "description": "Testing recipes" }, { - "id": "registrytest", - "name": "Registry Test", - "entrypoint": "org.spongepowered.test.registry.RegistryTest", - "description": "Testing registries" + "id": "validationtest", + "name": "Validation Test", + "entrypoint": "org.spongepowered.test.validation.ValidationTest", + "description": "Validate API classes" }, { "id": "particletest", From ec84c3183bce3f36d400dea144f87f13fb2fe76b Mon Sep 17 00:00:00 2001 From: Pandier <62116820+pandier@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:07:11 +0200 Subject: [PATCH 113/226] Fix: Resources incorrectly listed for plugin packs (#4069) * fix: Resources incorrectly listed for plugin packs * fix: Add invalid plugin resource path logging * refactor: Remove unused imports --- .../server/packs/PluginPackResources.java | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java index 7053ed5dad6..8558de7459b 100644 --- a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java +++ b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java @@ -24,7 +24,7 @@ */ package org.spongepowered.vanilla.server.packs; -import net.minecraft.ResourceLocationException; +import com.mojang.logging.LogUtils; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.AbstractPackResources; @@ -34,6 +34,7 @@ import net.minecraft.server.packs.metadata.pack.PackMetadataSection; import net.minecraft.server.packs.resources.IoSupplier; import org.checkerframework.checker.nullness.qual.Nullable; +import org.slf4j.Logger; import org.spongepowered.common.SpongeCommon; import org.spongepowered.plugin.PluginContainer; @@ -44,16 +45,13 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; -import java.util.Locale; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; +import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; public final class PluginPackResources extends AbstractPackResources { + private static final Logger LOGGER = LogUtils.getLogger(); private final PluginContainer container; private final PackMetadataSection metadata; @@ -91,34 +89,27 @@ public IoSupplier getResource(final PackType type, final ResourceLo public void listResources(final PackType type, final String namespace, final String path, final ResourceOutput out) { try { final Path root = this.typeRoot(type); - final Path namespaceDir = root.resolve(namespace).toAbsolutePath(); - try (final Stream stream = Files.walk(namespaceDir)) { + final Path namespaceDir = root.resolve(namespace); + final Path resourcesDir = namespaceDir.resolve(path); + try (final Stream stream = Files.walk(resourcesDir)) { stream.filter(Files::isRegularFile) - .filter(s -> !s.getFileName().toString().endsWith(".mcmeta")) + .filter(filePath -> !filePath.getFileName().toString().endsWith(".mcmeta")) .map(namespaceDir::relativize) - .map(Object::toString) -// TODO filter needed? .filter(p -> filterValidPath(namespace, p, fileNameValidator)) - .map(s -> ResourceLocation.fromNamespaceAndPath(namespace, s)) - .forEach(loc -> { - out.accept(loc, this.getResource(type, loc)); - }); + .map(filePath -> convertResourcePath(namespace, filePath)) + .filter(Objects::nonNull) + .forEach(loc -> out.accept(loc, this.getResource(type, loc))); } } catch (final IOException ignored) { } } - private boolean filterValidPath(final String namespace, final String path, final Predicate fileNameValidator) { - try { - final ResourceLocation loc = ResourceLocation.tryBuild(namespace, path); - if (loc == null) { - // LOGGER.warn("Invalid path in datapack: {}:{}, ignoring", $$1, $$7); - return false; - } - return fileNameValidator.test(loc); - } catch (ResourceLocationException e) { - // LOGGER.error(var13.getMessage()); - return false; - } + @Nullable + private ResourceLocation convertResourcePath(final String namespace, final Path resourcePath) { + final String path = resourcePath.toString(); + final ResourceLocation location = ResourceLocation.tryBuild(namespace, path); + if (location == null) + LOGGER.warn("Invalid path in plugin pack: {}:{}, ignoring", namespace, path); + return location; } @Nullable From fd3d111cc4765a1e9a4e9eafa0cd1565d8a6027c Mon Sep 17 00:00:00 2001 From: Jesse McKee Date: Fri, 31 May 2024 23:52:48 +0200 Subject: [PATCH 114/226] Implement Keys.TELEPORT_DURATION Closes #4020 --- SpongeAPI | 2 +- .../accessor/world/entity/DisplayAccessor.java | 3 +++ .../data/provider/entity/DisplayEntityData.java | 11 +++++++++++ .../advancements/DisplayInfoMixin_API.java | 1 + .../minecraft/world/entity/DisplayMixin_API.java | 1 - .../test/entity/DisplayEntityTest.java | 16 ++++++++++++++-- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 1f3b8648d92..5f1bbbae559 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 1f3b8648d92fe27dd029fe2373fe61b185fdf5e0 +Subproject commit 5f1bbbae559c50a6fd37a80bc06e314f5b3f994c diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/DisplayAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/DisplayAccessor.java index a50bf5207e4..ab5fa36bd4d 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/DisplayAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/entity/DisplayAccessor.java @@ -57,6 +57,9 @@ public interface DisplayAccessor { @Invoker("getTransformationInterpolationDelay") int invoker$getInterpolationDelay(); + @Invoker("setPosRotInterpolationDuration") void invoker$setPosRotInterpolationDuration(int $$0); + + @Invoker("getPosRotInterpolationDuration") int invoker$getPosRotInterpolationDuration(); @Invoker("setShadowRadius") void invoker$setShadowRadius(float $$0); diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/DisplayEntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/DisplayEntityData.java index 483e1911afc..dd4bdfddca8 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/DisplayEntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/DisplayEntityData.java @@ -34,6 +34,7 @@ import org.spongepowered.api.block.BlockState; import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.display.BillboardType; +import org.spongepowered.api.entity.display.DisplayEntity; import org.spongepowered.api.entity.display.ItemDisplayType; import org.spongepowered.api.util.Color; import org.spongepowered.api.util.Ticks; @@ -91,6 +92,15 @@ public static void register(final DataProviderRegistrator registrator) { h.invoker$setInterpolationDelay(SpongeTicks.toSaturatedIntOrInfinite(v)); return true; }) + .create(Keys.TELEPORT_DURATION) + .get(h -> Ticks.of(h.invoker$getPosRotInterpolationDuration())) + .setAnd((h ,v) -> { + if (v.isInfinite()) { + return false; + } + h.invoker$setPosRotInterpolationDuration(SpongeTicks.toSaturatedIntOrInfinite(v)); + return true; + }) .create(Keys.SHADOW_RADIUS) .get(h -> (double) h.invoker$getShadowRadius()) .set((h ,v) -> h.invoker$setShadowRadius(v.floatValue())) @@ -137,6 +147,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> DisplayEntityData.colorFromInt(h.invoker$getBackgroundColor())) .set((h, v) -> h.invoker$setBackgroundColor(DisplayEntityData.colorToInt(v))) ; + registrator.spongeDataStore(Keys.TELEPORT_DURATION.key(), DisplayEntity.class, Keys.TELEPORT_DURATION); } // @formatter:on diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/DisplayInfoMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/DisplayInfoMixin_API.java index b681092b3a8..110ea019c19 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/DisplayInfoMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/advancements/DisplayInfoMixin_API.java @@ -116,4 +116,5 @@ public boolean doesAnnounceToChat() { public boolean displayInfo$isHidden() { return this.shadow$isHidden(); } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/DisplayMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/DisplayMixin_API.java index 4cb618d918f..7457db52f8b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/DisplayMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/DisplayMixin_API.java @@ -31,5 +31,4 @@ @Mixin(Display.class) public abstract class DisplayMixin_API extends EntityMixin_API implements DisplayEntity { - } diff --git a/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java b/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java index 97b2c5b974f..3d9c74a991a 100644 --- a/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java @@ -47,6 +47,7 @@ import org.spongepowered.api.util.Color; import org.spongepowered.api.util.Ticks; import org.spongepowered.api.util.Transform; +import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.math.imaginary.Quaterniond; import org.spongepowered.math.vector.Vector3d; @@ -81,6 +82,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { final int col4 = 2; final int col5 = 3; final int col6 = 5; + final int col7 = 6; var textDisplay = spawnEntity(player.world(), EntityTypes.TEXT_DISPLAY, centerPos, forwardDir, -4, -1); textDisplay.offer(Keys.DISPLAY_NAME, Component.text("DisplayEntityTest").color(NamedTextColor.GOLD)); textDisplay.offer(Keys.SEE_THROUGH_BLOCKS, true); @@ -224,8 +226,18 @@ public void onRegisterCommand(final RegisterCommandEvent event) { blockDisplay.offer(Keys.INTERPOLATION_DURATION, Ticks.of(20)); blockDisplay.offer(Keys.INTERPOLATION_DELAY, Ticks.of(20)); - textDisplay = createEntity(player.world(), EntityTypes.TEXT_DISPLAY, centerPos, forwardDir, col6, 0); - textDisplay.offer(Keys.DISPLAY_NAME, Component.text("Look at this interpolation").color(NamedTextColor.RED)); + blockDisplay = createEntity(player.world(), EntityTypes.BLOCK_DISPLAY, centerPos, forwardDir, col6, 0); + blockDisplay.offer(Keys.BLOCK_STATE, BlockTypes.OBSIDIAN.get().defaultState()); + blockDisplay.offer(Keys.TRANSFORM, Transform.of(blockCenterOffset)); // set initial value before spawning + blockDisplay.offer(Keys.SHADOW_RADIUS, 2d); // set initial value before spawning + blockDisplay.offer(Keys.SHADOW_STRENGTH, 5d); // set initial value before spawning + player.world().spawnEntity(blockDisplay); + blockDisplay.offer(Keys.TELEPORT_DURATION, Ticks.of(20)); + blockDisplay.setLocation(((ServerLocation) blockDisplay.location().add(0.0, 4.0, 0.0))); + + + textDisplay = createEntity(player.world(), EntityTypes.TEXT_DISPLAY, centerPos, forwardDir, col7, 0); + textDisplay.offer(Keys.DISPLAY_NAME, Component.text("Look at these interpolations").color(NamedTextColor.RED)); textDisplay.offer(Keys.LINE_WIDTH, 100); textDisplay.offer(Keys.SEE_THROUGH_BLOCKS, true); textDisplay.offer(Keys.TEXT_BACKGROUND_COLOR, Color.BLACK); // set initial value before spawning From 83ce551359b29f20f5ebc100e06ccc6230eb25a4 Mon Sep 17 00:00:00 2001 From: ImMorpheus Date: Fri, 28 Jun 2024 21:24:01 +0200 Subject: [PATCH 115/226] Add missing AbstractPiglinMixin_API --- .../monster/AbstractPiglinMixin_API.java | 33 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/AbstractPiglinMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/AbstractPiglinMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/AbstractPiglinMixin_API.java new file mode 100644 index 00000000000..a06f5e83730 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/AbstractPiglinMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; + +import net.minecraft.world.entity.monster.piglin.AbstractPiglin; +import org.spongepowered.api.entity.living.monster.piglin.PiglinLike; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(AbstractPiglin.class) +public abstract class AbstractPiglinMixin_API implements PiglinLike { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 1103908b900..7056ce6f527 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -206,6 +206,7 @@ "minecraft.world.entity.item.ItemEntityMixin_API", "minecraft.world.entity.item.PrimedTntMixin_API", "minecraft.world.entity.monster.AbstractIllagerMixin_API", + "minecraft.world.entity.monster.AbstractPiglinMixin_API", "minecraft.world.entity.monster.AbstractSkeletonMixin_API", "minecraft.world.entity.monster.BlazeMixin_API", "minecraft.world.entity.monster.BoggedMixin_API", From 4e0a38bdff4876fd89259cef66be866fded0eba6 Mon Sep 17 00:00:00 2001 From: Lignium Date: Sat, 21 Jan 2023 18:17:46 +0200 Subject: [PATCH 116/226] Implement ServerWorld#saveAndFlush Closes #3688 --- SpongeAPI | 2 +- .../server/level/ServerLevelMixin_API.java | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 5f1bbbae559..ab886270581 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 5f1bbbae559c50a6fd37a80bc06e314f5b3f994c +Subproject commit ab8862705811110c382fdac61c29d170fddb19b6 diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java index 5d13d9cea3f..e0f27723f4a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java @@ -207,14 +207,23 @@ public Path directory() { return ((ServerLevelBridge) this).bridge$getLevelSave().getLevelPath(LevelResource.ROOT); } - @Override - public boolean save() throws IOException { + private boolean impl$save(final boolean flush) { final SerializationBehavior behavior = ((PrimaryLevelDataBridge) this.serverLevelData).bridge$serializationBehavior().orElse(SerializationBehavior.AUTOMATIC); ((ServerLevelBridge) this).bridge$setManualSave(true); - this.shadow$save(null, false, false); + this.shadow$save(null, flush, false); return !behavior.equals(SerializationBehavior.NONE); } + @Override + public boolean save() { + return this.impl$save(false); + } + + @Override + public boolean saveAndFlush() { + return this.impl$save(true); + } + @Override public boolean unloadChunk(final WorldChunk chunk) { this.shadow$unload((LevelChunk) Objects.requireNonNull(chunk, "chunk")); From 013ae888db25491c91855eeab7834f07e042d860 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 29 Jun 2024 19:38:36 +0000 Subject: [PATCH 117/226] Add missing api mixins and update keys references (#4074) * Add missing api mixins and update keys references * Bump SpongeAPI --- SpongeAPI | 2 +- .../provider/entity/AbstractHorseData.java | 2 +- .../data/provider/entity/TameableData.java | 2 +- .../world/entity/OwnableEntityMixin_API.java | 33 +++++++++++++++++++ .../world/entity/SaddleableMixin_API.java | 32 ++++++++++++++++++ .../world/entity/TamableAnimalMixin_API.java | 2 +- .../animal/horse/AbstractHorseMixin_API.java | 2 +- src/mixins/resources/mixins.sponge.api.json | 2 ++ .../org/spongepowered/test/data/DataTest.java | 8 ++--- 9 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OwnableEntityMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/SaddleableMixin_API.java diff --git a/SpongeAPI b/SpongeAPI index ab886270581..c24fd3a916d 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit ab8862705811110c382fdac61c29d170fddb19b6 +Subproject commit c24fd3a916d368d565cab5f5a8456bc177b46fea diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractHorseData.java b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractHorseData.java index d524002f175..06ba09e4c28 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractHorseData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractHorseData.java @@ -41,7 +41,7 @@ public static void register(final DataProviderRegistrator registrator) { .create(Keys.IS_TAMED) .get(AbstractHorse::isTamed) .set(AbstractHorse::setTamed) - .create(Keys.TAMER) + .create(Keys.OWNER) .get(AbstractHorse::getOwnerUUID) .set((h, v) -> { h.setOwnerUUID(v); diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/TameableData.java b/src/main/java/org/spongepowered/common/data/provider/entity/TameableData.java index fd3489e3e2f..c7f3ff898d0 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/TameableData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/TameableData.java @@ -43,7 +43,7 @@ public static void register(final DataProviderRegistrator registrator) { .create(Keys.IS_TAMED) .get(TamableAnimal::isTame) .set((h, v) -> h.setTame(v, true)) - .create(Keys.TAMER) + .create(Keys.OWNER) .get(TamableAnimal::getOwnerUUID) .set((h, v) -> { h.setOwnerUUID(v); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OwnableEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OwnableEntityMixin_API.java new file mode 100644 index 00000000000..91f636b02f8 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/OwnableEntityMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import net.minecraft.world.entity.OwnableEntity; +import org.spongepowered.api.entity.Ownable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(OwnableEntity.class) +public interface OwnableEntityMixin_API extends Ownable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/SaddleableMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/SaddleableMixin_API.java new file mode 100644 index 00000000000..76883707f1e --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/SaddleableMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.Saddleable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.Saddleable.class) +public interface SaddleableMixin_API extends Saddleable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TamableAnimalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TamableAnimalMixin_API.java index 3be92fe8419..7da4e143f42 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TamableAnimalMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TamableAnimalMixin_API.java @@ -43,7 +43,7 @@ public abstract class TamableAnimalMixin_API extends AnimalMixin_API implements values.add(this.requireValue(Keys.IS_SITTING).asImmutable()); values.add(this.requireValue(Keys.IS_TAMED).asImmutable()); - this.getValue(Keys.TAMER).map(Value::asImmutable).ifPresent(values::add); + this.getValue(Keys.OWNER).map(Value::asImmutable).ifPresent(values::add); return values; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/horse/AbstractHorseMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/horse/AbstractHorseMixin_API.java index f32e2f63cb1..40361de0a52 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/horse/AbstractHorseMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/horse/AbstractHorseMixin_API.java @@ -43,7 +43,7 @@ public abstract class AbstractHorseMixin_API extends AnimalMixin_API implements values.add(this.requireValue(Keys.IS_SADDLED).asImmutable()); values.add(this.requireValue(Keys.IS_TAMED).asImmutable()); - this.getValue(Keys.TAMER).map(Value::asImmutable).ifPresent(values::add); + this.getValue(Keys.OWNER).map(Value::asImmutable).ifPresent(values::add); return values; } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 7056ce6f527..5b86372416f 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -110,8 +110,10 @@ "minecraft.world.entity.MobCategoryMixin_API", "minecraft.world.entity.MobMixin_API", "minecraft.world.entity.OminousItemSpawnerMixin_API", + "minecraft.world.entity.OwnableEntityMixin_API", "minecraft.world.entity.PathfinderMobMixin_API", "minecraft.world.entity.PortalProcessorMixin_API", + "minecraft.world.entity.SaddleableMixin_API", "minecraft.world.entity.TamableAnimalMixin_API", "minecraft.world.entity.ai.attributes.AttributeInstanceMixin_API", "minecraft.world.entity.ai.attributes.AttributeMixin_API", diff --git a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java index 5d472934aa0..efd385b1532 100644 --- a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java @@ -1257,10 +1257,10 @@ public void testData(final ServerPlayer player) { this.checkOfferData(minecartEntity, Keys.VELOCITY, Vector3d.FORWARD); this.checkOfferData(minecartEntity, Keys.SWIFTNESS, 2.0); - this.checkOfferData(horse, Keys.TAMER, player.uniqueId()); - this.checkOfferData(wolf, Keys.TAMER, player.uniqueId()); - this.checkOfferData(parrot, Keys.TAMER, player.uniqueId()); - this.checkOfferData(parrot, Keys.TAMER, null); + this.checkOfferData(horse, Keys.OWNER, player.uniqueId()); + this.checkOfferData(wolf, Keys.OWNER, player.uniqueId()); + this.checkOfferData(parrot, Keys.OWNER, player.uniqueId()); + this.checkOfferData(parrot, Keys.OWNER, null); this.checkOfferData(zombifiedPiglin, Keys.TARGET_ENTITY, player); this.checkOfferData(shulkerBullet, Keys.TARGET_ENTITY, sheep); From f597bfa18a1a740c913e2e03807105b0615f9508 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 30 Jun 2024 12:57:43 +0200 Subject: [PATCH 118/226] actually prevent DestructEntityEventDeath --- .../common/mixin/core/world/entity/LivingEntityMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java index 246dcc0946b..655aacdd478 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin.java @@ -118,6 +118,7 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt @Shadow public abstract float shadow$getMaxHealth(); @Shadow public abstract AttributeMap shadow$getAttributes(); @Shadow public abstract void shadow$clearSleepingPos(); + @Shadow public abstract void shadow$setHealth(final float $$0); // @formatter:on @@ -154,8 +155,8 @@ public abstract class LivingEntityMixin extends EntityMixin implements LivingEnt // ignore because some moron is not resetting the entity. this.impl$deathEventsPosted++; if (SpongeCommonEventFactory.callDestructEntityEventDeath((LivingEntity) (Object) this, cause).isCancelled()) { - // Since the forge event is cancellable ci.cancel(); + this.shadow$setHealth(this.shadow$getMaxHealth()); } } } else { From 00b625514a7967e813ab659631f8449fbe8c55fc Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 30 Jun 2024 12:59:44 +0200 Subject: [PATCH 119/226] fix HarvestEntityEvent for ArmorStand also fix cancel causing a LOT of spawns --- .../EntityPerformingDropsTransaction.java | 11 +++---- .../entity/decoration/ArmorStandMixin.java | 29 +++++++++++++++++++ .../world/entity/EntityMixin_Tracker.java | 6 +--- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java index af22d75f300..312c191f13a 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java @@ -143,11 +143,12 @@ public Optional generateEvent( @Override public void restore(PhaseContext context, HarvestEntityEvent event) { - @Nullable final Entity spawn = this.destroyingEntity.getType() - .spawn(this.worldSupplier.get(), null, this.destroyingEntity.blockPosition(), MobSpawnType.COMMAND, false, false); - if (spawn != null) { - spawn.load(this.entityTag); - } + // TODO this is actually respawning the entity A LOT which is then dying immediately again +// @Nullable final Entity spawn = this.destroyingEntity.getType() +// .spawn(this.worldSupplier.get(), null, this.destroyingEntity.blockPosition(), MobSpawnType.COMMAND, false, false); +// if (spawn != null) { +// spawn.load(this.entityTag); +// } } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java index 494f43dd566..9e419a6e1e2 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/decoration/ArmorStandMixin.java @@ -28,6 +28,7 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.Entity.RemovalReason; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.level.gameevent.GameEvent; import org.objectweb.asm.Opcodes; @@ -39,6 +40,11 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.common.bridge.world.level.LevelBridge; +import org.spongepowered.common.event.ShouldFire; +import org.spongepowered.common.event.SpongeCommonEventFactory; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.mixin.core.world.entity.LivingEntityMixin; import org.spongepowered.common.util.DamageEventUtil; @@ -47,6 +53,8 @@ public abstract class ArmorStandMixin extends LivingEntityMixin { // @formatter:off @Shadow protected abstract void shadow$causeDamage(ServerLevel level, DamageSource damageSource, float damage); // damageArmorStand + @Shadow protected abstract void shadow$brokenByPlayer(final ServerLevel $$0, final DamageSource $$1); + // @formatter:on /** @@ -123,6 +131,27 @@ public abstract class ArmorStandMixin extends LivingEntityMixin { } } + @Inject(method = "hurt", cancellable = true, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/ArmorStand;brokenByPlayer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;)V")) + private void impl$beforeBrokenByPlayer(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + if (ShouldFire.DESTRUCT_ENTITY_EVENT && !((LevelBridge) this.shadow$level()).bridge$isFake()) { + final var event = SpongeCommonEventFactory.callDestructEntityEventDeath((ArmorStand) (Object) this, null); + if (event.isCancelled()) { + cir.setReturnValue(false); + } + // TODO event.keepInventory() actually prevent inventory drops + } + } + + @Redirect(method = "hurt", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/decoration/ArmorStand;brokenByPlayer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;)V")) + public void impl$onBrokenByPlayer(final ArmorStand instance, final ServerLevel $$0, final DamageSource $$1) + { + try (final EffectTransactor ignored = PhaseTracker.SERVER.getPhaseContext().getTransactor().ensureEntityDropTransactionEffect((LivingEntity) (Object) this)) { + this.shadow$brokenByPlayer($$0, $$1); + } + } + /** * {@link ArmorStand#lastHit} was recently */ diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/EntityMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/EntityMixin_Tracker.java index 5a1cf152eb9..5746dda6774 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/EntityMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/entity/EntityMixin_Tracker.java @@ -30,7 +30,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -55,7 +54,6 @@ import org.spongepowered.common.bridge.world.entity.TrackableEntityBridge; import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.event.ShouldFire; -import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; @@ -138,7 +136,7 @@ public abstract class EntityMixin_Tracker implements DelegatingConfigTrackableBr final EntityTickContext context) { } - @Inject(method = "setRemoved", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;stopRiding()V")) + @Inject(method = "setRemoved", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;stopRiding()V")) private void impl$createDestructionEventOnDeath(final CallbackInfo ci) { if (ShouldFire.DESTRUCT_ENTITY_EVENT && !((LevelBridge) this.shadow$level()).bridge$isFake() && this.levelCallback != EntityInLevelCallback.NULL) { @@ -155,8 +153,6 @@ public abstract class EntityMixin_Tracker implements DelegatingConfigTrackableBr (org.spongepowered.api.entity.Entity) this, false )); - } else if ((Entity) (Object) this instanceof ArmorStand) { - SpongeCommonEventFactory.callDestructEntityEventDeath((ArmorStand) (Object) this, null); } } } From ca79b30f69e075cb1510d35225388866ca26441c Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 30 Jun 2024 15:49:49 +0200 Subject: [PATCH 120/226] fix attack mixin final damage --- .../entity/LivingEntityMixin_Attack_impl.java | 23 ++++++++++++++---- .../player/PlayerMixin_Attack_Impl.java | 24 ++++++++----------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java index a3d7ef6c3b7..71549f0ca40 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -32,6 +32,7 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; @@ -40,6 +41,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -92,6 +94,7 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin protected float attackImpl$actuallyHurtFinalDamage; protected boolean attackImpl$actuallyHurtCancelled; protected float attackImpl$actuallyHurtBlockedDamage; + protected boolean attackImpl$wasInInvulnerableTime; /** * Forge onLivingAttack Hook @@ -161,6 +164,7 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin /** * Capture the old values to reset if we end up cancelling or blocking. + * Also reset {@link #attackImpl$wasInInvulnerableTime} */ @Inject(method = "hurt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;walkAnimation:Lnet/minecraft/world/entity/WalkAnimationState;")) @@ -169,15 +173,18 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin this.attackImpl$lastHurt = this.lastHurt; this.attackImpl$InvulnerableTime = this.invulnerableTime; this.attackImpl$actuallyHurtCancelled = false; + + this.attackImpl$wasInInvulnerableTime = false; } /** - * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable. + * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable and remember that we did */ @Redirect(method = "hurt", at = @At(value = "FIELD", ordinal = 0, target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) private float attackImpl$afterActuallyHurt(final LivingEntity instance) { + this.attackImpl$wasInInvulnerableTime = true; return 0; } @@ -284,8 +291,13 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin if (instance.isInvulnerableTo(damageSource)) { return true; } + var realOriginalDamage = originalDamage; + if (this.attackImpl$wasInInvulnerableTime) { + realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime + } + // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); // TODO check for direct call? this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); return false; @@ -379,9 +391,12 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin /** * Set final damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + * !!NOTE that var9 is actually decompiled incorrectly!! + * It is NOT the final damage value instead the method parameter is mutated */ - @ModifyVariable(method = "actuallyHurt", ordinal = 1, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0, shift = At.Shift.AFTER)) + @ModifyVariable(method = "actuallyHurt", ordinal = 0, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", + ordinal = 0, shift = At.Shift.AFTER), argsOnly = true) public float attackImpl$setFinalDamage(final float value) { if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { return 0; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index 0a7a07f5927..d0139e7fa85 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -380,31 +380,27 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i if (instance.isInvulnerableTo(damageSource)) { return true; } + + var realOriginalDamage = originalDamage; + if (this.attackImpl$wasInInvulnerableTime) { + realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime + } + // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); // TODO check for direct call? this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); return false; } /** - * Set original damage after calling {@link Player#setAbsorptionAmount} in which we called the event + * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event + * !!NOTE that var7 is actually decompiled incorrectly!! + * It is NOT the final damage value instead the method parameter is mutated */ @ModifyVariable(method = "actuallyHurt", ordinal = 0, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", shift = At.Shift.AFTER), argsOnly = true) - public float attackImpl$setOriginalDamage(final float value) { - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - return 0; - } - return value; - } - - /** - * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event - */ - @ModifyVariable(method = "actuallyHurt", ordinal = 1, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", shift = At.Shift.AFTER)) public float attackImpl$setFinalDamage(final float value) { if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { return 0; From d2eb9d2491d3af1dc2bf5a89618934e15a46eb4a Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 30 Jun 2024 15:44:06 +0000 Subject: [PATCH 121/226] Bump SpongeAPI for entity changes (#4075) * Update Strider reference * Update Allay reference * Update Hoglin reference * Update Aerial and Slime reference * Update reference for API changes * Update Ranger reference * Bump SpongeAPI * run spotlessApply --- SpongeAPI | 2 +- .../goal/builtin/creature/SpongeAttackLivingGoalBuilder.java | 4 ++-- .../goal/builtin/creature/SpongeAvoidLivingGoalBuilder.java | 4 ++-- .../goal/builtin/creature/SpongeRandomWalkingGoalBuilder.java | 4 ++-- .../creature/SpongeRangedAttackAgainstAgentGoalBuilder.java | 4 ++-- .../target/SpongeFindNearestAttackableTargetGoalBuilder.java | 4 ++-- .../transaction/world/EntityPerformingDropsTransaction.java | 1 - .../mixin/api/minecraft/world/entity/FlyingMobMixin_API.java | 2 +- .../api/minecraft/world/entity/PathfinderMobMixin_API.java | 4 ++-- .../world/entity/ai/goal/AvoidEntityGoalMixin_API.java | 4 ++-- .../world/entity/ai/goal/RandomStrollGoalMixin_API.java | 4 ++-- .../minecraft/world/entity/animal/allay/AllayMixin_API.java | 2 +- .../api/minecraft/world/entity/monster/HoglinMixin_API.java | 2 +- .../minecraft/world/entity/monster/MagmaCubeMixin_API.java | 2 +- .../world/entity/monster/RangedAttackMobMixin_API.java | 2 +- .../api/minecraft/world/entity/monster/SlimeMixin_API.java | 2 +- .../api/minecraft/world/entity/monster/StriderMixin_API.java | 2 +- .../java/org/spongepowered/common/util/TypeTokenUtilTest.java | 2 +- .../core/world/entity/LivingEntityMixin_Attack_impl.java | 2 -- 19 files changed, 25 insertions(+), 28 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index c24fd3a916d..3a4be663d90 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit c24fd3a916d368d565cab5f5a8456bc177b46fea +Subproject commit 3a4be663d90772afa59edeb83315576ca9448022 diff --git a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAttackLivingGoalBuilder.java b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAttackLivingGoalBuilder.java index c0fa2ec4256..9b3dcef58ee 100644 --- a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAttackLivingGoalBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAttackLivingGoalBuilder.java @@ -27,7 +27,7 @@ import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; import org.spongepowered.api.entity.ai.goal.builtin.creature.AttackLivingGoal; -import org.spongepowered.api.entity.living.Creature; +import org.spongepowered.api.entity.living.PathfinderAgent; import java.util.Objects; @@ -66,7 +66,7 @@ public AttackLivingGoal.Builder reset() { } @Override - public AttackLivingGoal build(Creature owner) { + public AttackLivingGoal build(PathfinderAgent owner) { Objects.requireNonNull(owner); return (AttackLivingGoal) new MeleeAttackGoal((PathfinderMob) owner, this.speed, this.longMemory); } diff --git a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAvoidLivingGoalBuilder.java b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAvoidLivingGoalBuilder.java index a98478b729c..d71213c7d9f 100644 --- a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAvoidLivingGoalBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeAvoidLivingGoalBuilder.java @@ -27,8 +27,8 @@ import net.minecraft.world.entity.PathfinderMob; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.ai.goal.builtin.creature.AvoidLivingGoal; -import org.spongepowered.api.entity.living.Creature; import org.spongepowered.api.entity.living.Living; +import org.spongepowered.api.entity.living.PathfinderAgent; import java.util.Objects; import java.util.function.Predicate; @@ -86,7 +86,7 @@ public AvoidLivingGoal.Builder reset() { @Override @SuppressWarnings({"unchecked", "rawtypes"}) - public AvoidLivingGoal build(Creature owner) { + public AvoidLivingGoal build(PathfinderAgent owner) { Objects.requireNonNull(owner); Objects.requireNonNull(this.targetSelector); return (AvoidLivingGoal) new net.minecraft.world.entity.ai.goal.AvoidEntityGoal((PathfinderMob) owner, Entity.class, this.searchDistance, diff --git a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRandomWalkingGoalBuilder.java b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRandomWalkingGoalBuilder.java index acaca26b440..1baf5fd4a3a 100644 --- a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRandomWalkingGoalBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRandomWalkingGoalBuilder.java @@ -26,7 +26,7 @@ import net.minecraft.world.entity.PathfinderMob; import org.spongepowered.api.entity.ai.goal.builtin.creature.RandomWalkingGoal; -import org.spongepowered.api.entity.living.Creature; +import org.spongepowered.api.entity.living.PathfinderAgent; import java.util.Objects; @@ -65,7 +65,7 @@ public RandomWalkingGoal.Builder reset() { } @Override - public RandomWalkingGoal build(Creature owner) { + public RandomWalkingGoal build(PathfinderAgent owner) { Objects.requireNonNull(owner); return (RandomWalkingGoal) new net.minecraft.world.entity.ai.goal.RandomStrollGoal((PathfinderMob) owner, this.speed, this.executionChance); } diff --git a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRangedAttackAgainstAgentGoalBuilder.java b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRangedAttackAgainstAgentGoalBuilder.java index 03914bcff14..ac0d8865672 100644 --- a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRangedAttackAgainstAgentGoalBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/SpongeRangedAttackAgainstAgentGoalBuilder.java @@ -27,7 +27,7 @@ import net.minecraft.world.entity.ai.goal.RangedAttackGoal; import net.minecraft.world.entity.monster.RangedAttackMob; import org.spongepowered.api.entity.ai.goal.builtin.creature.RangedAttackAgainstAgentGoal; -import org.spongepowered.api.entity.living.Ranger; +import org.spongepowered.api.entity.living.RangedAgent; import org.spongepowered.api.util.Ticks; import org.spongepowered.common.util.Constants; import org.spongepowered.common.util.SpongeTicks; @@ -81,7 +81,7 @@ public RangedAttackAgainstAgentGoal.Builder reset() { } @Override - public RangedAttackAgainstAgentGoal build(final Ranger owner) { + public RangedAttackAgainstAgentGoal build(final RangedAgent owner) { Objects.requireNonNull(owner); if (!(owner instanceof RangedAttackMob)) { throw new IllegalArgumentException("Ranger must be an IRangedAttackMob!"); diff --git a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/target/SpongeFindNearestAttackableTargetGoalBuilder.java b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/target/SpongeFindNearestAttackableTargetGoalBuilder.java index b73b5a24229..a85069f64e2 100644 --- a/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/target/SpongeFindNearestAttackableTargetGoalBuilder.java +++ b/src/main/java/org/spongepowered/common/entity/ai/goal/builtin/creature/target/SpongeFindNearestAttackableTargetGoalBuilder.java @@ -30,8 +30,8 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.entity.ai.goal.builtin.creature.target.FindNearestAttackableTargetGoal; -import org.spongepowered.api.entity.living.Creature; import org.spongepowered.api.entity.living.Living; +import org.spongepowered.api.entity.living.PathfinderAgent; import java.util.Objects; import java.util.function.Predicate; @@ -89,7 +89,7 @@ public FindNearestAttackableTargetGoal.Builder reset() { } @Override - public FindNearestAttackableTargetGoal build(Creature owner) { + public FindNearestAttackableTargetGoal build(PathfinderAgent owner) { Objects.requireNonNull(owner); Objects.requireNonNull(this.targetClass); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java index 312c191f13a..99af9107277 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/world/EntityPerformingDropsTransaction.java @@ -31,7 +31,6 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.MobSpawnType; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/FlyingMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/FlyingMobMixin_API.java index 345fcfb1271..eb413d88e1f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/FlyingMobMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/FlyingMobMixin_API.java @@ -25,7 +25,7 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity; import net.minecraft.world.entity.FlyingMob; -import org.spongepowered.api.entity.living.Aerial; +import org.spongepowered.api.entity.Aerial; import org.spongepowered.asm.mixin.Mixin; @Mixin(FlyingMob.class) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PathfinderMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PathfinderMobMixin_API.java index 9c6c4c277fc..bb9b343f445 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PathfinderMobMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PathfinderMobMixin_API.java @@ -25,10 +25,10 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity; import net.minecraft.world.entity.PathfinderMob; -import org.spongepowered.api.entity.living.Creature; +import org.spongepowered.api.entity.living.PathfinderAgent; import org.spongepowered.asm.mixin.Mixin; @Mixin(PathfinderMob.class) -public abstract class PathfinderMobMixin_API extends MobMixin_API implements Creature { +public abstract class PathfinderMobMixin_API extends MobMixin_API implements PathfinderAgent { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/AvoidEntityGoalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/AvoidEntityGoalMixin_API.java index 0a85b0d99d9..6b54348d93e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/AvoidEntityGoalMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/AvoidEntityGoalMixin_API.java @@ -27,8 +27,8 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.targeting.TargetingConditions; import org.spongepowered.api.entity.ai.goal.builtin.creature.AvoidLivingGoal; -import org.spongepowered.api.entity.living.Creature; import org.spongepowered.api.entity.living.Living; +import org.spongepowered.api.entity.living.PathfinderAgent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; @@ -39,7 +39,7 @@ @SuppressWarnings({"unchecked"}) @Mixin(net.minecraft.world.entity.ai.goal.AvoidEntityGoal.class) -public abstract class AvoidEntityGoalMixin_API extends GoalMixin_API implements AvoidLivingGoal { +public abstract class AvoidEntityGoalMixin_API extends GoalMixin_API implements AvoidLivingGoal { private static final Predicate ALWAYS_TRUE = e -> true; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/RandomStrollGoalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/RandomStrollGoalMixin_API.java index d3cc3370e07..5a19a456f64 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/RandomStrollGoalMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/goal/RandomStrollGoalMixin_API.java @@ -25,14 +25,14 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.ai.goal; import org.spongepowered.api.entity.ai.goal.builtin.creature.RandomWalkingGoal; -import org.spongepowered.api.entity.living.Creature; +import org.spongepowered.api.entity.living.PathfinderAgent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Shadow; @Mixin(net.minecraft.world.entity.ai.goal.RandomStrollGoal.class) -public abstract class RandomStrollGoalMixin_API extends GoalMixin_API implements RandomWalkingGoal { +public abstract class RandomStrollGoalMixin_API extends GoalMixin_API implements RandomWalkingGoal { // @formatter:off @Shadow @Final @Mutable protected double speedModifier; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/allay/AllayMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/allay/AllayMixin_API.java index 1c41e53b916..a0e139bafa3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/allay/AllayMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/allay/AllayMixin_API.java @@ -25,7 +25,7 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.animal.allay; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.living.animal.Allay; +import org.spongepowered.api.entity.living.Allay; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.common.mixin.api.minecraft.world.entity.PathfinderMobMixin_API; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/HoglinMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/HoglinMixin_API.java index c032e3afd56..566a80e54ca 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/HoglinMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/HoglinMixin_API.java @@ -24,7 +24,7 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; -import org.spongepowered.api.entity.living.monster.hoglin.Hoglin; +import org.spongepowered.api.entity.living.animal.Hoglin; import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.entity.monster.hoglin.Hoglin.class) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/MagmaCubeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/MagmaCubeMixin_API.java index 87638d577ea..201e358d58b 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/MagmaCubeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/MagmaCubeMixin_API.java @@ -24,7 +24,7 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; -import org.spongepowered.api.entity.living.monster.slime.MagmaCube; +import org.spongepowered.api.entity.living.slime.MagmaCube; import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.entity.monster.MagmaCube.class) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/RangedAttackMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/RangedAttackMobMixin_API.java index 06b8b0b8835..ebd6135546d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/RangedAttackMobMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/RangedAttackMobMixin_API.java @@ -25,7 +25,7 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; import net.minecraft.world.entity.monster.RangedAttackMob; -import org.spongepowered.api.entity.living.Ranger; +import org.spongepowered.api.entity.Ranger; import org.spongepowered.asm.mixin.Mixin; @Mixin(RangedAttackMob.class) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/SlimeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/SlimeMixin_API.java index 11b638b0b35..d856a84805a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/SlimeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/SlimeMixin_API.java @@ -26,7 +26,7 @@ import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.living.monster.slime.Slime; +import org.spongepowered.api.entity.living.slime.Slime; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.common.mixin.api.minecraft.world.entity.MobMixin_API; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java index c915884ae7a..b0f8eda1735 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/StriderMixin_API.java @@ -24,7 +24,7 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; -import org.spongepowered.api.entity.living.monster.Strider; +import org.spongepowered.api.entity.living.animal.Strider; import org.spongepowered.asm.mixin.Mixin; @Mixin(net.minecraft.world.entity.monster.Strider.class) diff --git a/src/test/java/org/spongepowered/common/util/TypeTokenUtilTest.java b/src/test/java/org/spongepowered/common/util/TypeTokenUtilTest.java index 6ad6ad3fdad..7ad58972742 100644 --- a/src/test/java/org/spongepowered/common/util/TypeTokenUtilTest.java +++ b/src/test/java/org/spongepowered/common/util/TypeTokenUtilTest.java @@ -37,7 +37,7 @@ import org.spongepowered.api.data.value.Value; import org.spongepowered.api.entity.living.Living; import org.spongepowered.api.entity.living.monster.boss.dragon.EnderDragon; -import org.spongepowered.api.entity.living.monster.slime.Slime; +import org.spongepowered.api.entity.living.slime.Slime; import org.spongepowered.common.data.value.SpongeValue; public final class TypeTokenUtilTest { diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java index 71549f0ca40..88c70836dfa 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -32,7 +32,6 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; @@ -41,7 +40,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.Level; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; From 268c7f3f8a4d35bfb7dca1294c6c597d52c52dc4 Mon Sep 17 00:00:00 2001 From: aromaa Date: Tue, 2 Jul 2024 22:13:53 +0300 Subject: [PATCH 122/226] Fixes to channels --- .../network/channel/SpongeChannelManager.java | 2 +- .../network/channel/TransactionStore.java | 15 ++++++------ .../packet/SpongeBasicPacketChannel.java | 23 +++++++++++++++---- .../channel/packet/SpongePacketChannel.java | 2 +- .../minecraft/client/MinecraftMixin_API.java | 8 +++++-- .../ClientPacketListenerMixin_API.java | 4 ++-- ...erGamePacketListenerImplMixin_Vanilla.java | 13 +++++++++++ 7 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/spongepowered/common/network/channel/SpongeChannelManager.java b/src/main/java/org/spongepowered/common/network/channel/SpongeChannelManager.java index 0a71fe53cc3..b15d10365f7 100644 --- a/src/main/java/org/spongepowered/common/network/channel/SpongeChannelManager.java +++ b/src/main/java/org/spongepowered/common/network/channel/SpongeChannelManager.java @@ -411,7 +411,7 @@ private void handleLoginResponsePayload(final EngineConnection connection, final // Normal handling final TransactionStore transactionStore = ConnectionUtil.getTransactionStore(connection); final TransactionStore.Entry entry = transactionStore.remove(transactionId); - if (entry == null) { + if (entry == null || entry.getData() == null) { return; } if (entry.getData() instanceof ClientTypeSyncFuture) { diff --git a/src/main/java/org/spongepowered/common/network/channel/TransactionStore.java b/src/main/java/org/spongepowered/common/network/channel/TransactionStore.java index 72c8007ee45..8c7d848649c 100644 --- a/src/main/java/org/spongepowered/common/network/channel/TransactionStore.java +++ b/src/main/java/org/spongepowered/common/network/channel/TransactionStore.java @@ -47,7 +47,8 @@ public final class TransactionStore { private final ConcurrentMap lookup = Caffeine.newBuilder() .expireAfterAccess(15, TimeUnit.SECONDS) .removalListener((RemovalListener) (key, value, cause) -> { - if (cause == RemovalCause.EXPIRED && value != null) { + //The channel is null for few internal packets + if (cause == RemovalCause.EXPIRED && value != null && value.getChannel() != null) { final EngineConnectionState state = (EngineConnectionState) ((SpongeEngineConnection) this.connection()).connection().getPacketListener(); value.getChannel().handleTransactionResponse( this.connection(), state, value.getData(), TransactionResult.failure(new TimeoutException())); @@ -57,19 +58,19 @@ public final class TransactionStore { public static class Entry { - private final SpongeChannel channel; - private final Object data; + private final @Nullable SpongeChannel channel; + private final @Nullable Object data; - public Entry(final SpongeChannel channel, final Object data) { + public Entry(final @Nullable SpongeChannel channel, final @Nullable Object data) { this.channel = channel; this.data = data; } - public SpongeChannel getChannel() { + public @Nullable SpongeChannel getChannel() { return this.channel; } - public Object getData() { + public @Nullable Object getData() { return this.data; } } @@ -110,7 +111,7 @@ public int nextId() { * @param channel The channel * @param stored The stored data */ - public void put(final int transactionId, final SpongeChannel channel, final Object stored) { + public void put(final int transactionId, final @Nullable SpongeChannel channel, final @Nullable Object stored) { this.lookup.put(transactionId, new Entry(channel, stored)); } diff --git a/src/main/java/org/spongepowered/common/network/channel/packet/SpongeBasicPacketChannel.java b/src/main/java/org/spongepowered/common/network/channel/packet/SpongeBasicPacketChannel.java index 799523045e2..68ad9ce8eb1 100644 --- a/src/main/java/org/spongepowered/common/network/channel/packet/SpongeBasicPacketChannel.java +++ b/src/main/java/org/spongepowered/common/network/channel/packet/SpongeBasicPacketChannel.java @@ -103,13 +103,17 @@ public void write(FriendlyByteBuf var1) { } } , transactionId); + + final TransactionData transactionData = new TransactionData<>(request, binding, success, future); + transactionStore.put(transactionId, SpongeBasicPacketChannel.this, transactionData); + PacketSender.sendTo(connection, mcPacket, throwable -> { if (throwable != null) { - // Failed before it could reach the client - SpongeBasicPacketChannel.this.handleException(connection, state, ChannelExceptionUtil.of(throwable), future); + if (transactionStore.remove(transactionId) != null) { + // Failed before it could reach the client + SpongeBasicPacketChannel.this.handleException(connection, state, ChannelExceptionUtil.of(throwable), future); + } } else { - final TransactionData transactionData = new TransactionData<>(request, binding, success, future); - transactionStore.put(transactionId, SpongeBasicPacketChannel.this, transactionData); if (sendSuccess != null) { sendSuccess.run(); } @@ -145,7 +149,16 @@ public void write(FriendlyByteBuf var1) { } } , transactionId); - PacketSender.sendTo(connection, mcPacket, future); + + transactionStore.put(transactionId, SpongeBasicPacketChannel.this, null); + + PacketSender.sendTo(connection, mcPacket, throwable -> { + if (throwable == null) { + future.complete(null); + } else if (transactionStore.remove(transactionId) != null) { + future.completeExceptionally(throwable); + } + }); return future; } diff --git a/src/main/java/org/spongepowered/common/network/channel/packet/SpongePacketChannel.java b/src/main/java/org/spongepowered/common/network/channel/packet/SpongePacketChannel.java index 256fe6e46c2..93af64f69c6 100644 --- a/src/main/java/org/spongepowered/common/network/channel/packet/SpongePacketChannel.java +++ b/src/main/java/org/spongepowered/common/network/channel/packet/SpongePacketChannel.java @@ -332,7 +332,7 @@ private void handleResponsePacket(final EngineConnection connection, final Engin final int dynamicOpcode) { final TransactionStore store = ConnectionUtil.getTransactionStore(connection); final TransactionStore.Entry stored = store.remove(transactionId); - if (stored == null) { + if (stored == null || stored.getData() == null) { return; } final TransactionData, Packet> transactionData = diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java index 8c8b1b3f89e..9a2a4c88084 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/MinecraftMixin_API.java @@ -26,6 +26,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.Options; +import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.server.IntegratedServer; import net.minecraft.network.Connection; import net.minecraft.server.packs.repository.PackRepository; @@ -42,6 +43,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.bridge.client.MinecraftBridge; +import org.spongepowered.common.bridge.network.ConnectionBridge; import org.spongepowered.common.client.SpongeClient; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.registry.RegistryHolderLogic; @@ -66,6 +68,7 @@ public abstract class MinecraftMixin_API implements SpongeClient, SpongeRegistry @Shadow @Nullable public abstract IntegratedServer shadow$getSingleplayerServer(); @Shadow public abstract PackRepository shadow$getResourcePackRepository(); @Shadow public abstract net.minecraft.server.packs.resources.ResourceManager shadow$getResourceManager(); + @Shadow @Nullable public abstract ClientPacketListener shadow$getConnection(); // @formatter:on private final ClientScheduler api$scheduler = new ClientScheduler(); @@ -96,10 +99,11 @@ public Optional world() { @Override public Optional connection() { - if (this.pendingConnection == null) { + final @Nullable ClientPacketListener connection = this.shadow$getConnection(); + if (connection == null) { return Optional.empty(); } - return Optional.ofNullable((ClientSideConnection) this.pendingConnection.getPacketListener()); + return Optional.ofNullable((ClientSideConnection) ((ConnectionBridge) connection.getConnection()).bridge$getEngineConnection()); } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientPacketListenerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientPacketListenerMixin_API.java index 1635a97f22f..c06e21c1c2e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientPacketListenerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/client/multiplayer/ClientPacketListenerMixin_API.java @@ -26,7 +26,7 @@ import net.minecraft.client.multiplayer.ClientPacketListener; import org.spongepowered.api.entity.living.player.client.LocalPlayer; -import org.spongepowered.api.network.EngineConnectionState; +import org.spongepowered.api.network.ClientConnectionState; import org.spongepowered.api.profile.GameProfile; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -34,7 +34,7 @@ import org.spongepowered.common.profile.SpongeGameProfile; @Mixin(ClientPacketListener.class) -public class ClientPacketListenerMixin_API extends ClientCommonPacketListenerImplMixin_API implements EngineConnectionState.Game { +public class ClientPacketListenerMixin_API extends ClientCommonPacketListenerImplMixin_API implements ClientConnectionState.Game { // @formatter:off @Shadow @Final private com.mojang.authlib.GameProfile localGameProfile; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/network/ServerGamePacketListenerImplMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/network/ServerGamePacketListenerImplMixin_Vanilla.java index a1b2325e913..2d3001e6308 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/network/ServerGamePacketListenerImplMixin_Vanilla.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/server/network/ServerGamePacketListenerImplMixin_Vanilla.java @@ -24,22 +24,29 @@ */ package org.spongepowered.vanilla.mixin.core.server.network; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.network.protocol.game.ServerGamePacketListener; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.world.inventory.RecipeBookMenu; import net.minecraft.world.item.crafting.RecipeHolder; import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.Sponge; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.crafting.CraftingInventory; import org.spongepowered.api.item.inventory.query.QueryTypes; +import org.spongepowered.api.network.EngineConnectionState; 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.network.ConnectionBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.network.channel.SpongeChannelManager; @Mixin(value = ServerGamePacketListenerImpl.class, priority = 999) public abstract class ServerGamePacketListenerImplMixin_Vanilla extends ServerCommonPacketListenerImplMixin_Vanilla implements ServerGamePacketListener { @@ -64,6 +71,12 @@ public abstract class ServerGamePacketListenerImplMixin_Vanilla extends ServerCo } } + @Inject(method = "handleCustomPayload", at = @At(value = "HEAD")) + private void vanilla$onHandleCustomPayload(final ServerboundCustomPayloadPacket packet, final CallbackInfo ci) { + final SpongeChannelManager channelRegistry = (SpongeChannelManager) Sponge.channelManager(); + this.server.execute(() -> channelRegistry.handlePlayPayload(((ConnectionBridge) this.connection).bridge$getEngineConnection(), (EngineConnectionState) this, packet.payload())); + } + /** * Specifically hooks the reach distance to use the forge hook. SpongeForge does not need this hook as forge already * replaces this logic with an equivalent. From a80c3233c7fef2b457ddce092f9d3bd3e5efbc3b Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 2 Jul 2024 03:21:55 +0300 Subject: [PATCH 123/226] fix EnderDragon#bossBar() --- SpongeAPI | 2 +- .../dimension/end/EndDragonFightAccessor.java | 36 +++++++++++++++++++ .../resources/mixins.sponge.accessors.json | 1 + .../data/provider/entity/EnderDragonData.java | 15 +++++++- .../enderdragon/EnderDragonMixin_API.java | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/accessors/java/org/spongepowered/common/accessor/world/level/dimension/end/EndDragonFightAccessor.java diff --git a/SpongeAPI b/SpongeAPI index 3a4be663d90..da80036cf27 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 3a4be663d90772afa59edeb83315576ca9448022 +Subproject commit da80036cf27047b78f0a3dbd5faca7342ebdb511 diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/dimension/end/EndDragonFightAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/dimension/end/EndDragonFightAccessor.java new file mode 100644 index 00000000000..7999d25ef76 --- /dev/null +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/dimension/end/EndDragonFightAccessor.java @@ -0,0 +1,36 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.accessor.world.level.dimension.end; + +import net.minecraft.server.level.ServerBossEvent; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EndDragonFight.class) +public interface EndDragonFightAccessor { + + @Accessor("dragonEvent") ServerBossEvent accessor$dragonEvent(); +} diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index 9ed69355952..fd01d3d6f7f 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -194,6 +194,7 @@ "world.level.chunk.storage.RegionFileAccessor", "world.level.chunk.storage.SimpleRegionStorageAccessor", "world.level.dimension.DimensionTypeAccessor", + "world.level.dimension.end.EndDragonFightAccessor", "world.level.entity.EntityTickListAccessor", "world.level.entity.PersistentEntitySectionManagerAccessor", "world.level.levelgen.NoiseSettingsAccessor", diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EnderDragonData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EnderDragonData.java index 51fea6d8294..1e7e9210906 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EnderDragonData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EnderDragonData.java @@ -25,8 +25,12 @@ package org.spongepowered.common.data.provider.entity; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.explosive.EndCrystal; +import org.spongepowered.common.accessor.world.level.dimension.end.EndDragonFightAccessor; +import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.data.provider.DataProviderRegistrator; public final class EnderDragonData { @@ -40,7 +44,16 @@ public static void register(final DataProviderRegistrator registrator) { .asMutable(EnderDragon.class) .create(Keys.HEALING_CRYSTAL) .get(h -> (EndCrystal) h.nearestCrystal) - .set((h, v) -> h.nearestCrystal = (net.minecraft.world.entity.boss.enderdragon.EndCrystal) v); + .set((h, v) -> h.nearestCrystal = (net.minecraft.world.entity.boss.enderdragon.EndCrystal) v) + .create(Keys.BOSS_BAR) + .get(h -> { + final @Nullable EndDragonFight fight = h.getDragonFight(); + if (fight != null) { + return SpongeAdventure.asAdventure(((EndDragonFightAccessor) fight).accessor$dragonEvent()); + } else { + return null; + } + }); } // @formatter:on } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/boss/enderdragon/EnderDragonMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/boss/enderdragon/EnderDragonMixin_API.java index 63576a37dea..1d5ea3ce658 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/boss/enderdragon/EnderDragonMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/boss/enderdragon/EnderDragonMixin_API.java @@ -68,6 +68,7 @@ public DragonPhaseManager phaseManager() { final Set> values = super.api$getVanillaValues(); this.getValue(Keys.HEALING_CRYSTAL).map(Value::asImmutable).ifPresent(values::add); + this.getValue(Keys.BOSS_BAR).map(Value::asImmutable).ifPresent(values::add); return values; } From 53674313b7eec9811a3fc4367aad0cf1ff83ba2c Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 2 Jul 2024 04:33:12 +0300 Subject: [PATCH 124/226] Add ServerWorld#dragonFightBossBar() --- SpongeAPI | 2 +- .../server/level/ServerLevelMixin_API.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index da80036cf27..d4e5a3663ab 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit da80036cf27047b78f0a3dbd5faca7342ebdb511 +Subproject commit d4e5a3663abade378d2868171d4fbf3ccc7b5c07 diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java index e0f27723f4a..03c3ef4ca14 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerLevelMixin_API.java @@ -25,6 +25,7 @@ package org.spongepowered.common.mixin.api.minecraft.server.level; import com.google.common.collect.ImmutableList; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.pointer.Pointers; import net.minecraft.core.BlockPos; @@ -41,6 +42,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionStorageInfo; +import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.storage.LevelResource; @@ -73,6 +75,8 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.accessor.world.entity.raid.RaidsAccessor; +import org.spongepowered.common.accessor.world.level.dimension.end.EndDragonFightAccessor; +import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.server.level.ServerLevelBridge; import org.spongepowered.common.bridge.world.level.border.WorldBorderBridge; import org.spongepowered.common.bridge.world.level.chunk.storage.RegionFileBridge; @@ -122,6 +126,7 @@ public abstract class ServerLevelMixin_API extends LevelMixin_API shadow$players(); @Shadow public abstract Raids shadow$getRaids(); @Nullable @Shadow public abstract Raid shadow$getRaidAt(BlockPos p_217475_1_); + @Nullable @Shadow public abstract EndDragonFight shadow$getDragonFight(); @Shadow public abstract long shadow$getSeed(); // @formatter:on @@ -258,6 +263,16 @@ public Optional raidAt(final Vector3i blockPosi return Optional.ofNullable((org.spongepowered.api.raid.Raid) this.shadow$getRaidAt(VecHelper.toBlockPos(Objects.requireNonNull(blockPosition, "blockPosition")))); } + @Override + public Optional dragonFightBossBar() { + final @Nullable EndDragonFight fight = this.shadow$getDragonFight(); + if (fight != null) { + return Optional.of(SpongeAdventure.asAdventure(((EndDragonFightAccessor) fight).accessor$dragonEvent())); + } else { + return Optional.empty(); + } + } + // Volume @Override From 93437a738f3e07877fd18af3de7b343fa1a0b7d7 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 11:09:37 +0200 Subject: [PATCH 125/226] fix ItemStackComparator fixes #3991 --- .../util/SpongeItemStackComparatorFactory.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/spongepowered/common/item/util/SpongeItemStackComparatorFactory.java b/src/main/java/org/spongepowered/common/item/util/SpongeItemStackComparatorFactory.java index 854672052c2..4e41bcb0558 100644 --- a/src/main/java/org/spongepowered/common/item/util/SpongeItemStackComparatorFactory.java +++ b/src/main/java/org/spongepowered/common/item/util/SpongeItemStackComparatorFactory.java @@ -31,9 +31,9 @@ import org.spongepowered.api.registry.RegistryTypes; import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; +import java.util.Map; import java.util.function.Supplier; +import java.util.stream.Collectors; public class SpongeItemStackComparatorFactory implements ItemStackComparators.Factory { @@ -92,21 +92,21 @@ private static final class ItemDataComparator implements Comparator { @Override public int compare(ItemStack o1, ItemStack o2) { - final Set> values = new HashSet<>(o2.getValues()); + final Map>, ?> map = o2.getValues().stream().collect(Collectors.toMap(Value::key, Value::get)); for (Value.Immutable value : o1.getValues()) { - if (values.contains(value)) { - values.remove(value); - } else if (!this.isIgnored(values, value)) { + if (map.containsKey(value.key()) && map.get(value.key()).equals(value.get())) { + map.remove(value.key()); + } else if (!this.isIgnored(map, value)) { return -1; } } - return values.size(); + return map.size(); } - private boolean isIgnored(Set> list, Value.Immutable toCheck) { + private boolean isIgnored(Map>, ?> map, Value.Immutable toCheck) { for (Key> ignore : this.ignored) { if (toCheck.key().equals(ignore)) { - list.removeIf(val -> ignore.equals(val.key())); + map.remove(ignore); return true; } } From df5aa795c0215bd55ceeabb6675e8aea62db1810 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 11:13:58 +0200 Subject: [PATCH 126/226] fix empty CONTAINER component breaking comparators --- .../common/data/provider/item/stack/ItemStackData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index efee62b5ac6..ced477d1845 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -286,7 +286,7 @@ private static Inventory inventoryFromItemContainerContents(final ItemContainerC } var slots = contents.stream().map(ItemStackUtil::cloneDefensive).toList(); if (slots.isEmpty()) { - return new EmptyInventoryImpl(null); + return null; } final Inventory inventory = Inventory.builder().slots(slots.size()).completeStructure() .plugin(SpongeCommon.game().platform().container(Platform.Component.IMPLEMENTATION)) From 0c7dcdd72b9d2857119f5b27368d5771c58f6b6e Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 11:13:13 +0200 Subject: [PATCH 127/226] fix AdventureComponents breaking ItemStack equality --- SpongeAPI | 2 +- .../common/data/provider/item/stack/BookItemStackData.java | 3 ++- .../common/data/provider/item/stack/ItemStackData.java | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index d4e5a3663ab..75f057f322d 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit d4e5a3663abade378d2868171d4fbf3ccc7b5c07 +Subproject commit 75f057f322d546b34c7b976c69dcc686e64fabac diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java index 0ac24a25528..a69147bffa2 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookItemStackData.java @@ -26,6 +26,7 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; import net.minecraft.server.network.Filterable; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -89,7 +90,7 @@ public static void register(final DataProviderRegistrator registrator) { }) .set((h, v) -> { final WrittenBookContent content = h.getOrDefault(DataComponents.WRITTEN_BOOK_CONTENT, WrittenBookContent.EMPTY); - var pages = v.stream().map(SpongeAdventure::asVanilla).map(Filterable::passThrough).toList(); + var pages = v.stream().map(SpongeAdventure::asVanillaMutable).map(Component.class::cast).map(Filterable::passThrough).toList(); h.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(content.title(), content.author(), content.generation(), pages, content.resolved())); }) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index ced477d1845..9038cfab5e1 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -157,7 +157,7 @@ public static void register(final DataProviderRegistrator registrator) { } return null; }) - .set((h, v) -> h.set(DataComponents.CUSTOM_NAME, SpongeAdventure.asVanilla(v))) + .set((h, v) -> h.set(DataComponents.CUSTOM_NAME, SpongeAdventure.asVanillaMutable(v))) .delete(h -> h.remove(DataComponents.CUSTOM_NAME)) .create(Keys.IS_UNBREAKABLE) .get(h -> h.has(DataComponents.UNBREAKABLE)) @@ -176,7 +176,7 @@ public static void register(final DataProviderRegistrator registrator) { h.remove(DataComponents.LORE); return; } - h.set(DataComponents.LORE, new ItemLore(v.stream().map(SpongeAdventure::asVanilla).toList())); + h.set(DataComponents.LORE, new ItemLore(v.stream().map(SpongeAdventure::asVanillaMutable).map(Component.class::cast).toList())); }) .delete(h -> h.remove(DataComponents.LORE)) .create(Keys.MAX_DURABILITY) @@ -274,7 +274,7 @@ public static void register(final DataProviderRegistrator registrator) { } return SpongeAdventure.asAdventure(component); }) - .set((h, value) -> h.set(DataComponents.ITEM_NAME, SpongeAdventure.asVanilla(value))) + .set((h, value) -> h.set(DataComponents.ITEM_NAME, SpongeAdventure.asVanillaMutable(value))) .delete(stack -> stack.remove(DataComponents.ITEM_NAME)) ; } From 0740f115a71ff52dd18300e1046f25e5bda1b7e8 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 11:25:45 +0200 Subject: [PATCH 128/226] fix build --- SpongeAPI | 2 +- .../common/data/provider/item/stack/ItemStackData.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 75f057f322d..3a4be663d90 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 75f057f322d546b34c7b976c69dcc686e64fabac +Subproject commit 3a4be663d90772afa59edeb83315576ca9448022 diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index 9038cfab5e1..ae045fac038 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -56,7 +56,6 @@ import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.data.provider.DataProviderRegistrator; -import org.spongepowered.common.inventory.EmptyInventoryImpl; import org.spongepowered.common.item.util.ItemStackUtil; import java.util.ArrayList; From 37444acfaf629eb13a92c20fffa369cdeca6df8d Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 11:53:04 +0200 Subject: [PATCH 129/226] actually fix build --- .../provider/entity/AbstractVillagerData.java | 5 ++- .../api/item/merchant/MerchantMixin_API.java | 5 --- .../entity/npc/AbstractVillagerMixin_API.java | 37 +------------------ .../org/spongepowered/test/data/DataTest.java | 2 +- 4 files changed, 6 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractVillagerData.java b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractVillagerData.java index 54d9919a7cc..52735629ee3 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/AbstractVillagerData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/AbstractVillagerData.java @@ -26,6 +26,7 @@ import net.minecraft.world.entity.npc.AbstractVillager; import org.spongepowered.api.data.Keys; +import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.common.data.provider.DataProviderRegistrator; public final class AbstractVillagerData { @@ -37,8 +38,8 @@ private AbstractVillagerData() { public static void register(final DataProviderRegistrator registrator) { registrator .asMutable(AbstractVillager.class) - .create(Keys.IS_TRADING) - .get(AbstractVillager::isTrading); + .create(Keys.CUSTOMER) + .get(v -> (Player) v.getTradingPlayer()); } // @formatter:on } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java index ec599414691..a81d665c2cb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java @@ -30,7 +30,6 @@ import net.minecraft.world.item.trading.MerchantOffers; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.data.Keys; -import org.spongepowered.api.entity.living.Humanoid; import org.spongepowered.api.item.merchant.Merchant; import org.spongepowered.api.item.merchant.TradeOffer; import org.spongepowered.asm.mixin.Implements; @@ -43,10 +42,6 @@ @Implements(@Interface(iface = net.minecraft.world.item.trading.Merchant.class, prefix = "imerchant$")) public interface MerchantMixin_API extends Merchant { - default void imerchant$setTradingPlayer(@Nullable final Player player) { - this.setCustomer((Humanoid) player); - } - @Nullable default Player imerchant$getTradingPlayer() { return (Player) this.customer() diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java index 263d1e39396..88b67059d60 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java @@ -25,44 +25,11 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.npc; import net.minecraft.world.entity.npc.AbstractVillager; -import net.minecraft.world.entity.player.Player; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.data.Keys; -import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.living.Humanoid; -import org.spongepowered.api.entity.living.trader.Trader; +import org.spongepowered.api.entity.living.trader.VillagerLike; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.mixin.api.minecraft.world.entity.AgeableMobMixin_API; -import java.util.Optional; -import java.util.Set; - @Mixin(AbstractVillager.class) -public abstract class AbstractVillagerMixin_API extends AgeableMobMixin_API implements Trader { - - // @formatter:off - @Shadow public abstract void shadow$setTradingPlayer(Player player); - @Shadow public abstract Player shadow$getTradingPlayer(); - // @formatter:on - - @Override - public Optional customer() { - return Optional.ofNullable((Humanoid) this.shadow$getTradingPlayer()); - } - - @Override - public void setCustomer(@Nullable Humanoid humanoid) { - this.shadow$setTradingPlayer((Player) humanoid); - } - - @Override - protected Set> api$getVanillaValues() { - final Set> values = super.api$getVanillaValues(); - - values.add(this.requireValue(Keys.IS_TRADING).asImmutable()); - - return values; - } +public abstract class AbstractVillagerMixin_API extends AgeableMobMixin_API implements VillagerLike { } diff --git a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java index efd385b1532..f215fd7b836 100644 --- a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java @@ -946,7 +946,7 @@ public void testData(final ServerPlayer player) { this.checkOfferData(wolf, Keys.IS_TAMED, true); final Entity villager = world.createEntity(EntityTypes.VILLAGER.get(), position); - this.checkGetData(villager, Keys.IS_TRADING, false); +// this.checkGetData(villager, Keys.IS_TRADING, false); final Entity ocelot = world.createEntity(EntityTypes.OCELOT.get(), position); this.checkOfferData(ocelot, Keys.IS_TRUSTING, true); From 09d27d32adc77015c727ef18422539a41b23fd9a Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sat, 6 Jul 2024 12:04:20 +0200 Subject: [PATCH 130/226] bump API --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 3a4be663d90..c7d825ac452 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 3a4be663d90772afa59edeb83315576ca9448022 +Subproject commit c7d825ac45277e4c20ed65b3ca921877cb6fcc32 From 63acd582c70d0523d7a6b671313a4ab7e18d543c Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 6 Jul 2024 12:53:16 +0000 Subject: [PATCH 131/226] Bump SpongeAPI and update mixins (#4081) --- SpongeAPI | 2 +- .../phase/tick/EntityTickPhaseState.java | 4 +- .../api/item/merchant/MerchantMixin_API.java | 38 +------------------ .../world/entity/AgeableMobMixin_API.java | 5 ++- .../entity/npc/AbstractVillagerMixin_API.java | 13 +++++++ .../entity/projectile/FireballMixin_API.java | 4 +- .../core/world/entity/animal/AnimalMixin.java | 2 +- .../org/spongepowered/test/data/DataTest.java | 2 +- 8 files changed, 24 insertions(+), 46 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index c7d825ac452..75f057f322d 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit c7d825ac45277e4c20ed65b3ca921877cb6fcc32 +Subproject commit 75f057f322d546b34c7b976c69dcc686e64fabac diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/tick/EntityTickPhaseState.java b/src/main/java/org/spongepowered/common/event/tracking/phase/tick/EntityTickPhaseState.java index aa8243b3169..27405e72373 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/tick/EntityTickPhaseState.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/tick/EntityTickPhaseState.java @@ -33,9 +33,9 @@ import net.minecraft.world.phys.Vec3; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.block.transaction.BlockTransactionReceipt; +import org.spongepowered.api.entity.Breedable; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.ExperienceOrb; -import org.spongepowered.api.entity.living.Ageable; import org.spongepowered.api.entity.projectile.Projectile; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.cause.entity.SpawnType; @@ -94,7 +94,7 @@ public Supplier getSpawnTypeForTransaction( } final Entity source = context.getSource(Entity.class) .orElseThrow(() -> new IllegalStateException("Ticking over a non Entity")); - if (source instanceof Ageable) { + if (source instanceof Breedable) { if (source.getClass() == entityToSpawn.getClass()) { return SpawnTypes.BREEDING; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java index a81d665c2cb..c22beb598a0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/item/merchant/MerchantMixin_API.java @@ -24,45 +24,9 @@ */ package org.spongepowered.common.mixin.api.item.merchant; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.trading.MerchantOffer; -import net.minecraft.world.item.trading.MerchantOffers; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.data.Keys; import org.spongepowered.api.item.merchant.Merchant; -import org.spongepowered.api.item.merchant.TradeOffer; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; import org.spongepowered.asm.mixin.Mixin; -import java.util.Collections; - -@Mixin(value = Merchant.class) -@Implements(@Interface(iface = net.minecraft.world.item.trading.Merchant.class, prefix = "imerchant$")) +@Mixin(net.minecraft.world.item.trading.Merchant.class) public interface MerchantMixin_API extends Merchant { - - @Nullable - default Player imerchant$getTradingPlayer() { - return (Player) this.customer() - .filter(humanoid -> humanoid instanceof Player) - .orElse(null); - } - - @Nullable - default MerchantOffers imerchant$getOffers() { - final MerchantOffers merchantRecipes = new MerchantOffers(); - for (final TradeOffer tradeOffer : this.get(Keys.TRADE_OFFERS).orElse(Collections.emptyList())) { - merchantRecipes.add((MerchantOffer) tradeOffer); - } - return merchantRecipes; - } - - default void imerchant$notifyTrade(final MerchantOffer recipe) { - - } - - default void imerchant$notifyTradeUpdated(final ItemStack stack) { - - } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AgeableMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AgeableMobMixin_API.java index 7afca4494a3..be4e1247132 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AgeableMobMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AgeableMobMixin_API.java @@ -27,13 +27,14 @@ import net.minecraft.world.entity.AgeableMob; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.living.Ageable; +import org.spongepowered.api.entity.Ageable; +import org.spongepowered.api.entity.Breedable; import org.spongepowered.asm.mixin.Mixin; import java.util.Set; @Mixin(AgeableMob.class) -public abstract class AgeableMobMixin_API extends PathfinderMobMixin_API implements Ageable { +public abstract class AgeableMobMixin_API extends PathfinderMobMixin_API implements Ageable, Breedable { @Override protected Set> api$getVanillaValues() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java index 88b67059d60..0898f3a3dea 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/npc/AbstractVillagerMixin_API.java @@ -25,11 +25,24 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.npc; import net.minecraft.world.entity.npc.AbstractVillager; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.data.value.Value; import org.spongepowered.api.entity.living.trader.VillagerLike; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.common.mixin.api.minecraft.world.entity.AgeableMobMixin_API; +import java.util.Set; + @Mixin(AbstractVillager.class) public abstract class AbstractVillagerMixin_API extends AgeableMobMixin_API implements VillagerLike { + @Override + protected Set> api$getVanillaValues() { + final Set> values = super.api$getVanillaValues(); + + values.add(this.requireValue(Keys.CUSTOMER).asImmutable()); + + return values; + } + } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/FireballMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/FireballMixin_API.java index 13ec9718334..3ee190cad57 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/FireballMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/FireballMixin_API.java @@ -25,10 +25,10 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile; import net.minecraft.world.entity.projectile.Fireball; -import org.spongepowered.api.entity.projectile.explosive.fireball.FireballEntity; +import org.spongepowered.api.entity.projectile.IgnitingProjectile; import org.spongepowered.asm.mixin.Mixin; @Mixin(Fireball.class) -public abstract class FireballMixin_API extends AbstractHurtingProjectileMixin_API implements FireballEntity { +public abstract class FireballMixin_API extends AbstractHurtingProjectileMixin_API implements IgnitingProjectile { } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/AnimalMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/AnimalMixin.java index 1fb7ef42a64..5d1f5738366 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/AnimalMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/animal/AnimalMixin.java @@ -27,7 +27,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.animal.Animal; -import org.spongepowered.api.entity.living.Ageable; +import org.spongepowered.api.entity.Ageable; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.asm.mixin.Mixin; diff --git a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java index f215fd7b836..84541eb6c7e 100644 --- a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java @@ -946,7 +946,7 @@ public void testData(final ServerPlayer player) { this.checkOfferData(wolf, Keys.IS_TAMED, true); final Entity villager = world.createEntity(EntityTypes.VILLAGER.get(), position); -// this.checkGetData(villager, Keys.IS_TRADING, false); + this.checkGetData(villager, Keys.CUSTOMER, null); final Entity ocelot = world.createEntity(EntityTypes.OCELOT.get(), position); this.checkOfferData(ocelot, Keys.IS_TRUSTING, true); From 17a87108c1ca77975bdef01f20286dddb814f671 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sat, 6 Jul 2024 16:44:02 +0000 Subject: [PATCH 132/226] Bump SpongeAPI (#4082) * Update for api changes * Bump SpongeAPI --- SpongeAPI | 2 +- .../world/entity/projectile/AbstractArrowMixin_API.java | 4 ++-- .../projectile/AbstractHurtingProjectileMixin_API.java | 4 ++-- .../entity/projectile/ThrowableItemProjectileMixin_API.java | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 75f057f322d..b4fab131ee0 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 75f057f322d546b34c7b976c69dcc686e64fabac +Subproject commit b4fab131ee01192ae3d6fa9bf33cdc2dc2af9076 diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractArrowMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractArrowMixin_API.java index a909e9048e9..14702b4832c 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractArrowMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractArrowMixin_API.java @@ -27,13 +27,13 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.projectile.arrow.ArrowEntity; +import org.spongepowered.api.entity.projectile.arrow.ArrowLike; import org.spongepowered.asm.mixin.Mixin; import java.util.Set; @Mixin(AbstractArrow.class) -public abstract class AbstractArrowMixin_API extends ProjectileMixin_API implements ArrowEntity { +public abstract class AbstractArrowMixin_API extends ProjectileMixin_API implements ArrowLike { @Override protected Set> api$getVanillaValues() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractHurtingProjectileMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractHurtingProjectileMixin_API.java index 2f64fa93b5b..e709112d51e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractHurtingProjectileMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/AbstractHurtingProjectileMixin_API.java @@ -27,13 +27,13 @@ import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.entity.projectile.DamagingProjectile; +import org.spongepowered.api.entity.projectile.AcceleratingProjectile; import org.spongepowered.asm.mixin.Mixin; import java.util.Set; @Mixin(AbstractHurtingProjectile.class) -public abstract class AbstractHurtingProjectileMixin_API extends ProjectileMixin_API implements DamagingProjectile { +public abstract class AbstractHurtingProjectileMixin_API extends ProjectileMixin_API implements AcceleratingProjectile { @Override protected Set> api$getVanillaValues() { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ThrowableItemProjectileMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ThrowableItemProjectileMixin_API.java index 7078f1afbeb..4c837849ac9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ThrowableItemProjectileMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ThrowableItemProjectileMixin_API.java @@ -24,15 +24,15 @@ */ package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile; -import net.minecraft.world.entity.projectile.ThrowableItemProjectile; import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.entity.projectile.ThrowableItemProjectile; import org.spongepowered.asm.mixin.Mixin; import java.util.Set; -@Mixin(ThrowableItemProjectile.class) -public abstract class ThrowableItemProjectileMixin_API extends ThrowableProjectileMixin_API { +@Mixin(net.minecraft.world.entity.projectile.ThrowableItemProjectile.class) +public abstract class ThrowableItemProjectileMixin_API extends ThrowableProjectileMixin_API implements ThrowableItemProjectile { @Override protected Set> api$getVanillaValues() { From 59d7fd5ec810bb51ba4807d48e653d4a61d43a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossi=20Erkkil=C3=A4?= <52257907+avaruus1@users.noreply.github.com> Date: Sun, 7 Jul 2024 12:57:56 +0300 Subject: [PATCH 133/226] Implement Attribute#removeModifier(ResourceKey) (#4076) --- .../entity/ai/attributes/AttributeInstanceMixin_API.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java index 2d00107ceb0..214bcf05b37 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/ai/attributes/AttributeInstanceMixin_API.java @@ -59,6 +59,7 @@ public abstract class AttributeInstanceMixin_API implements Attribute { @Shadow public abstract double shadow$getValue(); @Shadow protected abstract void shadow$addModifier(net.minecraft.world.entity.ai.attributes.AttributeModifier modifier); @Shadow public abstract void shadow$removeModifier(net.minecraft.world.entity.ai.attributes.AttributeModifier modifier); + @Shadow public abstract boolean shadow$removeModifier(ResourceLocation $$0); @Shadow abstract Map shadow$getModifiers(net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation p_225504_1_); @Shadow public abstract Set shadow$getModifiers(); @Shadow public abstract boolean shadow$hasModifier(final ResourceLocation $$0); @@ -111,6 +112,11 @@ public void removeModifier(final AttributeModifier modifier) { this.shadow$removeModifier((net.minecraft.world.entity.ai.attributes.AttributeModifier) (Object) Objects.requireNonNull(modifier, "modifier")); } + @Override + public void removeModifier(ResourceKey key) { + this.shadow$removeModifier((ResourceLocation) (Object) key); + } + @Override public Optional modifier(final ResourceKey key) { return Optional.ofNullable((AttributeModifier) (Object) this.shadow$getModifier((ResourceLocation) (Object) Objects.requireNonNull(key, "uniqueId"))); From 7065851a4c2aec1fc8a145739ba809d66b79564b Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 7 Jul 2024 13:33:04 +0000 Subject: [PATCH 134/226] Add missing EnemyMixin_API (#4083) --- .../world/entity/monster/EnemyMixin_API.java | 33 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/EnemyMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/EnemyMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/EnemyMixin_API.java new file mode 100644 index 00000000000..49b6963f3e1 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/monster/EnemyMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.monster; + +import net.minecraft.world.entity.monster.Enemy; +import org.spongepowered.api.entity.living.Hostile; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Enemy.class) +public interface EnemyMixin_API extends Hostile { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 5b86372416f..cbf5f0d779e 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -219,6 +219,7 @@ "minecraft.world.entity.monster.ElderGuardianMixin_API", "minecraft.world.entity.monster.EnderManMixin_API", "minecraft.world.entity.monster.EndermiteMixin_API", + "minecraft.world.entity.monster.EnemyMixin_API", "minecraft.world.entity.monster.EvokerMixin_API", "minecraft.world.entity.monster.GhastMixin_API", "minecraft.world.entity.monster.GiantMixin_API", From 95bccf43b3db0abbfe7a9929264d9c4bbc1a7164 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 7 Jul 2024 13:33:35 +0000 Subject: [PATCH 135/226] Add missing FlyingAnimalMixin_API (#4084) --- .../entity/animal/FlyingAnimalMixin_API.java | 33 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/FlyingAnimalMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/FlyingAnimalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/FlyingAnimalMixin_API.java new file mode 100644 index 00000000000..0d566309c56 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/animal/FlyingAnimalMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.animal; + +import net.minecraft.world.entity.animal.FlyingAnimal; +import org.spongepowered.api.entity.Aerial; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(FlyingAnimal.class) +public interface FlyingAnimalMixin_API extends Aerial { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index cbf5f0d779e..1e45e3db5c4 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -145,6 +145,7 @@ "minecraft.world.entity.animal.CodMixin_API", "minecraft.world.entity.animal.CowMixin_API", "minecraft.world.entity.animal.DolphinMixin_API", + "minecraft.world.entity.animal.FlyingAnimalMixin_API", "minecraft.world.entity.animal.Fox_TypeMixin_API", "minecraft.world.entity.animal.FoxMixin_API", "minecraft.world.entity.animal.IronGolemMixin_API", From 971ae89aa7f0cbf663a320ab97ca2c74668115ab Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Fri, 5 Jul 2024 19:16:19 +0700 Subject: [PATCH 136/226] Implement BossBarViewer & BossBar#viewers() --- SpongeAPI | 2 +- .../BossBarImplementationProviderImpl.java | 61 +++++++++++++++ .../adventure/VanillaBossBarListener.java | 76 ------------------- .../bridge/adventure/BossBarBridge.java | 5 ++ .../common/bridge/world/BossEventBridge.java | 2 +- .../world/entity/player/PlayerBridge.java | 8 ++ ...ure.bossbar.BossBarImplementation$Provider | 1 + .../world/entity/player/PlayerMixin_API.java | 9 +++ .../HackyBossBarPlatformBridgeMixin.java | 20 ++++- .../server/level/ServerBossEventMixin.java | 38 ++++++---- .../mixin/core/world/BossEventMixin.java | 7 +- .../core/world/entity/player/PlayerMixin.java | 21 +++++ 12 files changed, 151 insertions(+), 99 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/adventure/BossBarImplementationProviderImpl.java delete mode 100644 src/main/java/org/spongepowered/common/adventure/VanillaBossBarListener.java create mode 100644 src/main/resources/META-INF/services/net.kyori.adventure.bossbar.BossBarImplementation$Provider diff --git a/SpongeAPI b/SpongeAPI index b4fab131ee0..de8ffbad766 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit b4fab131ee01192ae3d6fa9bf33cdc2dc2af9076 +Subproject commit de8ffbad766ae84bea5dcd8d65be67806c07804a diff --git a/src/main/java/org/spongepowered/common/adventure/BossBarImplementationProviderImpl.java b/src/main/java/org/spongepowered/common/adventure/BossBarImplementationProviderImpl.java new file mode 100644 index 00000000000..41a217e200e --- /dev/null +++ b/src/main/java/org/spongepowered/common/adventure/BossBarImplementationProviderImpl.java @@ -0,0 +1,61 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.adventure; + +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.bossbar.BossBarImplementation; +import net.kyori.adventure.bossbar.BossBarViewer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; + +import java.util.Collection; + +@SuppressWarnings("UnstableApiUsage") // permitted provider +public final class BossBarImplementationProviderImpl implements BossBarImplementation.Provider { + + public static void assignImplementation(final BossBar bar) { + // Triggers BossBarImplementation field assigning in BossBarImpl + BossBarImplementation.get(bar, BossBarImplementation.class); + } + + @Override + public @NonNull BossBarImplementation create(final @NonNull BossBar bar) { + return new BossBarImplementationImpl(bar); + } + + private static final class BossBarImplementationImpl implements BossBarImplementation { + + private final Collection unmodifiableViewers; + + private BossBarImplementationImpl(final @NonNull BossBar bar) { + this.unmodifiableViewers = (Collection) (Object) SpongeAdventure.asVanillaServer(bar).getPlayers(); + } + + @Override + public @NonNull Iterable viewers() { + return this.unmodifiableViewers; + } + } +} diff --git a/src/main/java/org/spongepowered/common/adventure/VanillaBossBarListener.java b/src/main/java/org/spongepowered/common/adventure/VanillaBossBarListener.java deleted file mode 100644 index 0ce9cb9c761..00000000000 --- a/src/main/java/org/spongepowered/common/adventure/VanillaBossBarListener.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.adventure; - -import net.kyori.adventure.bossbar.BossBar; -import net.kyori.adventure.text.Component; -import net.minecraft.network.protocol.game.ClientboundBossEventPacket; -import net.minecraft.server.level.ServerBossEvent; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.BossEvent; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.Set; -import java.util.function.Function; - -public final class VanillaBossBarListener implements BossBar.Listener { - private final ServerBossEvent vanilla; - - public VanillaBossBarListener(final ServerBossEvent vanilla) { - this.vanilla = vanilla; - } - - @Override - public void bossBarNameChanged(final @NonNull BossBar bar, final @NonNull Component oldName, final @NonNull Component newName) { - this.sendPacket(ClientboundBossEventPacket::createUpdateNamePacket); - } - - @Override - public void bossBarProgressChanged(final @NonNull BossBar bar, final float oldProgress, final float newProgress) { - this.sendPacket(ClientboundBossEventPacket::createUpdateProgressPacket); - } - - @Override - public void bossBarColorChanged(final @NonNull BossBar bar, final BossBar.@NonNull Color oldColor, final BossBar.@NonNull Color newColor) { - this.sendPacket(ClientboundBossEventPacket::createUpdateStylePacket); - } - - @Override - public void bossBarOverlayChanged(final @NonNull BossBar bar, final BossBar.@NonNull Overlay oldOverlay, final BossBar.@NonNull Overlay newOverlay) { - this.sendPacket(ClientboundBossEventPacket::createUpdateStylePacket); - } - - @Override - public void bossBarFlagsChanged(final @NonNull BossBar bar, final @NonNull Set flagsAdded, final @NonNull Set flagsRemoved) { - this.sendPacket(ClientboundBossEventPacket::createUpdatePropertiesPacket); - } - - private void sendPacket(final Function action) { - final ClientboundBossEventPacket packet = action.apply(this.vanilla); - for (final ServerPlayer player : this.vanilla.getPlayers()) { - player.connection.send(packet); - } - } -} diff --git a/src/main/java/org/spongepowered/common/bridge/adventure/BossBarBridge.java b/src/main/java/org/spongepowered/common/bridge/adventure/BossBarBridge.java index 724de316bcb..e3639e96198 100644 --- a/src/main/java/org/spongepowered/common/bridge/adventure/BossBarBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/adventure/BossBarBridge.java @@ -25,8 +25,13 @@ package org.spongepowered.common.bridge.adventure; import net.minecraft.server.level.ServerBossEvent; +import net.minecraft.world.BossEvent; public interface BossBarBridge { ServerBossEvent bridge$asVanillaServerBar(); + + void bridge$setVanilla(BossEvent vanilla); + + void bridge$assignImplementation(); } diff --git a/src/main/java/org/spongepowered/common/bridge/world/BossEventBridge.java b/src/main/java/org/spongepowered/common/bridge/world/BossEventBridge.java index c574233f5e8..9b3381f312c 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/BossEventBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/BossEventBridge.java @@ -33,7 +33,7 @@ public interface BossEventBridge { * * @param adventure adventure boss bar */ - void bridge$copyAndAssign(BossBar adventure); + void bridge$copy(BossBar adventure); BossBar bridge$asAdventure(); diff --git a/src/main/java/org/spongepowered/common/bridge/world/entity/player/PlayerBridge.java b/src/main/java/org/spongepowered/common/bridge/world/entity/player/PlayerBridge.java index d5a02fbf7ed..9fc379537ab 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/entity/player/PlayerBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/entity/player/PlayerBridge.java @@ -24,6 +24,8 @@ */ package org.spongepowered.common.bridge.world.entity.player; +import net.kyori.adventure.bossbar.BossBar; + public interface PlayerBridge { boolean bridge$affectsSpawning(); @@ -35,4 +37,10 @@ public interface PlayerBridge { int bridge$getExperienceSinceLevel(); void bridge$setExperienceSinceLevel(int experience); + + Iterable bridge$getActiveBossBars(); + + void bridge$addActiveBossBar(BossBar bar); + + void bridge$removeActiveBossBar(BossBar bar); } diff --git a/src/main/resources/META-INF/services/net.kyori.adventure.bossbar.BossBarImplementation$Provider b/src/main/resources/META-INF/services/net.kyori.adventure.bossbar.BossBarImplementation$Provider new file mode 100644 index 00000000000..975f75ab21d --- /dev/null +++ b/src/main/resources/META-INF/services/net.kyori.adventure.bossbar.BossBarImplementation$Provider @@ -0,0 +1 @@ +org.spongepowered.common.adventure.BossBarImplementationProviderImpl diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java index afb59e418aa..2bbe326bdf1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/player/PlayerMixin_API.java @@ -25,6 +25,7 @@ package org.spongepowered.common.mixin.api.minecraft.world.entity.player; import com.mojang.authlib.GameProfile; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.identity.Identified; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.inventory.Book; @@ -44,6 +45,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.bridge.effect.ViewerBridge; import org.spongepowered.common.bridge.world.entity.PlatformEntityBridge; +import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; import org.spongepowered.common.effect.SpongeViewer; import org.spongepowered.common.effect.util.ViewerPacketUtil; import org.spongepowered.common.mixin.api.minecraft.world.entity.LivingEntityMixin_API; @@ -156,4 +158,11 @@ public void playSound(final Sound sound, final Sound.Emitter emitter) { public void openBook(final Book book) { ((ViewerBridge) this).bridge$sendToViewer(BookUtil.createFakeBookViewPacket(this, Objects.requireNonNull(book, "book"))); } + + // BossBarViewer + + @Override + public Iterable activeBossBars() { + return ((PlayerBridge) this).bridge$getActiveBossBars(); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/adventure/bossbar/HackyBossBarPlatformBridgeMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/adventure/bossbar/HackyBossBarPlatformBridgeMixin.java index 44fb0025a5e..81b02c109e1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/adventure/bossbar/HackyBossBarPlatformBridgeMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/adventure/bossbar/HackyBossBarPlatformBridgeMixin.java @@ -26,9 +26,10 @@ import net.kyori.adventure.bossbar.BossBar; import net.minecraft.server.level.ServerBossEvent; +import net.minecraft.world.BossEvent; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.common.adventure.BossBarImplementationProviderImpl; import org.spongepowered.common.adventure.SpongeAdventure; -import org.spongepowered.common.adventure.VanillaBossBarListener; import org.spongepowered.common.bridge.adventure.BossBarBridge; import org.spongepowered.common.bridge.world.BossEventBridge; @@ -43,9 +44,22 @@ public abstract class HackyBossBarPlatformBridgeMixin implements BossBarBridge { final BossBar $this = (BossBar) this; this.bridge$vanillaServerBar = new ServerBossEvent(SpongeAdventure.asVanilla($this.name()), SpongeAdventure.asVanilla($this.color()), SpongeAdventure.asVanilla($this.overlay())); final BossEventBridge bridge = (BossEventBridge) this.bridge$vanillaServerBar; - bridge.bridge$copyAndAssign($this); - $this.addListener(new VanillaBossBarListener(this.bridge$vanillaServerBar)); + bridge.bridge$copy($this); + bridge.bridge$setAdventure($this); + this.bridge$assignImplementation(); } return this.bridge$vanillaServerBar; } + + @Override + public void bridge$setVanilla(final BossEvent vanilla) { + if (vanilla instanceof final ServerBossEvent vanillaServer) { + this.bridge$vanillaServerBar = vanillaServer; + } + } + + @Override + public void bridge$assignImplementation() { + BossBarImplementationProviderImpl.assignImplementation((BossBar) this); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerBossEventMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerBossEventMixin.java index c407ad14cf7..0568e95b278 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerBossEventMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerBossEventMixin.java @@ -39,6 +39,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.adventure.SpongeAdventure; +import org.spongepowered.common.bridge.world.entity.player.PlayerBridge; import org.spongepowered.common.mixin.core.world.BossEventMixin; import java.util.Set; @@ -57,28 +58,24 @@ public abstract class ServerBossEventMixin extends BossEventMixin implements Bos @Override public void bridge$setAdventure(final BossBar adventure) { - final BossBar oldAdventure = this.impl$adventure; super.bridge$setAdventure(adventure); - if (oldAdventure != adventure) { - if (oldAdventure != null) { - oldAdventure.removeListener(this); // TODO(adventure): how to update viewers? - } - adventure.addListener(this); - - // Apply invalid data where possible, avoid sameness checks - this.name = null; - this.progress = Float.MIN_VALUE; - this.color = null; - this.overlay = null; - // flags have to be done separately - } + adventure.addListener(this); + + // Apply invalid data where possible, avoid sameness checks + this.name = null; + this.progress = Float.MIN_VALUE; + this.color = null; + this.overlay = null; + // flags have to be done separately } @Override public void bridge$replacePlayer(final ServerPlayer oldPlayer, final ServerPlayer newPlayer) { super.bridge$replacePlayer(oldPlayer, newPlayer); - if(this.players.remove(oldPlayer)) { + if (this.players.remove(oldPlayer)) { this.players.add(newPlayer); + ((PlayerBridge) oldPlayer).bridge$removeActiveBossBar(this.bridge$asAdventure()); + ((PlayerBridge) newPlayer).bridge$addActiveBossBar(this.bridge$asAdventure()); } } @@ -140,6 +137,10 @@ public void bossBarFlagsChanged(final BossBar bar, final Set flags if (!this.players.isEmpty() && this.visible) { SpongeAdventure.registerBossBar((ServerBossEvent) (Object) this); } + + if (this.visible) { + ((PlayerBridge) player).bridge$addActiveBossBar(this.bridge$asAdventure()); + } } @Inject(method = "removePlayer", at = @At("TAIL")) @@ -147,6 +148,10 @@ public void bossBarFlagsChanged(final BossBar bar, final Set flags if (this.players.isEmpty()) { SpongeAdventure.unregisterBossBar((ServerBossEvent) (Object) this); } + + if (this.visible) { + ((PlayerBridge) player).bridge$removeActiveBossBar(this.bridge$asAdventure()); + } } @Inject(method = "removeAllPlayers", at = @At("HEAD")) @@ -157,10 +162,13 @@ public void bossBarFlagsChanged(final BossBar bar, final Set flags @Inject(method = "setVisible", at = @At("HEAD")) private void impl$setVisible(final boolean visible, final CallbackInfo ci) { if (!this.players.isEmpty()) { + final BossBar bar = this.bridge$asAdventure(); if (visible) { SpongeAdventure.registerBossBar((ServerBossEvent) (Object) this); + this.players.forEach(player -> ((PlayerBridge) player).bridge$addActiveBossBar(bar)); } else { SpongeAdventure.unregisterBossBar((ServerBossEvent) (Object) this); + this.players.forEach(player -> ((PlayerBridge) player).bridge$removeActiveBossBar(bar)); } } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/BossEventMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/BossEventMixin.java index 6f47e81813a..976e1b2bb29 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/BossEventMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/BossEventMixin.java @@ -33,6 +33,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.common.adventure.SpongeAdventure; +import org.spongepowered.common.bridge.adventure.BossBarBridge; import org.spongepowered.common.bridge.world.BossEventBridge; @Mixin(BossEvent.class) @@ -49,9 +50,7 @@ public abstract class BossEventMixin implements BossEventBridge { protected BossBar impl$adventure; @Override - public void bridge$copyAndAssign(final BossBar adventure) { - this.impl$adventure = adventure; - this.progress = adventure.progress(); + public void bridge$copy(final BossBar adventure) { this.darkenScreen = adventure.hasFlag(BossBar.Flag.DARKEN_SCREEN); this.playBossMusic = adventure.hasFlag(BossBar.Flag.PLAY_BOSS_MUSIC); this.createWorldFog = adventure.hasFlag(BossBar.Flag.CREATE_WORLD_FOG); @@ -67,6 +66,8 @@ public abstract class BossEventMixin implements BossEventBridge { SpongeAdventure.asAdventure(this.overlay), SpongeAdventure.asAdventureFlags(this.darkenScreen, this.playBossMusic, this.createWorldFog) )); + ((BossBarBridge) this.impl$adventure).bridge$setVanilla((BossEvent) (Object) this); + ((BossBarBridge) this.impl$adventure).bridge$assignImplementation(); } return this.impl$adventure; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java index 6a3aa2c542f..59860310fb6 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin.java @@ -26,6 +26,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; +import net.kyori.adventure.bossbar.BossBar; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -85,7 +86,9 @@ import org.spongepowered.common.util.ExperienceHolderUtil; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; @Mixin(net.minecraft.world.entity.player.Player.class) public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBridge, GameProfileHolderBridge, ViewerBridge { @@ -119,6 +122,9 @@ public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBri private boolean impl$affectsSpawning = true; protected final boolean impl$isFake = this.bridge$isFakePlayer(); + private final Set impl$activeBossBars = new HashSet<>(); + private final Set impl$unmodifiableActiveBossBars = Collections.unmodifiableSet(this.impl$activeBossBars); + @Override public boolean bridge$affectsSpawning() { return this.impl$affectsSpawning && !this.shadow$isSpectator() && !this.bridge$vanishState().untargetable(); @@ -145,6 +151,21 @@ public abstract class PlayerMixin extends LivingEntityMixin implements PlayerBri this.experienceProgress = (float) experience / this.shadow$getXpNeededForNextLevel(); } + @Override + public Iterable bridge$getActiveBossBars() { + return this.impl$unmodifiableActiveBossBars; + } + + @Override + public void bridge$addActiveBossBar(final BossBar bar) { + this.impl$activeBossBars.add(bar); + } + + @Override + public void bridge$removeActiveBossBar(final BossBar bar) { + this.impl$activeBossBars.remove(bar); + } + @Redirect( method = "aiStep", at = @At( From 13a444ef4562ee4a560ed842fb5b2ad6cfaea922 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Fri, 5 Jul 2024 12:55:48 +0700 Subject: [PATCH 137/226] Remove manual update of bossbars locale --- .../common/mixin/core/server/level/ServerPlayerMixin.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index d55c5a50597..73fcb2a228c 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -39,7 +39,6 @@ import net.minecraft.network.chat.OutgoingChatMessage; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.protocol.game.ClientboundBossEventPacket; import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; import net.minecraft.network.protocol.game.ClientboundGameEventPacket; import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; @@ -279,12 +278,6 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr final Channel channel = ((ConnectionAccessor) ((ServerCommonPacketListenerImplAccessor) this.connection).accessor$connection()).accessor$channel(); channel.attr(SpongeAdventure.CHANNEL_LOCALE).set(language); - SpongeAdventure.forEachBossBar(bar -> { - if (bar.getPlayers().contains(this)) { - this.connection.send(ClientboundBossEventPacket.createUpdateNamePacket(bar)); - } - }); - this.containerMenu.broadcastFullState(); } } From f2ca53f67e33c313997f3e9ea5a896ce58a909e2 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 7 Jul 2024 16:08:02 +0000 Subject: [PATCH 138/226] Add missing ItemSupplierMixin_API (#4085) --- .../projectile/ItemSupplierMixin_API.java | 33 +++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ItemSupplierMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ItemSupplierMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ItemSupplierMixin_API.java new file mode 100644 index 00000000000..90979226eea --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/projectile/ItemSupplierMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity.projectile; + +import net.minecraft.world.entity.projectile.ItemSupplier; +import org.spongepowered.api.entity.ItemRepresentable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(ItemSupplier.class) +public interface ItemSupplierMixin_API extends ItemRepresentable { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 1e45e3db5c4..e09ffde7763 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -275,6 +275,7 @@ "minecraft.world.entity.projectile.FireballMixin_API", "minecraft.world.entity.projectile.FireworkRocketEntityMixin_API", "minecraft.world.entity.projectile.FishingHookMixin_API", + "minecraft.world.entity.projectile.ItemSupplierMixin_API", "minecraft.world.entity.projectile.LargeFireballMixin_API", "minecraft.world.entity.projectile.LlamaSpitMixin_API", "minecraft.world.entity.projectile.ProjectileMixin_API", From b3c486887f7dfbbfd4be1f5465b9e8b4db5b8fad Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Sun, 7 Jul 2024 18:27:58 +0200 Subject: [PATCH 139/226] wrap null ContainerType fixes #3925 --- SpongeAPI | 2 +- .../api/inventory/container/ContainerMixin_Inventory_API.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index de8ffbad766..96e3b65cb71 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit de8ffbad766ae84bea5dcd8d65be67806c07804a +Subproject commit 96e3b65cb7135c445e9fa1ea384247e108c1930b diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java index 5f169c84429..b553b02a922 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java @@ -121,8 +121,8 @@ public boolean isOpen() { } @Override - public ContainerType type() { - return ((ContainerType) this.menuType); + public Optional type() { + return Optional.ofNullable((ContainerType) this.menuType); } private List listeners() { From 1cffbd1b1a7658bf0b3412610c4adb1642758099 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 7 Jul 2024 16:32:32 +0000 Subject: [PATCH 140/226] Bump SpongeAPI and update mixins (#4086) * Add missing Mixin_API after API bump * run spotlessApply --- .../world/entity/AttackableMixin_API.java | 32 ++++++++++++++++++ .../world/entity/LeashableMixin_API.java | 32 ++++++++++++++++++ .../world/entity/NeutralMobMixin_API.java | 33 +++++++++++++++++++ .../world/entity/PowerableMobMixin_API.java | 33 +++++++++++++++++++ .../world/entity/TargetingMixin_API.java | 32 ++++++++++++++++++ src/mixins/resources/mixins.sponge.api.json | 5 +++ 6 files changed, 167 insertions(+) create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AttackableMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/LeashableMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/NeutralMobMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PowerableMobMixin_API.java create mode 100644 src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TargetingMixin_API.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AttackableMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AttackableMixin_API.java new file mode 100644 index 00000000000..417716493d7 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/AttackableMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.Attackable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.Attackable.class) +public interface AttackableMixin_API extends Attackable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/LeashableMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/LeashableMixin_API.java new file mode 100644 index 00000000000..6d90250a698 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/LeashableMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.Leashable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.Leashable.class) +public interface LeashableMixin_API extends Leashable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/NeutralMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/NeutralMobMixin_API.java new file mode 100644 index 00000000000..e46b96bc1a0 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/NeutralMobMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import net.minecraft.world.entity.NeutralMob; +import org.spongepowered.api.entity.Angerable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(NeutralMob.class) +public interface NeutralMobMixin_API extends Angerable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PowerableMobMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PowerableMobMixin_API.java new file mode 100644 index 00000000000..47588fb4481 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/PowerableMobMixin_API.java @@ -0,0 +1,33 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import net.minecraft.world.entity.PowerableMob; +import org.spongepowered.api.entity.Chargeable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(PowerableMob.class) +public interface PowerableMobMixin_API extends Chargeable { +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TargetingMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TargetingMixin_API.java new file mode 100644 index 00000000000..8a13f742db9 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/TargetingMixin_API.java @@ -0,0 +1,32 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.entity; + +import org.spongepowered.api.entity.Targeting; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(net.minecraft.world.entity.Targeting.class) +public interface TargetingMixin_API extends Targeting { +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index e09ffde7763..fc1ac639d46 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -91,6 +91,7 @@ "minecraft.world.effect.MobEffectMixin_API", "minecraft.world.entity.AgeableMobMixin_API", "minecraft.world.entity.AreaEffectCloudMixin_API", + "minecraft.world.entity.AttackableMixin_API", "minecraft.world.entity.Display_BillboardConstraintsMixin_API", "minecraft.world.entity.Display_BlockDisplayMixin_API", "minecraft.world.entity.Display_ItemDisplayMixin_API", @@ -104,17 +105,21 @@ "minecraft.world.entity.GlowSquidMixin_API", "minecraft.world.entity.HumanoidArmMixin_API", "minecraft.world.entity.InteractionMixin_API", + "minecraft.world.entity.LeashableMixin_API", "minecraft.world.entity.LightningBoltMixin_API", "minecraft.world.entity.LivingEntityMixin_API", "minecraft.world.entity.MarkerMixin_API", "minecraft.world.entity.MobCategoryMixin_API", "minecraft.world.entity.MobMixin_API", + "minecraft.world.entity.NeutralMobMixin_API", "minecraft.world.entity.OminousItemSpawnerMixin_API", "minecraft.world.entity.OwnableEntityMixin_API", "minecraft.world.entity.PathfinderMobMixin_API", "minecraft.world.entity.PortalProcessorMixin_API", + "minecraft.world.entity.PowerableMobMixin_API", "minecraft.world.entity.SaddleableMixin_API", "minecraft.world.entity.TamableAnimalMixin_API", + "minecraft.world.entity.TargetingMixin_API", "minecraft.world.entity.ai.attributes.AttributeInstanceMixin_API", "minecraft.world.entity.ai.attributes.AttributeMixin_API", "minecraft.world.entity.ai.attributes.AttributeModifier_OperationMixin_API", From 6f5cc47cd64cbaf4b424771c0f3c5e4b024ef514 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Sun, 7 Jul 2024 16:45:47 +0000 Subject: [PATCH 141/226] Update validationtest plugin (#4087) * Update validationtest plugin * run spotlessApply --- .../test/validation/ValidationTest.java | 438 ++++++++++++------ 1 file changed, 303 insertions(+), 135 deletions(-) diff --git a/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java b/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java index 939cd396b8c..8fcdae3f1f6 100644 --- a/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/validation/ValidationTest.java @@ -30,12 +30,96 @@ import org.spongepowered.api.command.Command; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.effect.Viewer; +import org.spongepowered.api.entity.Aerial; +import org.spongepowered.api.entity.Ageable; +import org.spongepowered.api.entity.Angerable; +import org.spongepowered.api.entity.Breedable; +import org.spongepowered.api.entity.Chargeable; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.FallingBlock; +import org.spongepowered.api.entity.Item; +import org.spongepowered.api.entity.ItemRepresentable; +import org.spongepowered.api.entity.Ownable; +import org.spongepowered.api.entity.Ranger; +import org.spongepowered.api.entity.Tamer; +import org.spongepowered.api.entity.attribute.AttributeHolder; +import org.spongepowered.api.entity.display.DisplayEntity; +import org.spongepowered.api.entity.explosive.Explosive; +import org.spongepowered.api.entity.explosive.fused.FusedExplosive; +import org.spongepowered.api.entity.hanging.Hanging; +import org.spongepowered.api.entity.hanging.LeashKnot; +import org.spongepowered.api.entity.living.Agent; +import org.spongepowered.api.entity.living.Ambient; +import org.spongepowered.api.entity.living.ComplexLiving; +import org.spongepowered.api.entity.living.Hostile; +import org.spongepowered.api.entity.living.Humanoid; +import org.spongepowered.api.entity.living.Living; +import org.spongepowered.api.entity.living.PathfinderAgent; +import org.spongepowered.api.entity.living.RangedAgent; +import org.spongepowered.api.entity.living.animal.Sittable; +import org.spongepowered.api.entity.living.animal.TameableAnimal; +import org.spongepowered.api.entity.living.animal.cow.Mooshroom; +import org.spongepowered.api.entity.living.animal.horse.HorseLike; +import org.spongepowered.api.entity.living.animal.horse.PackHorse; +import org.spongepowered.api.entity.living.aquatic.Aquatic; +import org.spongepowered.api.entity.living.aquatic.fish.Fish; +import org.spongepowered.api.entity.living.aquatic.fish.school.SchoolingFish; +import org.spongepowered.api.entity.living.golem.Golem; +import org.spongepowered.api.entity.living.monster.Patroller; +import org.spongepowered.api.entity.living.monster.boss.Boss; +import org.spongepowered.api.entity.living.monster.boss.Wither; +import org.spongepowered.api.entity.living.monster.piglin.PiglinLike; +import org.spongepowered.api.entity.living.monster.raider.illager.Illager; +import org.spongepowered.api.entity.living.monster.raider.illager.spellcaster.Spellcaster; +import org.spongepowered.api.entity.living.monster.skeleton.SkeletonLike; +import org.spongepowered.api.entity.living.trader.VillagerLike; +import org.spongepowered.api.entity.projectile.AcceleratingProjectile; +import org.spongepowered.api.entity.projectile.Egg; +import org.spongepowered.api.entity.projectile.EnderPearl; +import org.spongepowered.api.entity.projectile.ExperienceBottle; +import org.spongepowered.api.entity.projectile.FishingBobber; +import org.spongepowered.api.entity.projectile.IgnitingProjectile; +import org.spongepowered.api.entity.projectile.Potion; +import org.spongepowered.api.entity.projectile.Projectile; +import org.spongepowered.api.entity.projectile.arrow.ArrowLike; +import org.spongepowered.api.entity.projectile.arrow.Trident; +import org.spongepowered.api.entity.projectile.explosive.FireworkRocket; +import org.spongepowered.api.entity.projectile.explosive.fireball.ExplosiveFireball; +import org.spongepowered.api.entity.projectile.windcharge.WindChargeLike; +import org.spongepowered.api.entity.vehicle.Vehicle; +import org.spongepowered.api.entity.vehicle.minecart.BlockOccupiedMinecart; +import org.spongepowered.api.entity.vehicle.minecart.CommandBlockMinecart; +import org.spongepowered.api.entity.vehicle.minecart.FurnaceMinecart; +import org.spongepowered.api.entity.vehicle.minecart.MinecartLike; +import org.spongepowered.api.entity.vehicle.minecart.SpawnerMinecart; +import org.spongepowered.api.entity.vehicle.minecart.TNTMinecart; +import org.spongepowered.api.entity.vehicle.minecart.carrier.CarrierMinecart; +import org.spongepowered.api.entity.vehicle.minecart.carrier.ChestMinecart; +import org.spongepowered.api.entity.vehicle.minecart.carrier.HopperMinecart; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.item.inventory.ArmorEquipable; +import org.spongepowered.api.item.inventory.Carrier; +import org.spongepowered.api.item.inventory.Equipable; +import org.spongepowered.api.item.inventory.Inventory; +import org.spongepowered.api.item.inventory.type.CarriedInventory; +import org.spongepowered.api.item.inventory.type.ViewableInventory; +import org.spongepowered.api.projectile.source.EntityProjectileSource; +import org.spongepowered.api.projectile.source.ProjectileSource; import org.spongepowered.api.registry.DefaultedRegistryReference; import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.scoreboard.TeamMember; +import org.spongepowered.api.service.context.Contextual; +import org.spongepowered.api.service.permission.Subject; +import org.spongepowered.api.spawner.Spawner; +import org.spongepowered.api.util.Identifiable; +import org.spongepowered.api.util.Nameable; +import org.spongepowered.api.util.RandomProvider; import org.spongepowered.api.util.annotation.CatalogedBy; +import org.spongepowered.api.util.locale.LocaleSource; +import org.spongepowered.api.world.Locatable; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; import org.spongepowered.test.LoadableModule; @@ -46,10 +130,9 @@ import java.lang.reflect.ParameterizedType; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; +import java.util.IdentityHashMap; import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -98,7 +181,7 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent registryType) { + if (registryField instanceof final DefaultedRegistryType registryType) { if (registryType.find().isEmpty()) { this.logger.error("Registry {} is empty", registryType.location()); continue; @@ -119,24 +202,24 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent !Modifier.isPrivate(ctor.getModifiers()))) { - this.logger.error("{} has non-private constructors", catalogClass.getSimpleName()); + this.logger.error("{} has non-private constructors", catalogClass.getName()); } final Method registryMethod; try { registryMethod = catalogClass.getDeclaredMethod("registry"); } catch (final NoSuchMethodException e) { - this.logger.error("{}.registry() does not exist", catalogClass.getSimpleName()); + this.logger.error("{}.registry() does not exist", catalogClass.getName()); continue; } @@ -144,7 +227,7 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent reference) { + if (catalogObj instanceof final DefaultedRegistryReference reference) { if (reference.find().isEmpty()) { - this.logger.error("{}.{}.find() is empty", catalogClass.getSimpleName(), catalogField.getName()); + this.logger.error("{}.{}.find() is empty", catalogClass.getName(), catalogField.getName()); } } } @@ -184,6 +267,7 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent> seen = Collections.newSetFromMap(new IdentityHashMap<>()); for (final Field field : entityTypeClass.getDeclaredFields()) { if (!field.getType().getSimpleName().equals("EntityType")) { - if (this.verbose) { - this.logger.info("Skipping field {} of type {}", field.getName(), field.getType().getSimpleName()); - } continue; } @@ -222,142 +305,224 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent) typeArg) - .filter(clazz -> clazz.getPackageName().startsWith("org.spongepowered.api") || clazz.getPackageName().startsWith("net.minecraft")) - .filter(clazz -> !clazz.getPackageName().startsWith("org.spongepowered.api.data")) - .filter(clazz -> !clazz.getPackageName().startsWith("org.spongepowered.api.item.inventory")) - .filter(clazz -> !clazz.getPackageName().startsWith("net.minecraft.commands")) - .filter(clazz -> !clazz.getPackageName().startsWith("net.minecraft.network")) - .filter(clazz -> !unknownClasses.contains(clazz.getName())) - .distinct() - .collect(Collectors.groupingBy( - clazz -> { - if (clazz.getPackageName().startsWith("net.minecraft")) { - return mc; - } - if (clazz.getPackageName().startsWith("org.spongepowered")) { - return sponge; - } - return ""; - } - )); - - final var mcInterfaces = interfaces.getOrDefault(mc, Collections.emptyList()); - mcInterfaces.sort(Comparator.comparing(Class::getSimpleName)); - - final var spongeInterfaces = interfaces.getOrDefault(sponge, Collections.emptyList()); - spongeInterfaces.sort(Comparator.comparing(Class::getSimpleName)); - - final var mcToSpongeMapping = Map.ofEntries( - Map.entry("AbstractArrow", "ArrowEntity"), - Map.entry("AbstractChestedHorse", "PackHorse"), - Map.entry("AbstractFish", "Fish"), - Map.entry("AbstractGolem", "Golem"), - Map.entry("AbstractHorse", "HorseLike"), - Map.entry("AbstractHurtingProjectile", "DamagingProjectile"), - Map.entry("AbstractIllager", "Illager"), - Map.entry("AbstractMinecart", "MinecartLike"), - Map.entry("AbstractMinecartContainer", "CarrierMinecart"), - Map.entry("AbstractSchoolingFish", "SchoolingFish"), - Map.entry("AbstractSkeleton", "SkeletonLike"), - Map.entry("AbstractVillager", "Trader"), - Map.entry("AbstractWindCharge", "WindChargeLike"), - Map.entry("AgeableMob", "Ageable"), - Map.entry("BlockAttachedEntity", "Hanging"), - Map.entry("Display", "DisplayEntity"), - Map.entry("FallingBlockEntity", "FallingBlock"), - Map.entry("Fireball", "FireballEntity"), - Map.entry("FireworkRocketEntity", "FireworkRocket"), - Map.entry("FishingHook", "FishingBobber"), - Map.entry("FlyingMob", "Aerial"), - Map.entry("ItemEntity", "Item"), - Map.entry("LargeFireball", "ExplosiveFireball"), - Map.entry("LeashFenceKnotEntity", "LeashKnot"), - Map.entry("LivingEntity", "Living"), - Map.entry("MinecartChest", "ChestMinecart"), - Map.entry("MinecartCommandBlock", "CommandBlockMinecart"), - Map.entry("MinecartFurnace", "FurnaceMinecart"), - Map.entry("MinecartHopper", "HopperMinecart"), - Map.entry("MinecartSpawner", "SpawnerMinecart"), - Map.entry("MinecartTNT", "TNTMinecart"), - Map.entry("Mob", "Agent"), - Map.entry("MushroomCow", "Mooshroom"), - Map.entry("PathfinderMob", "Creature"), - Map.entry("PatrollingMonster", "Patroller"), - Map.entry("SpellcasterIllager", "Spellcaster"), - Map.entry("TamableAnimal", "TameableAnimal"), - Map.entry("ThrownEgg", "Egg"), - Map.entry("ThrownEnderpearl", "EnderPearl"), - Map.entry("ThrownExperienceBottle", "ExperienceBottle"), - Map.entry("ThrownPotion", "Potion"), - Map.entry("ThrownTrident", "Trident"), - Map.entry("WaterAnimal", "Aquatic"), - Map.entry("WitherBoss", "Wither") + final var unmappedSpongeClasses = Set.of( + AttributeHolder.class, + BlockOccupiedMinecart.class, + Boss.class, + ComplexLiving.class, + EntityProjectileSource.class, + FusedExplosive.class, + Humanoid.class, + Identifiable.class, + Nameable.class, + RangedAgent.class, + Tamer.class, + // TODO + ArmorEquipable.class, + Equipable.class, + Explosive.class ); - final AtomicBoolean brokenMapping = new AtomicBoolean(false); - mcToSpongeMapping.forEach((key, value) -> { - if (!mcToSpongeMapping.containsKey(value) && mcInterfaces.stream().anyMatch(c -> c.getSimpleName().equalsIgnoreCase(value))) { - this.logger.error("Duplicat mapping: {}->{} ; {}->{}", key, value, value, value); - brokenMapping.set(true); - } - }); - if (brokenMapping.get()) { - continue; - } + final Map> minecraftToSpongeMapping = Map.ofEntries( + Map.entry("AbstractArrow", ArrowLike.class), + Map.entry("AbstractChestedHorse", PackHorse.class), + Map.entry("AbstractFish", Fish.class), + Map.entry("AbstractGolem", Golem.class), + Map.entry("AbstractHorse", HorseLike.class), + Map.entry("AbstractHurtingProjectile", AcceleratingProjectile.class), + Map.entry("AbstractIllager", Illager.class), + Map.entry("AbstractMinecart", MinecartLike.class), + Map.entry("AbstractMinecartContainer", CarrierMinecart.class), + Map.entry("AbstractPiglin", PiglinLike.class), + Map.entry("AbstractSchoolingFish", SchoolingFish.class), + Map.entry("AbstractSkeleton", SkeletonLike.class), + Map.entry("AbstractVillager", VillagerLike.class), + Map.entry("AbstractWindCharge", WindChargeLike.class), + Map.entry("AgeableMob", Ageable.class), + Map.entry("AmbientCreature", Ambient.class), + Map.entry("BlockAttachedEntity", Hanging.class), + Map.entry("Display", DisplayEntity.class), + Map.entry("Enemy", Hostile.class), + Map.entry("FallingBlockEntity", FallingBlock.class), + Map.entry("Fireball", IgnitingProjectile.class), + Map.entry("FireworkRocketEntity", FireworkRocket.class), + Map.entry("FishingHook", FishingBobber.class), + Map.entry("FlyingAnimal", Aerial.class), + Map.entry("FlyingMob", Aerial.class), + Map.entry("ItemEntity", Item.class), + Map.entry("ItemSupplier", ItemRepresentable.class), + Map.entry("LargeFireball", ExplosiveFireball.class), + Map.entry("LeashFenceKnotEntity", LeashKnot.class), + Map.entry("LivingEntity", Living.class), + Map.entry("MinecartChest", ChestMinecart.class), + Map.entry("MinecartCommandBlock", CommandBlockMinecart.class), + Map.entry("MinecartFurnace", FurnaceMinecart.class), + Map.entry("MinecartHopper", HopperMinecart.class), + Map.entry("MinecartSpawner", SpawnerMinecart.class), + Map.entry("MinecartTNT", TNTMinecart.class), + Map.entry("Mob", Agent.class), + Map.entry("MushroomCow", Mooshroom.class), + Map.entry("NeutralMob", Angerable.class), + Map.entry("OwnableEntity", Ownable.class), + Map.entry("PathfinderMob", PathfinderAgent.class), + Map.entry("PatrollingMonster", Patroller.class), + Map.entry("PowerableMob", Chargeable.class), + Map.entry("RangedAttackMob", Ranger.class), + Map.entry("SpellcasterIllager", Spellcaster.class), + Map.entry("TamableAnimal", TameableAnimal.class), + Map.entry("ThrownEgg", Egg.class), + Map.entry("ThrownEnderpearl", EnderPearl.class), + Map.entry("ThrownExperienceBottle", ExperienceBottle.class), + Map.entry("ThrownPotion", Potion.class), + Map.entry("ThrownTrident", Trident.class), + Map.entry("VehicleEntity", Vehicle.class), + Map.entry("WaterAnimal", Aquatic.class), + Map.entry("WitherBoss", Wither.class) + ); - final var baseClass = mcToSpongeMapping.getOrDefault(((Class) typeArg).getSimpleName(), ((Class) typeArg).getSimpleName()); - if (!spongeInterfaces.removeIf(spongeInterface -> spongeInterface.getSimpleName().equalsIgnoreCase(baseClass))) { - this.logger.error("{} does not implement matching Sponge interface", ((Class) typeArg).getName()); - continue; - } + this.interfacesAndSuperclasses((Class) typeArg) + .filter(clazz -> clazz.getPackageName().startsWith("net.minecraft")) + .forEach(minecraftClass -> { + if (seen.add(minecraftClass)) { + final Set> minecraftClasses = Collections.newSetFromMap(new IdentityHashMap<>()); + final Set> implSpongeClasses = Collections.newSetFromMap(new IdentityHashMap<>()); + + // unrelated to the entity system + final var unrelatedSpongeClasses = Set.of( + Carrier.class, + CarriedInventory.class, + Contextual.class, + Inventory.class, + LocaleSource.class, + Locatable.class, + ProjectileSource.class, + RandomProvider.class, + Spawner.class, + Subject.class, + TeamMember.class, + ViewableInventory.class, + Viewer.class + ); + + this.interfacesAndSuperclasses(minecraftClass) + .filter(c -> c.getPackageName().startsWith("org.spongepowered.api") || c.getPackageName().startsWith("net.minecraft")) + .filter(c -> !c.getPackageName().startsWith("org.spongepowered.api.data")) + .filter(c -> !unrelatedSpongeClasses.contains(c)) + .forEach(c -> { + if (c.getPackageName().startsWith("net.minecraft")) { + minecraftClasses.add(c); + } + if (c.getPackageName().startsWith("org.spongepowered")) { + implSpongeClasses.add(c); + } + }); + + final var spongeConceptClasses = Set.of( + Aerial.class, + Ageable.class, + Breedable.class, + ItemRepresentable.class, + Projectile.class, + Ranger.class, + Sittable.class + ); + + if (!unmappedMinecraftClasses.contains(minecraftClass.getName())) { + var apiSpongeClass = minecraftToSpongeMapping.get(minecraftClass.getSimpleName()); + if (apiSpongeClass == null) { + apiSpongeClass = implSpongeClasses.stream() + .filter(c -> c.getSimpleName().equalsIgnoreCase(minecraftClass.getSimpleName())) + .findAny() + .orElse(null); + } + if (apiSpongeClass == null) { + this.logger.error("{} cannot find matching Sponge interface", minecraftClass.getName()); + return; + } + + if (!spongeConceptClasses.contains(apiSpongeClass)) { + final var apiSpongeClasses = this.interfacesAndSuperclasses(apiSpongeClass) + .filter(c -> c.getPackageName().startsWith("org.spongepowered.api")) + .filter(c -> !c.getPackageName().startsWith("org.spongepowered.api.data")) + .collect(Collectors.toSet()); + + if (implSpongeClasses.isEmpty()) { + this.logger.error("{} does not implement expected Sponge interface: {}", minecraftClass.getName(), apiSpongeClass.getName()); + return; + } + + if (!apiSpongeClasses.containsAll(implSpongeClasses)) { + implSpongeClasses.removeAll(apiSpongeClasses); + this.logger.error("{}: extra sponge classes compared to the API: {}", minecraftClass.getName(), implSpongeClasses); + return; + } + } + } - mcInterfaces.removeIf(mcInterface -> - spongeInterfaces.removeIf(spongeClass -> - spongeClass.getSimpleName().equals(mcToSpongeMapping.getOrDefault(mcInterface.getSimpleName(), mcInterface.getSimpleName())) - ) - ); + minecraftClasses.removeIf(c -> unmappedMinecraftClasses.contains(c.getName())); + implSpongeClasses.removeAll(unmappedSpongeClasses); - if (this.verbose) { - if (!mcInterfaces.isEmpty()) { - this.logger.info("extra unmapped mc interfaces for {}: {}", ((Class) typeArg).getSimpleName(), mcInterfaces); - } - if (!spongeInterfaces.isEmpty()) { - this.logger.info("extra unmapped sponge interfaces for {}: {}", ((Class) typeArg).getSimpleName(), spongeInterfaces); - } - } + minecraftClasses.removeIf(mClass -> { + final var targetSpongeClass = minecraftToSpongeMapping.get(mClass.getSimpleName()); + final var targetSpongeName = mClass.getSimpleName(); + return targetSpongeClass != null + ? implSpongeClasses.remove(targetSpongeClass) + : implSpongeClasses.removeIf(sClass -> sClass.getSimpleName().equalsIgnoreCase(targetSpongeName)); + }); + + implSpongeClasses.removeAll(spongeConceptClasses); + + if (minecraftClasses.isEmpty() && implSpongeClasses.size() == 1 && implSpongeClasses.contains(Entity.class)) { + return; + } + + if (this.verbose) { + if (!minecraftClasses.isEmpty()) { + this.logger.info("{}: extra unmapped minecraft classes: {}", minecraftClass.getName(), minecraftClasses); + } + if (!implSpongeClasses.isEmpty()) { + this.logger.info("{}: extra unmapped sponge classes: {}", minecraftClass.getName(), implSpongeClasses); + } + } + } + }); } + context.sendMessage(Component.text("Done!")); return CommandResult.success(); }) .build(), @@ -366,8 +531,11 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent> interfacesAndSuperclasses(final Class clazz) { return Stream.concat( - Stream.of(clazz.getInterfaces()).flatMap(interfaceType -> Stream.concat(Stream.of(interfaceType), this.interfacesAndSuperclasses(interfaceType))), - Stream.ofNullable(clazz.getSuperclass()).flatMap(superclass -> Stream.concat(Stream.of(superclass), this.interfacesAndSuperclasses(superclass))) + Stream.of(clazz), + Stream.concat( + Stream.of(clazz.getInterfaces()).flatMap(interfaceType -> Stream.concat(Stream.of(interfaceType), this.interfacesAndSuperclasses(interfaceType))), + Stream.ofNullable(clazz.getSuperclass()).flatMap(superclass -> Stream.concat(Stream.of(superclass), this.interfacesAndSuperclasses(superclass))) + ) ); } } From 9f0b870ea39fe2da4903f963bfe1c30aa137151a Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Wed, 10 Jul 2024 18:22:09 +0200 Subject: [PATCH 142/226] unwrap enchantment holder fixes #4092 --- .../item/enchantment/SpongeRandomEnchantmentListBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java b/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java index 8471cf38d21..1c8c25e8881 100644 --- a/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java +++ b/src/main/java/org/spongepowered/common/item/enchantment/SpongeRandomEnchantmentListBuilder.java @@ -135,7 +135,7 @@ private List basedOfFixedPool(final RandomSource randomIn, } public static List fromNative(final List list) { - return list.stream().map(data -> Enchantment.of(((EnchantmentType) data.enchantment), data.level)).collect(Collectors.toList()); + return list.stream().map(data -> Enchantment.of(((EnchantmentType) (Object) data.enchantment.value()), data.level)).collect(Collectors.toList()); } public static List toNative(final List list) { From 232408022b347d871efadec16b4ab6965128af98 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 12 Jul 2024 19:22:21 +0200 Subject: [PATCH 143/226] DataFix entity nbt when spawning from DataContainer --- .../common/mixin/core/world/level/LevelMixin.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java index 229cfe2fcfa..05dd80dd4c6 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java @@ -24,10 +24,15 @@ */ package org.spongepowered.common.mixin.core.world.level; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.util.RandomSource; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.LightningBolt; import net.minecraft.world.entity.Mob; @@ -37,6 +42,7 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.projectile.ThrownEnderpearl; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.FireworkExplosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; @@ -152,10 +158,11 @@ public abstract class LevelMixin implements LevelBridge, LevelAccessor { dataContainer.getView(Constants.Sponge.UNSAFE_NBT) .map(NBTTranslator.INSTANCE::translate) .ifPresent(x -> { - final net.minecraft.world.entity.Entity e = ((net.minecraft.world.entity.Entity) createdEntity); + final var dataFixed = DataFixers.getDataFixer().update(References.ENTITY, new Dynamic<>(NbtOps.INSTANCE, x), 3692, 3833); + final var e = ((net.minecraft.world.entity.Entity) createdEntity); // mimicing Entity#restoreFrom - x.remove("Dimension"); - e.load(x); + dataFixed.remove("Dimension"); + e.load((CompoundTag) dataFixed.getValue()); // position needs a reset e.moveTo(proposedPosition.x(), proposedPosition.y(), proposedPosition.z()); }); From 90cca885fa9a1fe0a0a2fa845008b353656f50b7 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:10:21 +0000 Subject: [PATCH 144/226] Fix Keys.ABSORPTION remove operation (#4089) --- .../spongepowered/common/data/provider/entity/LivingData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java index 3bcf5773cc6..adea3b772b3 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java @@ -58,6 +58,7 @@ public static void register(final DataProviderRegistrator registrator) { .asMutable(LivingEntity.class) .create(Keys.ABSORPTION) .get(h -> (double) h.getAbsorptionAmount()) + .resetOnDelete(0.0) .setAnd((h, v) -> { if (v < 0) { return false; From c5bbe2d4adb67bb754848d72f15ebab5fcfd1d38 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:13:05 +0000 Subject: [PATCH 145/226] Support Keys.LEASH_HOLDER for all Leashable entities and fix remove (#4090) --- .../provider/entity/EntityDataProviders.java | 1 + .../data/provider/entity/LeashableData.java | 57 +++++++++++++++++++ .../common/data/provider/entity/MobData.java | 10 ---- 3 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/data/provider/entity/LeashableData.java diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityDataProviders.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityDataProviders.java index a6044d3c076..facac285ef6 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityDataProviders.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityDataProviders.java @@ -78,6 +78,7 @@ public void registerProviders() { IronGolemData.register(this.registrator); ItemData.register(this.registrator); ItemFrameData.register(this.registrator); + LeashableData.register(this.registrator); LightningBoltData.register(this.registrator); LivingData.register(this.registrator); LlamaData.register(this.registrator); diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LeashableData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LeashableData.java new file mode 100644 index 00000000000..1948a9b0db0 --- /dev/null +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LeashableData.java @@ -0,0 +1,57 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.data.provider.entity; + +import net.minecraft.world.entity.Leashable; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.common.data.provider.DataProviderRegistrator; + +public final class LeashableData { + + private LeashableData() { + } + + public static void register(final DataProviderRegistrator registrator) { + registrator + .asMutable(Leashable.class) + .create(Keys.LEASH_HOLDER) + .get(h -> { + final var ld = h.getLeashData(); + return ld == null ? null : (Entity) ld.leashHolder; + }) + .delete(h -> { + h.dropLeash(true, false); + }) + .set((h, v) -> { + if (v == null) { + // TODO remove + h.dropLeash(true, false); + } else { + h.setLeashedTo((net.minecraft.world.entity.Entity) v, true); + } + }); + } +} diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/MobData.java b/src/main/java/org/spongepowered/common/data/provider/entity/MobData.java index 238408bd55d..7e606f07520 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/MobData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/MobData.java @@ -29,7 +29,6 @@ import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.HandPreference; import org.spongepowered.api.data.type.HandPreferences; -import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.living.Living; import org.spongepowered.common.accessor.world.entity.MobAccessor; import org.spongepowered.common.data.provider.DataProviderRegistrator; @@ -46,15 +45,6 @@ public static void register(final DataProviderRegistrator registrator) { .create(Keys.DOMINANT_HAND) .get(h -> (HandPreference) (Object) h.getMainArm()) .set((h, v) -> h.setLeftHanded(v.equals(HandPreferences.LEFT.get()))) - .create(Keys.LEASH_HOLDER) - .get(h -> ((Entity) h.getLeashHolder())) - .set((h, v) -> { - if (v == null) { - h.dropLeash(true, false); - } else { - h.setLeashedTo((net.minecraft.world.entity.Entity) v, true); - } - }) .create(Keys.TARGET_ENTITY) .get(h -> (Living) h.getTarget()) .setAnd((h, v) -> { From 22d37d446a6f200ba05ddfd3e61d530164c21aa6 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:15:05 +0000 Subject: [PATCH 146/226] Fix Keys.FROZEN_TIME remove operation (#4094) --- .../spongepowered/common/data/provider/entity/EntityData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index 683eee50731..c954d790a04 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -139,6 +139,7 @@ public static void register(final DataProviderRegistrator registrator) { }) .create(Keys.FROZEN_TIME) .get(h -> Ticks.of(h.getTicksFrozen())) + .resetOnDelete(Ticks.zero()) .setAnd((h, v) -> { if (v.isInfinite()) { return false; From 911a12a6fd331f6dc7591096ab55adefec1b966c Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:15:18 +0000 Subject: [PATCH 147/226] Fix Keys.PASSENGERS remove operation (#4093) --- .../spongepowered/common/data/provider/entity/EntityData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index c954d790a04..ce98cd05136 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -192,6 +192,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(Entity::onGround) .create(Keys.PASSENGERS) .get(h -> h.getPassengers().stream().map(org.spongepowered.api.entity.Entity.class::cast).collect(Collectors.toList())) + .delete(Entity::ejectPassengers) .set((h, v) -> { h.ejectPassengers(); v.forEach(v1 -> ((Entity) v1).startRiding(h, true)); From 8f7720bf946c61d0f03f0bd9048434aa8358387e Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:15:37 +0000 Subject: [PATCH 148/226] Fix Keys.INVULNERABILITY_TICKS remove operation (#4091) --- .../spongepowered/common/data/provider/entity/EntityData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index ce98cd05136..50a3eb49773 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -153,6 +153,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> (double) h.getBbHeight()) .create(Keys.INVULNERABILITY_TICKS) .get(h -> new SpongeTicks(h.invulnerableTime)) + .resetOnDelete(Ticks.zero()) .setAnd((h, v) -> { final int ticks = SpongeTicks.toSaturatedIntOrInfinite(v); if (v.isInfinite() || ticks < 0) { From 1e8c4d4f18e5482ac3723a951c33540357e32385 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 12 Jul 2024 20:17:55 +0200 Subject: [PATCH 149/226] fix build --- .../spongepowered/common/mixin/core/world/level/LevelMixin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java index 05dd80dd4c6..863a0637a3a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java @@ -42,7 +42,6 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.projectile.ThrownEnderpearl; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.FireworkExplosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; From 6379fcc35bca38b78286b2837485512dbbd9cc36 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:23:12 +0000 Subject: [PATCH 150/226] Fix Keys.SCOREBOARD_TAGS remove operation (#4098) --- .../spongepowered/common/data/provider/entity/EntityData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index 50a3eb49773..4c2638319ce 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -216,6 +216,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> 1d) .create(Keys.SCOREBOARD_TAGS) .get(Entity::getTags) + .delete(h -> h.getTags().clear()) .set((h, v) -> { h.getTags().clear(); h.getTags().addAll(v); From 1b0d092f962b15e23f3bc5a4078cac17391cc5ac Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:23:21 +0000 Subject: [PATCH 151/226] Fix Keys.VELOCITY remove operation (#4097) --- .../spongepowered/common/data/provider/entity/EntityData.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java index 4c2638319ce..5e62f6e798b 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/EntityData.java @@ -49,6 +49,7 @@ import org.spongepowered.common.util.Constants; import org.spongepowered.common.util.SpongeTicks; import org.spongepowered.common.util.VecHelper; +import org.spongepowered.math.vector.Vector3d; import java.util.stream.Collectors; @@ -227,6 +228,7 @@ public static void register(final DataProviderRegistrator registrator) { .delete(h -> h.stopRiding()) .create(Keys.VELOCITY) .get(h -> VecHelper.toVector3d(h.getDeltaMovement())) + .resetOnDelete(Vector3d.ZERO) .set((h, v) -> { h.setDeltaMovement(VecHelper.toVanillaVector3d(v)); h.hurtMarked = true; From 4030d704faa579358bcfb3d21df7c0680c27ee64 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:23:41 +0000 Subject: [PATCH 152/226] Fix Keys.TRANSIENT remove operation (#4095) --- .../spongepowered/common/data/provider/entity/TransientData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/TransientData.java b/src/main/java/org/spongepowered/common/data/provider/entity/TransientData.java index e5061b58ac6..6b08266456d 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/TransientData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/TransientData.java @@ -39,6 +39,7 @@ public static void register(final DataProviderRegistrator registrator) { .asMutable(TransientBridge.class) .create(Keys.TRANSIENT) .get(TransientBridge::bridge$isTransient) + .resetOnDelete(false) .set(TransientBridge::bridge$setTransient); } // @formatter:on From b702266247ffec61e6ac40e77c6ae8fa53847f22 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:24:16 +0000 Subject: [PATCH 153/226] Fix Keys.STUCK_ARROWS remove operation (#4099) --- .../spongepowered/common/data/provider/entity/LivingData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java index adea3b772b3..95d469bc09f 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java @@ -200,6 +200,7 @@ public static void register(final DataProviderRegistrator registrator) { .get(h -> (double) h.getScale()) .create(Keys.STUCK_ARROWS) .get(LivingEntity::getArrowCount) + .resetOnDelete(0) .setAnd((h, v) -> { if (v < 0 || v > Integer.MAX_VALUE) { return false; From 166b3125ce69dfe4f587be86ce0de188555a04c5 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:26:40 +0000 Subject: [PATCH 154/226] Fix Keys.POTION_EFFECTS remove operation (#4096) --- .../spongepowered/common/data/provider/entity/LivingData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java index 95d469bc09f..ee919967865 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java @@ -190,6 +190,7 @@ public static void register(final DataProviderRegistrator registrator) { final Collection effects = h.getActiveEffects(); return PotionEffectUtil.copyAsPotionEffects(effects); }) + .delete(LivingEntity::removeAllEffects) .set((h, v) -> { h.removeAllEffects(); for (final PotionEffect effect : v) { From 8cc987873dfa8afc125ab32b4e7a50b10b75933f Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:26:56 +0000 Subject: [PATCH 155/226] Fix Keys.INVULNERABLE remove operation (#4101) --- .../common/data/provider/entity/InvulnerableData.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/InvulnerableData.java b/src/main/java/org/spongepowered/common/data/provider/entity/InvulnerableData.java index c5ff76cc3f7..f23f27981dc 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/InvulnerableData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/InvulnerableData.java @@ -40,10 +40,12 @@ public static void register(final DataProviderRegistrator registrator) { .asMutable(Entity.class) .create(Keys.INVULNERABLE) .get(Entity::isInvulnerable) + .resetOnDelete(false) .set(Entity::setInvulnerable) .asMutable(SpongeUserData.class) .create(Keys.INVULNERABLE) .get(SpongeUserData::isInvulnerable) + .resetOnDelete(false) .set(SpongeUserData::setInvulnerable); } // @formatter:on From ea6b9a4fc20649f22211c1e22f854c9d48e79679 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:27:43 +0000 Subject: [PATCH 156/226] Implement Keys.AUTO_SPIN_ATTACK_TICKS for Living (#4088) --- .../common/accessor/world/entity/LivingEntityAccessor.java | 3 +++ .../common/data/provider/entity/LivingData.java | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java index e759b0ff380..4c6ed062320 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/entity/LivingEntityAccessor.java @@ -86,9 +86,12 @@ public interface LivingEntityAccessor { @Accessor("lastHurtByMob") @Nullable LivingEntity accessor$lastHurtByMob(); @Accessor("autoSpinAttackTicks") int accessor$autoSpinAttackTicks(); + @Accessor("autoSpinAttackTicks") void accessor$autoSpinAttackTicks(final int autoSpinAttackTicks); @Accessor("autoSpinAttackDmg") float accessor$autoSpinAttackDmg(); @Accessor("autoSpinAttackItemStack") ItemStack accessor$autoSpinAttackItemStack(); + @Invoker("setLivingEntityFlag") void invoker$setLivingEntityFlag(int $$0, boolean $$1); + @Accessor("useItem") void accessor$useItem(final ItemStack useItem); @Invoker("isDamageSourceBlocked") boolean invoker$isDamageSourceBlocked(final DamageSource source); diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java index ee919967865..c26f30fd7de 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/LivingData.java @@ -78,6 +78,7 @@ public static void register(final DataProviderRegistrator registrator) { .delete(LivingEntity::releaseUsingItem) .create(Keys.AUTO_SPIN_ATTACK_TICKS) .get(h -> Ticks.of(((LivingEntityAccessor)h).accessor$autoSpinAttackTicks())) + .resetOnDelete(Ticks.zero()) .setAnd((h, v) -> { if (v.isInfinite()) { return false; @@ -88,7 +89,9 @@ public static void register(final DataProviderRegistrator registrator) { p.startAutoSpinAttack(SpongeTicks.toSaturatedIntOrInfinite(v), dmg == 0 ? 8.0F : dmg, stack); return true; } - return false; + ((LivingEntityAccessor) h).accessor$autoSpinAttackTicks(SpongeTicks.toSaturatedIntOrInfinite(v)); + ((LivingEntityAccessor) h).invoker$setLivingEntityFlag(4, true); + return true; }) .create(Keys.AUTO_SPIN_ATTACK_DAMAGE) .get(h -> (double) ((LivingEntityAccessor)h).accessor$autoSpinAttackDmg()) From dbde30713fa95763979a859ae5b851de4e36b80a Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 2 Jul 2024 03:32:53 +0300 Subject: [PATCH 157/226] remove Raid#setBossBar() --- .../api/minecraft/world/entity/raid/RaidMixin_API.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/raid/RaidMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/raid/RaidMixin_API.java index b64bd1ea9cd..feb2b13a32d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/raid/RaidMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/entity/raid/RaidMixin_API.java @@ -35,7 +35,6 @@ import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.world.entity.raid.RaidBridge; @@ -43,7 +42,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -52,7 +50,7 @@ public abstract class RaidMixin_API implements org.spongepowered.api.raid.Raid { //@formatter:off @Shadow @Final private Map> groupRaiderMap; - @Shadow @Final @Mutable private ServerBossEvent raidEvent; + @Shadow @Final private ServerBossEvent raidEvent; @Shadow private Raid.RaidStatus status; @Shadow public abstract Level shadow$getLevel(); @@ -70,12 +68,6 @@ public BossBar bossBar() { return SpongeAdventure.asAdventure(this.raidEvent); } - @Override - public void setBossBar(final BossBar bossBar) { - Objects.requireNonNull(bossBar, "BossBar cannot be null."); - this.raidEvent = SpongeAdventure.asVanillaServer(bossBar); - } - @Override public RaidStatus status() { return (RaidStatus) (Object) this.status; From 695b934675e75138e17477a95c7f42bdae24e2c4 Mon Sep 17 00:00:00 2001 From: Morpheus Date: Fri, 12 Jul 2024 18:58:38 +0000 Subject: [PATCH 158/226] Guard against null elements in cached valueconstructors (#4102) --- .../common/data/value/CachedBooleanValueConstructor.java | 3 +++ .../common/data/value/CachedEnumValueConstructor.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/org/spongepowered/common/data/value/CachedBooleanValueConstructor.java b/src/main/java/org/spongepowered/common/data/value/CachedBooleanValueConstructor.java index 4ea2dd38ed2..3365925d4ce 100644 --- a/src/main/java/org/spongepowered/common/data/value/CachedBooleanValueConstructor.java +++ b/src/main/java/org/spongepowered/common/data/value/CachedBooleanValueConstructor.java @@ -26,6 +26,8 @@ import org.spongepowered.api.data.value.Value; +import java.util.Objects; + final class CachedBooleanValueConstructor implements ValueConstructor, Boolean> { private final ValueConstructor, Boolean> original; @@ -45,6 +47,7 @@ public Value getMutable(final Boolean element) { @Override public Value getImmutable(final Boolean element) { + Objects.requireNonNull(element, "element"); return element ? this.immutableValueTrue : this.immutableValueFalse; } diff --git a/src/main/java/org/spongepowered/common/data/value/CachedEnumValueConstructor.java b/src/main/java/org/spongepowered/common/data/value/CachedEnumValueConstructor.java index cf2c66e1899..dfa6624135c 100644 --- a/src/main/java/org/spongepowered/common/data/value/CachedEnumValueConstructor.java +++ b/src/main/java/org/spongepowered/common/data/value/CachedEnumValueConstructor.java @@ -26,6 +26,8 @@ import org.spongepowered.api.data.value.Value; +import java.util.Objects; + @SuppressWarnings("unchecked") final class CachedEnumValueConstructor, E extends Enum> implements ValueConstructor { @@ -48,6 +50,7 @@ public V getMutable(final E element) { @Override public V getImmutable(final E element) { + Objects.requireNonNull(element, "element"); return this.immutableValues[element.ordinal()]; } From 3368919e971e46eb92cff23f4cde7a4e9e65c0d5 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Fri, 12 Jul 2024 21:51:48 +0200 Subject: [PATCH 159/226] register updaters for ItemStack/ItemStackSnapshot, fix wrappedContentUpdater and set content version after updating to v3 --- .../common/data/SpongeDataManager.java | 7 ++- .../item/ItemStackDataComponentsUpdater.java | 2 + .../spongepowered/test/entity/EntityTest.java | 43 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/SpongeDataManager.java b/src/main/java/org/spongepowered/common/data/SpongeDataManager.java index 56b219c64ea..78fbc22b49e 100644 --- a/src/main/java/org/spongepowered/common/data/SpongeDataManager.java +++ b/src/main/java/org/spongepowered/common/data/SpongeDataManager.java @@ -166,6 +166,9 @@ private SpongeDataManager() { this.customDataUpdaters = new ArrayList<>(); this.legacyRegistrations = new HashMap<>(); this.keyListeners = new ArrayList<>(); + + this.updatersMap.put(ItemStack.class, SpongeItemStack.STACK_UPDATERS); + this.updatersMap.put(ItemStackSnapshot.class, SpongeItemStack.STACK_UPDATERS); } @Override @@ -201,8 +204,8 @@ public Optional wrappedContentU if (fromVersion == toVersion) { throw new IllegalArgumentException("Attempting to convert to the same version!"); } - if (fromVersion < toVersion) { - throw new IllegalArgumentException("Attempting to backwards convert data! This isn't supported!"); + if (fromVersion > toVersion) { + throw new IllegalArgumentException("Attempting to backwards convert data! This isn't supported! " + fromVersion + " -> " + toVersion); } final List updaters = this.updatersMap.get(clazz); if (updaters == null) { diff --git a/src/main/java/org/spongepowered/common/item/ItemStackDataComponentsUpdater.java b/src/main/java/org/spongepowered/common/item/ItemStackDataComponentsUpdater.java index 4c13672cb09..fe0ed3442a8 100644 --- a/src/main/java/org/spongepowered/common/item/ItemStackDataComponentsUpdater.java +++ b/src/main/java/org/spongepowered/common/item/ItemStackDataComponentsUpdater.java @@ -32,6 +32,7 @@ import org.spongepowered.api.data.persistence.DataContainer; import org.spongepowered.api.data.persistence.DataContentUpdater; import org.spongepowered.api.data.persistence.DataView; +import org.spongepowered.api.data.persistence.Queries; import org.spongepowered.common.data.persistence.NBTTranslator; import org.spongepowered.common.util.Constants; @@ -77,6 +78,7 @@ public DataView update(final DataView content) { }); updated.set(Constants.ItemStack.COMPONENTS, components); + updated.set(Queries.CONTENT_VERSION, this.outputVersion()); return updated; } diff --git a/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java b/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java index a408c6bc9a1..7fb814a7561 100644 --- a/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java @@ -30,20 +30,29 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.Sponge; import org.spongepowered.api.command.Command; import org.spongepowered.api.command.Command.Parameterized; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.parameter.Parameter; +import org.spongepowered.api.config.ConfigDir; +import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.entity.SpawnEntityEvent; import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.hocon.HoconConfigurationLoader; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; +import java.nio.file.Path; import java.util.HashSet; +import java.util.Objects; import java.util.Set; @Plugin("entitytest") @@ -53,12 +62,44 @@ public class EntityTest { private final Set> blockedSpawn = new HashSet<>(); @Inject - public EntityTest(final PluginContainer plugin) { + public EntityTest(final PluginContainer plugin, @ConfigDir(sharedRoot = true) Path cfg) { this.plugin = plugin; + this.configFile =cfg.resolve("entitytest.conf"); + } + + private final Path configFile; + + @Listener + public void onRegisterCommands(final RegisterCommandEvent event) { + } @Listener public void onRegisterCommand(final RegisterCommandEvent event) { + + + event.register(this.plugin, Command.builder() + .executor(ctx -> { + final var player = ctx.cause().first(ServerPlayer.class).orElseThrow(); + + try { + final var loader = HoconConfigurationLoader.builder() + .defaultOptions(opt -> opt.serializers(Sponge.configManager().serializers())) + .path(configFile) + .build(); + + final var node = loader.load(); + + final var item = Objects.requireNonNull(node.node("item").get(ItemStackSnapshot.class)); + + player.setItemInHand(HandTypes.MAIN_HAND, item.createStack()); + } catch (ConfigurateException e) { + throw new RuntimeException(e); + } + + return CommandResult.success(); + }) + .build(), "testload"); final Parameter.Value> entityTypeParam = Parameter.registryElement(new TypeToken>() {}, RegistryTypes.ENTITY_TYPE, "minecraft").key("entityType").build(); event.register(this.plugin, Command.builder() From 5edf409ce0c36ca505a2fa67110683d9e59fa576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Sat, 13 Jul 2024 00:40:50 +0300 Subject: [PATCH 160/226] Update PlayerListMixin.java Fix for the `PlayerChatEvent.Submit` event. Now you can change messages in this event and it will work correctly. --- .../mixin/core/server/players/PlayerListMixin.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) mode change 100644 => 100755 src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java old mode 100644 new mode 100755 index 468e902e5e4..305949406bb --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/players/PlayerListMixin.java @@ -650,11 +650,15 @@ public abstract class PlayerListMixin implements PlayerListBridge { boundChatType = event.target().map(SpongeAdventure::asVanilla).map(boundChatType::withTargetName).orElse(boundChatType); filter = event.filter().map(f -> $$1.and((Predicate) f)).orElse($$1); - if (!isTrusted && event.message() != event.originalMessage()) { + if (event.message() != event.originalMessage()) { final net.minecraft.network.chat.Component customMessage = SpongeAdventure.asVanilla(event.message()); - // TODO does this work? - var systemMessage = PlayerChatMessage.system(customMessage.getString()).withUnsignedContent(customMessage); - this.shadow$broadcastChatMessage(systemMessage, filter, $$2, boundChatType); + // It works! + // If the message is changed, the player will be shown the standard message change notification for such situations. + // The value of `isTrusted` will always be `true` when `online-mode=true`. + // If `online-mode=false`, then `isTrusted` will also have a value of `false`. + // When `online-mode=false`, the player is not shown a notification when the server changes the message. + var modifiedMessage = new PlayerChatMessage($$0.link(), $$0.signature(), $$0.signedBody(), customMessage, $$0.filterMask()); + this.shadow$broadcastChatMessage(modifiedMessage, filter, $$2, boundChatType); return; } } From 093d90ca5b3532491563a66186009809b8c8896d Mon Sep 17 00:00:00 2001 From: aromaa Date: Sun, 14 Jul 2024 21:44:28 +0300 Subject: [PATCH 161/226] Fix block entity archetype querying --- src/main/java/org/spongepowered/common/SpongeCommon.java | 7 ++++++- .../common/block/entity/SpongeBlockEntityArchetype.java | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/SpongeCommon.java b/src/main/java/org/spongepowered/common/SpongeCommon.java index 51ce152496a..2789b1c36bc 100644 --- a/src/main/java/org/spongepowered/common/SpongeCommon.java +++ b/src/main/java/org/spongepowered/common/SpongeCommon.java @@ -28,6 +28,7 @@ import com.google.inject.Singleton; import net.minecraft.SharedConstants; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import org.apache.logging.log4j.LogManager; @@ -95,8 +96,12 @@ public static MinecraftServer server() { return (MinecraftServer) Sponge.server(); } + public static RegistryAccess.Frozen vanillaRegistryAccess() { + return SpongeCommon.server().registryAccess(); + } + public static Registry vanillaRegistry(ResourceKey> key) { - return SpongeCommon.server().registryAccess().registryOrThrow(key); + return SpongeCommon.vanillaRegistryAccess().registryOrThrow(key); } public static ServerScheduler serverScheduler() { diff --git a/src/main/java/org/spongepowered/common/block/entity/SpongeBlockEntityArchetype.java b/src/main/java/org/spongepowered/common/block/entity/SpongeBlockEntityArchetype.java index 4c65288795c..f4331bc2054 100644 --- a/src/main/java/org/spongepowered/common/block/entity/SpongeBlockEntityArchetype.java +++ b/src/main/java/org/spongepowered/common/block/entity/SpongeBlockEntityArchetype.java @@ -198,8 +198,7 @@ public String toString() { if (this.cachedBlockEntity == null) { final CompoundTag compound = this.compound.copy(); compound.putString(Constants.Item.BLOCK_ENTITY_ID, SpongeCommon.vanillaRegistry(Registries.BLOCK_ENTITY_TYPE).getKey((net.minecraft.world.level.block.entity.BlockEntityType) this.type).toString()); - //TODO fixme - //this.cachedBlockEntity = net.minecraft.world.level.block.entity.BlockEntity.loadStatic(new BlockPos(0, 0, 0), (net.minecraft.world.level.block.state.BlockState) this.blockState, compound); + this.cachedBlockEntity = net.minecraft.world.level.block.entity.BlockEntity.loadStatic(new BlockPos(0, 0, 0), (net.minecraft.world.level.block.state.BlockState) this.blockState, compound, SpongeCommon.vanillaRegistryAccess()); } return Arrays.asList(this, (DataHolder) this.cachedBlockEntity); } From 2339fa616de08913f0269646502caa1c52c6baf1 Mon Sep 17 00:00:00 2001 From: aromaa Date: Thu, 18 Jul 2024 15:44:35 +0300 Subject: [PATCH 162/226] Clear block drop effect after capturing is done --- .../mixin/tracker/world/level/block/BlockMixin_Tracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/block/BlockMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/block/BlockMixin_Tracker.java index fa44df38956..3534f5443bb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/block/BlockMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/block/BlockMixin_Tracker.java @@ -159,6 +159,7 @@ public abstract class BlockMixin_Tracker implements TrackableBlockBridge, Regist } final PhaseContext<@NonNull ?> context = server.getPhaseContext(); context.getTransactor().completeBlockDrops(BlockMixin_Tracker.tracker$effectTransactorForDrops); + BlockMixin_Tracker.tracker$effectTransactorForDrops = null; } @Override From 723603efd539e7d0b6206c13ff353d627c8afe48 Mon Sep 17 00:00:00 2001 From: aromaa Date: Thu, 18 Jul 2024 15:46:05 +0300 Subject: [PATCH 163/226] Move onSend mixin to other overload --- .../common/mixin/core/network/ConnectionMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java index 77b90b76770..835ad9a1da2 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/network/ConnectionMixin.java @@ -161,8 +161,8 @@ public abstract class ConnectionMixin extends SimpleChannelInboundHandler $$0, final @Nullable PacketSendListener $$1, final CallbackInfo ci) { + @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;Z)V", at = @At(value = "HEAD"), cancellable = true) + private void impl$onSend(final Packet $$0, final @Nullable PacketSendListener $$1, final boolean $$2, final CallbackInfo ci) { if (this.disconnectionHandled) { if ($$1 instanceof final PacketSender.SpongePacketSendListener spongeListener) { spongeListener.accept(new IOException("Connection has been closed.")); From f25cc69226e6934bd77da231a5139bba41507351 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sun, 21 Jul 2024 00:38:25 +0300 Subject: [PATCH 164/226] Fixes to damage injections --- .../entity/LivingEntityMixin_Attack_impl.java | 19 ++++++++++++++++--- .../player/PlayerMixin_Attack_Impl.java | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java index 88c70836dfa..ce4e59cf7ec 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -46,6 +46,7 @@ import org.spongepowered.asm.mixin.injection.Coerce; import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; @@ -84,6 +85,7 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin // @formatter:on private float attackImpl$lastHurt; + private float attackImpl$baseDamage; private int attackImpl$InvulnerableTime; protected DamageEventUtil.Hurt attackImpl$hurt; @@ -114,6 +116,7 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, damageTaken)) { cir.setReturnValue(false); } + this.attackImpl$baseDamage = damageTaken; } /** @@ -186,6 +189,16 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin return 0; } + @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 0)) + private float attackImp$useBaseDamage1(final float $$0) { + return this.attackImpl$baseDamage - this.attackImpl$lastHurt; + } + + @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 1)) + private float attackImp$useBaseDamage2(final float $$0) { + return this.attackImpl$baseDamage; + } + /** * After calling #actuallyHurt (even when invulnerable), if cancelled return early or is still invulnerable * and reset {@link #lastHurt} and {@link #invulnerableTime} @@ -425,10 +438,9 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin * * And capture inventory changes if needed */ - @Inject(method = "setHealth", at = @At("HEAD")) - public void attackImpl$afterActuallyHurtEvent(final float $$0, final CallbackInfo ci) { + protected void attackImpl$handlePostDamage() { final var result = this.attackImpl$actuallyHurtResult; - if (result != null) { + if (result != null && !this.attackImpl$actuallyHurtCancelled) { final var damageSource = result.source(); result.damageToShield().ifPresent(dmg -> { this.shadow$hurtCurrentlyUsedShield(dmg); @@ -467,6 +479,7 @@ public abstract class LivingEntityMixin_Attack_impl extends EntityMixin */ @Inject(method = "actuallyHurt", at = @At("RETURN")) public void attackImpl$cleanupActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$handlePostDamage(); this.attackImpl$actuallyHurt = null; this.attackImpl$actuallyHurtResult = null; this.lastHurt = this.attackImpl$lastHurt; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index d0139e7fa85..366ad6c33c7 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -426,6 +426,7 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i */ @Inject(method = "actuallyHurt", at = @At("RETURN")) public void attackImpl$afterActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$handlePostDamage(); this.attackImpl$actuallyHurt = null; this.attackImpl$actuallyHurtResult = null; } From 6411814800202524e302b9dd5be5fe6770ce47db Mon Sep 17 00:00:00 2001 From: Morpheus Date: Mon, 12 Aug 2024 20:29:28 +0000 Subject: [PATCH 165/226] Update to MC 1.21.1 (#4118) --- gradle.properties | 4 ++-- gradle/verification-metadata.xml | 8 ++++++++ .../common/command/selector/SpongeSelectorFactory.java | 4 ++-- .../common/command/selector/SpongeSelectorType.java | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index b624ba50c6c..db84133290e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,10 +12,10 @@ mixinConfigs=mixins.sponge.accessors.json,mixins.sponge.api.json,mixins.sponge.c mixins.sponge.tracker.json,mixins.sponge.ipforward.json,mixins.sponge.optimization.json superClassChanges=common.superclasschange -minecraftVersion=1.21 +minecraftVersion=1.21.1 recommendedVersion=0-SNAPSHOT org.gradle.dependency.verification.console=verbose org.gradle.jvmargs=-Xss4m org.gradle.parallel=true -org.gradle.caching=false +org.gradle.caching=false \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5604a29250b..694a1c87a51 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1016,6 +1016,14 @@
+ + + + + + + + diff --git a/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorFactory.java b/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorFactory.java index 1783e622e56..83d9a6363f0 100644 --- a/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorFactory.java +++ b/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorFactory.java @@ -32,13 +32,13 @@ public final class SpongeSelectorFactory implements Selector.Factory { public static Selector.Builder createBuilder() { - return (Selector.Builder) new EntitySelectorParser(new StringReader("")); + return (Selector.Builder) new EntitySelectorParser(new StringReader(""), true); } @Override public @NonNull Selector parse(final @NonNull String string) throws IllegalArgumentException { try { - return (Selector) new EntitySelectorParser(new StringReader(string)).parse(); + return (Selector) new EntitySelectorParser(new StringReader(string), true).parse(); } catch (final Exception ex) { throw new IllegalArgumentException(ex.getMessage(), ex); } diff --git a/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorType.java b/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorType.java index 1a0a6d2798c..b641c335672 100644 --- a/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorType.java +++ b/src/main/java/org/spongepowered/common/command/selector/SpongeSelectorType.java @@ -40,7 +40,7 @@ public final class SpongeSelectorType implements SelectorType { public SpongeSelectorType(final String selectorToken) { this.selectorToken = selectorToken; try { - this.selector = (Selector) new EntitySelectorParser(new StringReader(this.selectorToken)).parse(); + this.selector = (Selector) new EntitySelectorParser(new StringReader(this.selectorToken), true).parse(); } catch (final CommandSyntaxException exception) { // This should never happen, if it does, it's a bug in our code. throw new RuntimeException(exception); @@ -60,7 +60,7 @@ public SpongeSelectorType(final String selectorToken) { @SuppressWarnings("ConstantConditions") @Override public final Selector.@NonNull Builder toBuilder() { - final EntitySelectorParser parser = new EntitySelectorParser(new StringReader(this.selectorToken)); + final EntitySelectorParser parser = new EntitySelectorParser(new StringReader(this.selectorToken), true); ((EntitySelectorParserAccessor) parser).invoker$parseSelector(); return (Selector.Builder) parser; } From 8750428a5367a62d68b5273a1fd4364d7f05a1a8 Mon Sep 17 00:00:00 2001 From: MrHell228 <82652479+MrHell228@users.noreply.github.com> Date: Tue, 13 Aug 2024 03:30:48 +0700 Subject: [PATCH 166/226] viewer fix (#4112) --- .../spongepowered/common/SpongeServer.java | 6 ----- .../server/MinecraftServerMixin_API.java | 12 ---------- .../server/level/ServerPlayerMixin_API.java | 23 ------------------- .../minecraft/world/level/LevelMixin_API.java | 16 ------------- 4 files changed, 57 deletions(-) diff --git a/src/main/java/org/spongepowered/common/SpongeServer.java b/src/main/java/org/spongepowered/common/SpongeServer.java index 717130c81d7..e72d54960e5 100644 --- a/src/main/java/org/spongepowered/common/SpongeServer.java +++ b/src/main/java/org/spongepowered/common/SpongeServer.java @@ -24,8 +24,6 @@ */ package org.spongepowered.common; -import net.minecraft.core.BlockPos; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Server; import org.spongepowered.common.command.manager.SpongeCommandManager; import org.spongepowered.common.profile.SpongeGameProfileManager; @@ -49,10 +47,6 @@ public interface SpongeServer extends SpongeEngine, Server { UsernameCache getUsernameCache(); - @Nullable Integer getBlockDestructionId(BlockPos pos); - - int getOrCreateBlockDestructionId(BlockPos pos); - SpongeUserManager userManager(); @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java index 3e22f17cdd7..f6a97235086 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/MinecraftServerMixin_API.java @@ -34,7 +34,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.commands.Commands; -import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.server.MinecraftServer; @@ -52,7 +51,6 @@ import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Game; import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; @@ -481,16 +479,6 @@ public UsernameCache getUsernameCache() { return this.api$usernameCache; } - @Override - public @Nullable Integer getBlockDestructionId(BlockPos pos) { - return this.api$blockDestructionIdCache.get(pos).orElse(null); - } - - @Override - public int getOrCreateBlockDestructionId(BlockPos pos) { - return this.api$blockDestructionIdCache.getOrCreate(pos); - } - @Override public BlockDestructionIdCache getBlockDestructionIdCache() { return this.api$blockDestructionIdCache; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java index a04adb8a334..8b8d27c7c1f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ServerPlayerMixin_API.java @@ -34,12 +34,10 @@ import net.kyori.adventure.text.Component; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.core.BlockPos; import net.minecraft.network.Connection; import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.MessageSignature; import net.minecraft.network.chat.PlayerChatMessage; -import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; import net.minecraft.network.protocol.game.ClientboundDeleteChatPacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.resources.ResourceLocation; @@ -211,27 +209,6 @@ public boolean hasPlayedBefore() { return timeSinceFirstJoined.getSeconds() > 0; } - @Override - public void sendBlockProgress(final int x, final int y, final int z, final double progress) { - if (progress < 0 || progress > 1) { - throw new IllegalArgumentException("Progress must be between 0 and 1"); - } - - final BlockPos pos = new BlockPos(x, y, z); - final int id = ((SpongeServer) this.server).getOrCreateBlockDestructionId(pos); - final int progressStage = progress == 1 ? 9 : (int) (progress * 10); - this.connection.send(new ClientboundBlockDestructionPacket(id, pos, progressStage)); - } - - @Override - public void resetBlockProgress(final int x, final int y, final int z) { - final BlockPos pos = new BlockPos(x, y, z); - final Integer id = ((SpongeServer) this.server).getBlockDestructionId(pos); - if (id != null) { - this.connection.send(new ClientboundBlockDestructionPacket(id, pos, -1)); - } - } - @Override public boolean respawn() { if (this.impl$isFake) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java index c1107d96674..71e7937a942 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/LevelMixin_API.java @@ -27,18 +27,15 @@ import net.kyori.adventure.sound.Sound; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Tuple; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ImposterProtoChunk; @@ -264,19 +261,6 @@ public void resetBlockProgress(final int x, final int y, final int z) { ViewerPacketUtil.resetBlockProgress(x, y, z, this.engine()).ifPresent(((ViewerBridge) this)::bridge$sendToViewer); } - @Override - public void sendBlockChange(final int x, final int y, final int z, final org.spongepowered.api.block.BlockState state) { - Objects.requireNonNull(state, "state"); - - final ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), (BlockState) state); - - ((net.minecraft.world.level.Level) (Object) this).players() - .stream() - .filter(ServerPlayer.class::isInstance) - .map(ServerPlayer.class::cast) - .forEach(p -> p.connection.send(packet)); - } - // Audience @Override From 6627ee243c21a1fd94f8a377f1cdf76c308eccd1 Mon Sep 17 00:00:00 2001 From: MrHell228 <82652479+MrHell228@users.noreply.github.com> Date: Tue, 13 Aug 2024 04:04:49 +0700 Subject: [PATCH 167/226] Fix client crash with portals (#4110) * Fix client crash * use bridge$isFake --- .../common/mixin/core/world/entity/EntityMixin.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java index 04cb9b268c3..fc75500c9d8 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java @@ -424,6 +424,10 @@ public Entity changeDimension(final DimensionTransition transition) { @Inject(method = "setAsInsidePortal", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER, target = "Lnet/minecraft/world/entity/Entity;portalProcess:Lnet/minecraft/world/entity/PortalProcessor;")) public void impl$onCreatePortalProcessor(final Portal $$0, final BlockPos $$1, final CallbackInfo ci) { + if (((LevelBridge) this.shadow$level()).bridge$isFake()) { + return; + } + try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()){ var be = this.shadow$level().getBlockEntity(this.portalProcess.getEntryPosition()); if (be != null) { From c1a976f544f54f4976e890d1815fba899e7cbf5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossi=20Erkkil=C3=A4?= <52257907+avaruus1@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:36:09 +0300 Subject: [PATCH 168/226] Support MAX_STACK_SIZE for ItemStack (#4121) Also fix incorrect supports condition for MAX_DURABILITY --- .../provider/item/stack/ItemStackData.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index ae045fac038..616b362f397 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -180,8 +180,26 @@ public static void register(final DataProviderRegistrator registrator) { .delete(h -> h.remove(DataComponents.LORE)) .create(Keys.MAX_DURABILITY) .get(h -> h.getMaxDamage() != 0 ? h.getMaxDamage() : null) - .set((h, v) -> h.set(DataComponents.MAX_DAMAGE, v)) - .supports(h -> h.getMaxDamage() != 0) + .setAnd((h, v) -> { + if (v <= 0) { + return false; + } + + h.set(DataComponents.MAX_DAMAGE, v); + return true; + }) + .supports(h -> h.getOrDefault(DataComponents.MAX_STACK_SIZE, 1) == 1) + .create(Keys.MAX_STACK_SIZE) + .get(ItemStack::getMaxStackSize) + .setAnd((h, v) -> { + if (v <= 0 || v > 99) { + return false; + } + + h.set(DataComponents.MAX_STACK_SIZE, v); + return true; + }) + .supports(h -> !h.has(DataComponents.MAX_DAMAGE)) .create(Keys.ITEM_DURABILITY) .get(stack -> stack.getMaxDamage() - stack.getDamageValue()) .set((stack, durability) -> stack.setDamageValue(stack.getMaxDamage() - durability)) From b76fa669ac34fbd21ff1630b93f79e1d43669402 Mon Sep 17 00:00:00 2001 From: Anselm Brehme Date: Thu, 13 Jun 2024 17:28:59 +0200 Subject: [PATCH 169/226] Revert "disable SpongeForge during snapshots" This reverts commit 1c9e76139d1e77362deaeb12c93e3e3b3abc2e2c. --- .github/workflows/deploy.yaml | 4 ++-- settings.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index c4a65192b77..009eda82dbb 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -44,8 +44,8 @@ jobs: echo "GIT_BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - name: Publish to Sponge Maven & GitHub Packages - # run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish :SpongeForge:publish - run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish + run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish :SpongeForge:publish + # run: ./gradlew -s -PenableSpongeForge=true :publish :SpongeVanilla:publish env: CI_SYSTEM: Github Actions GITHUB_USERNAME: "${{ github.actor }}" diff --git a/settings.gradle.kts b/settings.gradle.kts index 2484c22d7a1..6ad57d49c5e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -89,7 +89,7 @@ if (spongeForge.exists()) { ).joinToString(separator = System.lineSeparator(), postfix = System.lineSeparator())) } val spongeForgeEnabledInCi: String = startParameter.projectProperties.getOrDefault("enableSpongeForge", "false") -if (false && spongeForgeEnabledInCi.toBoolean()) { +if (spongeForgeEnabledInCi.toBoolean()) { include(":SpongeForge") project(":SpongeForge").projectDir = file("forge") } From 16e74e42bcfa4e9c84597d421803ceb8e26e1a30 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 13 Jun 2024 22:41:13 +0200 Subject: [PATCH 170/226] Update SpongeForge to MC 1.21 --- forge/build.gradle.kts | 2 +- forge/gradle.properties | 2 +- .../resource-templates/META-INF/mods.toml | 8 +- forge/src/main/resources/pack.mcmeta | 7 +- .../util/ITeleporterMixin_Forge.java | 53 --------- .../server/level/ServerPlayerMixin_Forge.java | 7 -- .../core/world/entity/EntityMixin_Forge.java | 49 -------- .../resources/mixins.spongeforge.core.json | 2 - gradle/verification-metadata.xml | 105 ++++++++++++++++++ 9 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/minecraftforge/util/ITeleporterMixin_Forge.java delete mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/EntityMixin_Forge.java diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index d492e58c3cf..6e655604e1f 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -236,7 +236,7 @@ dependencies { val runTaskOnly = runTaskOnlyConfig.name // Arch-loom bug, fix support of MOD_CLASSES - runTaskOnly("net.minecraftforge:bootstrap-dev:2.1.1") + runTaskOnly("net.minecraftforge:bootstrap-dev:2.1.3") } val forgeManifest = java.manifest { diff --git a/forge/gradle.properties b/forge/gradle.properties index cbfdd47f7e0..e201e5ab1f5 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -2,7 +2,7 @@ name=SpongeForge implementation=Forge description=The SpongeAPI implementation for MinecraftForge -forgeVersion=50.0.22 +forgeVersion=51.0.0 loom.platform=forge fabric.loom.dontRemap=true mixinConfigs=mixins.spongeforge.accessors.json,mixins.spongeforge.api.json,mixins.spongeforge.inventory.json,mixins.spongeforge.core.json,mixins.spongeforge.tracker.json \ No newline at end of file diff --git a/forge/src/main/resource-templates/META-INF/mods.toml b/forge/src/main/resource-templates/META-INF/mods.toml index 3523cffeb39..2c2c89be5f3 100644 --- a/forge/src/main/resource-templates/META-INF/mods.toml +++ b/forge/src/main/resource-templates/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[50,)" +loaderVersion="[51,)" license="MIT License" issueTrackerURL="https://github.com/SpongePowered/Sponge/issues" @@ -17,7 +17,7 @@ description = "{{ description }}" [[dependencies.spongeforge]] modId="forge" mandatory=true -versionRange="[50,)" +versionRange="[51,)" ordering="AFTER" side="BOTH" @@ -41,14 +41,14 @@ description="The SpongeAPI implementation targeting vanilla Minecraft and 3rd pa [[dependencies.sponge]] modId="spongeapi" mandatory=true -versionRange="[11.0.0,)" +versionRange="[12.0.0,)" ordering="AFTER" side="BOTH" [[mods]] modId="spongeapi" -version="11.0.0" +version="12.0.0" displayName="SpongeAPI" displayTest="IGNORE_SERVER_VERSION" credits="SpongePowered and Contributors" diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta index b1e42542122..da6cf4608c3 100644 --- a/forge/src/main/resources/pack.mcmeta +++ b/forge/src/main/resources/pack.mcmeta @@ -1,9 +1,6 @@ { "pack": { - "description": { - "text": "Resources for SpongeForge" - }, - "forge:server_data_pack_format": 12, - "pack_format": 13 + "description": "Resources for SpongeForge", + "pack_format": 34 } } \ No newline at end of file diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/minecraftforge/util/ITeleporterMixin_Forge.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/minecraftforge/util/ITeleporterMixin_Forge.java deleted file mode 100644 index 708b75d2b46..00000000000 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/minecraftforge/util/ITeleporterMixin_Forge.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.forge.mixin.core.minecraftforge.util; - -import net.minecraftforge.common.util.ITeleporter; -import org.spongepowered.api.event.cause.entity.MovementType; -import org.spongepowered.api.event.cause.entity.MovementTypes; -import org.spongepowered.api.world.portal.PortalType; -import org.spongepowered.api.world.portal.PortalTypes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.world.portal.PortalLogic; - -// PortalLogic matches signatures for ITeleporter when appropriate, -// so we just default implement what it doesn't have. -@Mixin(ITeleporter.class) -public interface ITeleporterMixin_Forge extends PortalLogic { - - @Override - default MovementType getMovementType() { - return MovementTypes.PORTAL.get(); - } - - @Override - default PortalType getPortalType() { - if (this.isVanilla()) { - return PortalTypes.NETHER.get(); - } - return PortalTypes.UNKNOWN.get(); - } - -} diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java index bf2ef7037c4..b06f9cb2cce 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/server/level/ServerPlayerMixin_Forge.java @@ -24,21 +24,14 @@ */ package org.spongepowered.forge.mixin.core.server.level; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.util.ITeleporter; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.common.bridge.world.entity.EntityBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.world.portal.PortalLogic; import org.spongepowered.forge.mixin.core.world.entity.LivingEntityMixin_Forge; @Mixin(ServerPlayer.class) diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/EntityMixin_Forge.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/EntityMixin_Forge.java deleted file mode 100644 index 26110f8e001..00000000000 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/EntityMixin_Forge.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.forge.mixin.core.world.entity; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.util.ITeleporter; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.common.bridge.world.entity.EntityBridge; -import org.spongepowered.common.world.portal.PortalLogic; - -@Mixin(Entity.class) -public abstract class EntityMixin_Forge { - - /** - * @author dualspiral - 8th August 2021, Minecraft 1.16.5 - * @reason Redirects to our handling so we have common logic with Vanilla. - */ - @Overwrite - @Nullable - public Entity changeDimension(final ServerLevel level, final ITeleporter teleporter) { - return ((EntityBridge) this).bridge$changeDimension(level, (PortalLogic) teleporter); - } - -} diff --git a/forge/src/mixins/resources/mixins.spongeforge.core.json b/forge/src/mixins/resources/mixins.spongeforge.core.json index 43ca259f197..5cfd7523621 100644 --- a/forge/src/mixins/resources/mixins.spongeforge.core.json +++ b/forge/src/mixins/resources/mixins.spongeforge.core.json @@ -20,7 +20,6 @@ "minecraftforge.internal.BrandingControlMixin_Forge", "minecraftforge.registries.ForgeRegistryMixin_Forge", "minecraftforge.registries.RegistryManagerMixin_Forge", - "minecraftforge.util.ITeleporterMixin_Forge", "network.ConnectionMixin_Forge", "server.BootstrapMixin_Forge", "server.MinecraftServerMixin_Forge", @@ -28,7 +27,6 @@ "server.level.ServerPlayerMixin_Forge", "server.network.ServerGamePacketListenerImplMixin_Forge", "server.network.ServerLoginPacketListenerImplMixin_Forge", - "world.entity.EntityMixin_Forge", "world.entity.LivingEntityMixin_Forge", "world.entity.item.ItemEntityMixin_Forge", "world.entity.player.PlayerMixin_Forge", diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 694a1c87a51..9cc87ecb6c9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1053,6 +1053,9 @@ + + + @@ -1337,6 +1340,14 @@ + + + + + + + + @@ -1819,6 +1830,14 @@ + + + + + + + + @@ -2422,6 +2441,14 @@ + + + + + + + + @@ -2438,6 +2465,14 @@ + + + + + + + + @@ -2454,6 +2489,14 @@ + + + + + + + + @@ -2502,6 +2545,14 @@ + + + + + + + + @@ -2518,6 +2569,14 @@ + + + + + + + + @@ -2534,6 +2593,14 @@ + + + + + + + + @@ -2562,6 +2629,20 @@ + + + + + + + + + + + + + + @@ -2602,6 +2683,14 @@ + + + + + + + + @@ -2618,6 +2707,14 @@ + + + + + + + + @@ -2634,6 +2731,14 @@ + + + + + + + + From a093a2aecd2de2e39183ecc4819d683c9d3005d2 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 16 Jun 2024 18:55:42 -0700 Subject: [PATCH 171/226] fix: update Forge implementation of Player.attack Signed-off-by: Gabriel Harris-Rouquette --- .../forge/hook/ForgeEntityHooks.java | 6 - .../LivingEntityMixin_Forge_Attack_impl.java | 442 ++++++++++++++++++ .../player/PlayerMixin_Forge_Attack_Impl.java | 390 ++++++++++++++++ .../resources/mixins.spongeforge.core.json | 86 ++-- 4 files changed, 876 insertions(+), 48 deletions(-) create mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java create mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java diff --git a/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java b/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java index 33b5a72a66e..713b5710630 100644 --- a/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java +++ b/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java @@ -30,13 +30,7 @@ import net.minecraftforge.entity.PartEntity; import org.spongepowered.common.hooks.EntityHooks; -@SuppressWarnings("UnstableApiUsage") public class ForgeEntityHooks implements EntityHooks { - @Override - public boolean checkAttackEntity(final Player player, final Entity victim) { - return ForgeHooks.onPlayerAttackTarget(player, victim); - } - @Override public Entity getParentPart(final Entity entity) { if (entity instanceof PartEntity pe) { diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java new file mode 100644 index 00000000000..2f8216ad561 --- /dev/null +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java @@ -0,0 +1,442 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.forge.mixin.core.world.entity; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.stats.Stat; +import net.minecraft.stats.Stats; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.damagesource.CombatRules; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.TamableAnimal; +import net.minecraft.world.entity.animal.Wolf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import org.apache.logging.log4j.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Coerce; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.bridge.world.entity.LivingEntityBridge; +import org.spongepowered.common.bridge.world.entity.PlatformLivingEntityBridge; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.mixin.core.world.entity.EntityMixin; +import org.spongepowered.common.util.DamageEventUtil; +import org.spongepowered.common.util.PrettyPrinter; + +import java.util.ArrayList; + +@Mixin(value = LivingEntity.class, priority = 900) +public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin + implements LivingEntityBridge, PlatformLivingEntityBridge { + + //@formatter:off + @Shadow protected abstract void shadow$playHurtSound(DamageSource param0); + @Shadow protected abstract void shadow$hurtHelmet(final DamageSource $$0, final float $$1); + @Shadow protected abstract void shadow$hurtCurrentlyUsedShield(final float $$0); + @Shadow protected abstract void shadow$blockUsingShield(final LivingEntity $$0); + @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); + @Shadow protected abstract float shadow$getKnockback(final Entity $$0, final DamageSource $$1); + @Shadow public abstract ItemStack shadow$getItemInHand(final InteractionHand $$0); + @Shadow public abstract float shadow$getAbsorptionAmount(); + @Shadow public abstract void setAbsorptionAmount(final float $$0); + @Shadow protected int attackStrengthTicker; + @Shadow protected float lastHurt; + + + // @formatter:on + private float attackImpl$lastHurt; + private int attackImpl$InvulnerableTime; + + protected DamageEventUtil.Hurt attackImpl$hurt; + protected DamageEventUtil.ActuallyHurt attackImpl$actuallyHurt; + protected DamageEventUtil.DamageEventResult attackImpl$actuallyHurtResult; + protected float attackImpl$actuallyHurtFinalDamage; + protected boolean attackImpl$actuallyHurtCancelled; + protected float attackImpl$actuallyHurtBlockedDamage; + + /** + * Forge onLivingAttack Hook + */ + @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) + private void attackImpl$beforeHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { + if (source == null) { + new PrettyPrinter(60).centre().add("Null DamageSource").hr() + .addWrapped("Sponge has found a null damage source! This should NEVER happen " + + "as the DamageSource is used for all sorts of calculations. Usually" + + " this can be considered developer error. Please report the following" + + " stacktrace to the most appropriate mod/plugin available.") + .add() + .add(new IllegalArgumentException("Null DamageSource")) + .log(SpongeCommon.logger(), Level.WARN); + cir.setReturnValue(false); + } + // Sponge - This hook is for forge use mainly + if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, damageTaken)) { + cir.setReturnValue(false); + } + } + + /** + * Prepare {@link org.spongepowered.common.util.DamageEventUtil.Hurt} for damage event + */ + @Inject(method = "hurt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;noActionTime:I")) + private void attackImpl$preventEarlyBlock1(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + this.attackImpl$hurt = new DamageEventUtil.Hurt($$0, new ArrayList<>()); + } + + /** + * Prevents shield usage before event + * Captures the blocked damage as a function + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtCurrentlyUsedShield(F)V")) + private void attackImpl$preventEarlyBlock1(final LivingEntity instance, final float damageToShield) { + // this.hurtCurrentlyUsedShield(damageToShield); + this.attackImpl$hurt.functions().add(DamageEventUtil.createShieldFunction(instance)); + } + + /** + * Prevents shield usage before event + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;blockUsingShield(Lnet/minecraft/world/entity/LivingEntity;)V")) + private void attackImpl$preventEarlyBlock2(final LivingEntity instance, final LivingEntity livingDamageSource) { + // this.blockUsingShield(livingDamageSource); + } + + /** + * Capture the bonus freezing damage as a function + */ + @Inject(method = "hurt", at = @At(value = "CONSTANT", args = "floatValue=5.0F")) + private void attackImpl$freezingBonus(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + this.attackImpl$hurt.functions().add(DamageEventUtil.createFreezingBonus((LivingEntity) (Object) this, $$0, 5.0F)); + } + + /** + * Prevents {@link #shadow$hurtHelmet} before the event + * Captures the hard hat damage reduction as a function + */ + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtHelmet(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$hardHat(final LivingEntity instance, final DamageSource $$0, final float $$1) { + // this.hurtHelmet($$0, $$1); + this.attackImpl$hurt.functions().add(DamageEventUtil.createHardHatModifier(instance.getItemBySlot(EquipmentSlot.HEAD), 0.75F)); + } + + /** + * Capture the old values to reset if we end up cancelling or blocking. + */ + @Inject(method = "hurt", at = @At(value = "FIELD", + target = "Lnet/minecraft/world/entity/LivingEntity;walkAnimation:Lnet/minecraft/world/entity/WalkAnimationState;")) + private void attackImpl$beforeActuallyHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { + // Save old values + this.attackImpl$lastHurt = this.lastHurt; + this.attackImpl$InvulnerableTime = this.invulnerableTime; + this.attackImpl$actuallyHurtCancelled = false; + } + + /** + * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable. + */ + @Redirect(method = "hurt", + at = @At(value = "FIELD", ordinal = 0, + target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) + private float attackImpl$afterActuallyHurt(final LivingEntity instance) { + return 0; + } + + /** + * After calling #actuallyHurt (even when invulnerable), if cancelled return early or is still invulnerable + * and reset {@link #lastHurt} and {@link #invulnerableTime} + */ + @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, + at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 0, + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$afterActuallyHurt1(final DamageSource $$0, + final float damageTaken, + final CallbackInfoReturnable cir, + final float dealtDamage, + final boolean isBlocked + ) { + if (this.attackImpl$actuallyHurtCancelled || damageTaken <= this.lastHurt) { + this.invulnerableTime = this.attackImpl$InvulnerableTime; + this.lastHurt = this.attackImpl$lastHurt; + cir.setReturnValue(false); + } + } + + /** + * After calling #actuallyHurt, if cancelled return early + * Also reset values + */ + @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, + at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 1, + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + private void attackImpl$afterActuallyHurt2(final DamageSource $$0, + final float damageTaken, + final CallbackInfoReturnable cir, + final float dealtDamage, + final boolean isBlocked + ) { + if (this.attackImpl$actuallyHurtCancelled) { + this.invulnerableTime = this.attackImpl$InvulnerableTime; + cir.setReturnValue(false); + } + } + + + /** + * Set final damage after #actuallyHurt + */ + @ModifyVariable(method = "hurt", argsOnly = true, + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", + shift = At.Shift.AFTER)) + private float attackImpl$modifyDamageTaken(float damageTaken) { + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Sets blocked damage after #actuallyHurt + */ + @ModifyVariable(method = "hurt", ordinal = 2, + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", + shift = At.Shift.AFTER)) + private float attackImpl$modifyBlockedDamage(float damageBlocked) { + return this.attackImpl$actuallyHurtBlockedDamage; + } + + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;playHurtSound(Lnet/minecraft/world/damagesource/DamageSource;)V")) + private void attackImpl$onHurtSound(final LivingEntity instance, final DamageSource $$0) { + if (this.bridge$vanishState().createsSounds()) { + this.shadow$playHurtSound($$0); + } + } + + @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;makeSound(Lnet/minecraft/sounds/SoundEvent;)V")) + private void attackImpl$onMakeSound(final LivingEntity instance, final SoundEvent $$0) { + if (this.bridge$vanishState().createsSounds()) { + instance.makeSound($$0); + } + } + + @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) + public boolean attackImpl$startActuallyHurt(final LivingEntity instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { + if (instance.isInvulnerableTo(damageSource)) { + return true; + } + // Call platform hook for adjusting damage + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + // TODO check for direct call? + this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); + return false; + } + + /** + * Prevents LivingEntity#hurtArmor from running before event + * and capture the armor absorption as a function + */ + @Redirect(method = "getDamageAfterArmorAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtArmor(Lnet/minecraft/world/damagesource/DamageSource;F)V")) + public void attackImpl$onDamageAfterArmorAbsorb(final LivingEntity instance, final DamageSource $$0, final float $$1) { + if (this.attackImpl$actuallyHurt != null) { + // prevents this.hurtArmor($$0, $$1); + // $$1 = CombatRules.getDamageAfterAbsorb(this, $$1, $$0, (float)this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); + var func = DamageEventUtil.createArmorModifiers(instance, this.attackImpl$actuallyHurt.dmgSource()); + this.attackImpl$actuallyHurt.functions().add(func); + } + } + + /** + * Captures the damage resistance as a function + */ + @Inject(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getEffect(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/effect/MobEffectInstance;")) + public void attackImpl$onDamageAfterMagicAbsorb(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { + if (this.attackImpl$actuallyHurt != null) { + var func = DamageEventUtil.createResistanceModifier(this.attackImpl$actuallyHurt.entity()); + this.attackImpl$actuallyHurt.functions().add(func); + } + } + + /** + * Prevents {@link ServerPlayer#awardStat} from running before event + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/stats/Stat;I)V")) + public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final Stat stat, final int i) { + // do nothing + } + + /** + * Captures the damage protection as a function + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/CombatRules;getDamageAfterMagicAbsorb(FF)F")) + public float attackImpl$onDetDamageProtection(final float damage, final float protection) { + if (this.attackImpl$actuallyHurt != null) { + var func = DamageEventUtil.createEnchantmentModifiers(this.attackImpl$actuallyHurt.entity(), protection); + this.attackImpl$actuallyHurt.functions().add(func); + } + return CombatRules.getDamageAfterMagicAbsorb(damage, protection); + } + + /** + * Prevents setting absorption before event + * Captures the absorption amount as a functions + * Then calls the DamageEntityEvent + */ + @Inject(method = "setAbsorptionAmount", cancellable = true, at = @At("HEAD")) + public void attackImpl$onSetAbsorptionAmount(final float newAmount, final CallbackInfo ci) { + if (this.attackImpl$actuallyHurt != null) { + ci.cancel(); // Always cancel this + var oldAmount = this.shadow$getAbsorptionAmount(); + if (oldAmount > 0) { + var func = DamageEventUtil.createAbsorptionModifier(this.attackImpl$actuallyHurt.entity(), oldAmount); + this.attackImpl$actuallyHurt.functions().add(func); + } + + this.attackImpl$actuallyHurtResult = DamageEventUtil.callLivingDamageEntityEvent(this.attackImpl$hurt, this.attackImpl$actuallyHurt); + this.attackImpl$actuallyHurt = null; + + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + this.attackImpl$actuallyHurtCancelled = true; + this.attackImpl$actuallyHurtFinalDamage = 0; + this.attackImpl$actuallyHurtBlockedDamage = 0; + return; // Cancel vanilla behaviour by setting absorbed & finalDamage to 0 + } + + // TODO is this actually wrong? we are actually after functions + // (old comment was: Allow the platform to adjust damage before applying armor/etc) + this.attackImpl$actuallyHurtFinalDamage = this.bridge$applyModDamageBeforeFunctions( + (LivingEntity) (Object) (this), + this.attackImpl$actuallyHurtResult.source(), + (float) this.attackImpl$actuallyHurtResult.event().finalDamage()); + + this.attackImpl$actuallyHurtResult.damageAbsorbed().ifPresent(absorbed -> this.setAbsorptionAmount(oldAmount - absorbed)); + this.attackImpl$actuallyHurtBlockedDamage = this.attackImpl$actuallyHurtResult.damageBlockedByShield().orElse(0f); + } + } + + /** + * Set final damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 1, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0, shift = At.Shift.AFTER)) + public float attackImpl$setFinalDamage(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Set absorbed damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 2, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0)), + at = @At(value = "STORE", ordinal = 0)) + public float attackImpl$setAbsorbed(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); + } + + /** + * Replay prevented + * {@link #shadow$hurtCurrentlyUsedShield} and {@link #shadow$blockUsingShield} + * {@link #shadow$hurtHelmet} + * {@link #shadow$hurtArmor} + * {@link ServerPlayer#awardStat} for {@link Stats#DAMAGE_RESISTED} and {@link Stats#DAMAGE_DEALT} + * from {@link LivingEntity#hurt} and #actuallyHurt + * + * And capture inventory changes if needed + */ + @Inject(method = "setHealth", at = @At("HEAD")) + public void attackImpl$afterActuallyHurtEvent(final float $$0, final CallbackInfo ci) { + final var result = this.attackImpl$actuallyHurtResult; + if (result != null) { + final var damageSource = result.source(); + result.damageToShield().ifPresent(dmg -> { + this.shadow$hurtCurrentlyUsedShield(dmg); + if (!damageSource.is(DamageTypeTags.IS_PROJECTILE)) { + if (damageSource.getDirectEntity() instanceof LivingEntity livingSource) { + this.shadow$blockUsingShield(livingSource); + } + } + }); + result.damageToHelmet().ifPresent(dmg -> + this.shadow$hurtHelmet(damageSource, dmg)); + result.damageToArmor().ifPresent(dmg -> + this.shadow$hurtArmor(damageSource, dmg)); + result.damageResisted().ifPresent(dmg -> { + if ((Object) this instanceof ServerPlayer player) { + player.awardStat(Stats.DAMAGE_RESISTED, Math.round(dmg * 10.0F)); + } else if (damageSource.getEntity() instanceof ServerPlayer player) { + player.awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(dmg * 10.0F)); + } + }); + + // Capture inventory change if we modified stacks + if ((result.damageToShield().isPresent() || + result.damageToHelmet().isPresent() || + result.damageToArmor().isPresent()) + && (Object) this instanceof Player player) { + PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange(player, PlayerInventoryTransaction.EventCreator.STANDARD); + player.inventoryMenu.broadcastChanges(); // capture + } + } + } + + /** + * Cleanup + * also reverts {@link #attackImpl$beforeActuallyHurt} + */ + @Inject(method = "actuallyHurt", at = @At("RETURN")) + public void attackImpl$cleanupActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$actuallyHurt = null; + this.attackImpl$actuallyHurtResult = null; + this.lastHurt = this.attackImpl$lastHurt; + } + +} diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java new file mode 100644 index 00000000000..d0ad3615fba --- /dev/null +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java @@ -0,0 +1,390 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.forge.mixin.core.world.entity.player; + +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraftforge.entity.PartEntity; +import net.minecraftforge.event.entity.player.CriticalHitEvent; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.event.entity.AttackEntityEvent; +import org.spongepowered.api.event.impl.entity.AbstractModifierEvent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.hooks.PlatformHooks; +import org.spongepowered.common.util.DamageEventUtil; +import org.spongepowered.forge.mixin.core.world.entity.LivingEntityMixin_Forge_Attack_impl; + +import java.util.ArrayList; +import java.util.Map; + +@SuppressWarnings("ConstantConditions") +@Mixin(value = Player.class, priority = 900) +public abstract class PlayerMixin_Forge_Attack_Impl extends LivingEntityMixin_Forge_Attack_impl { + + //@formatter:off + @Shadow @Final public InventoryMenu inventoryMenu; + @Shadow public abstract float shadow$getAttackStrengthScale(final float $$0); + + //@formatter:on + + private void impl$playAttackSound(Player thisPlayer, SoundEvent sound) { + if (this.bridge$vanishState().createsSounds()) { + thisPlayer.level().playSound(null, thisPlayer.getX(), thisPlayer.getY(), thisPlayer.getZ(), sound, thisPlayer.getSoundSource()); + } + } + + private DamageEventUtil.Attack forgeAttackImpl$attack; + private AttackEntityEvent forgeAttackImpl$attackEvent; + private Map forgeAttackImpl$finalDamageAmounts; + + private int forgeAttackImpl$attackStrengthTicker; + private boolean forgeAttackImpl$isStrongSprintAttack; + + /** + * Cleanup + */ + @Inject(method = "attack", at = @At("RETURN")) + public void attackImpl$onReturnCleanup(final Entity $$0, final CallbackInfo ci) { + this.forgeAttackImpl$attack = null; + this.forgeAttackImpl$attackEvent = null; + this.forgeAttackImpl$finalDamageAmounts = null; + } + + /** + * Captures the base damage for the {@link AttackEntityEvent} in {@link #forgeAttackImpl$attack} + * and the {@link #attackStrengthTicker} in case we need to roll it back. + * Reset {@link #forgeAttackImpl$isStrongSprintAttack} + */ + @Inject(method = "attack", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F", shift = At.Shift.BEFORE)) + public void attackImpl$captureAttackStart(final Entity target, final CallbackInfo ci, final float baseDamage, final ItemStack weapon, final DamageSource source) { + final var strengthScale = this.shadow$getAttackStrengthScale(0.5F); + this.forgeAttackImpl$attack = new DamageEventUtil.Attack<>((Player) (Object) this, target, weapon, source, strengthScale, baseDamage, new ArrayList<>()); + this.forgeAttackImpl$attackStrengthTicker = this.attackStrengthTicker; + this.forgeAttackImpl$isStrongSprintAttack = false; + } + + /** + * Captures the enchantment damage calculations as functions + */ + @Inject(method = "attack", at = @At(value = "INVOKE", ordinal = 0, + target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public void attackImpl$enchanttDamageFunc(final Entity $$0, final CallbackInfo ci) { + final var weapon = this.forgeAttackImpl$attack.weapon(); + // this.getEnchantedDamage(targetEntity, damage, damageSource) - damage; + final var functions = DamageEventUtil.createAttackEnchantmentFunction(weapon, this.forgeAttackImpl$attack.target(), this.forgeAttackImpl$attack.dmgSource()); + final var separateFunc = DamageEventUtil.provideSeparateEnchantmentFromBaseDamageFunction(this.forgeAttackImpl$attack.baseDamage(), weapon); + // enchantmentDamage *= attackStrength; + final var strengthScaleFunc = DamageEventUtil.provideCooldownEnchantmentStrengthFunction(weapon, this.forgeAttackImpl$attack.strengthScale()); + + this.forgeAttackImpl$attack.functions().addAll(functions); + this.forgeAttackImpl$attack.functions().add(separateFunc); + this.forgeAttackImpl$attack.functions().add(strengthScaleFunc); + } + + /** + * Captures the attack-strength damage scaling as a function + */ + @Inject(method = "attack", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;resetAttackStrengthTicker()V")) + public void attackImpl$attackStrengthScalingDamageFunc(final Entity $$0, final CallbackInfo ci) { + // damage *= 0.2F + attackStrength * attackStrength * 0.8F; + final var strengthScaleFunc = DamageEventUtil.provideCooldownAttackStrengthFunction((Player) (Object) this, this.forgeAttackImpl$attack.strengthScale()); + this.forgeAttackImpl$attack.functions().add(strengthScaleFunc); + } + + /** + * Prevents the {@link SoundEvents#PLAYER_ATTACK_KNOCKBACK} from playing before the event. + * Captures if {@link #forgeAttackImpl$isStrongSprintAttack} for later + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 0), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + public void attackImpl$preventSprintingAttackSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, final SoundEvent $$4, + final SoundSource $$5, final float $$6, final float $$7) { + // prevent sound + this.forgeAttackImpl$isStrongSprintAttack = true; + } + + /** + * Captures the weapon bonus damage as a function + */ + @Inject(method = "attack", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public void attackImpl$attackDamageFunc(final Entity $$0, final CallbackInfo ci) { + // damage += weaponItem.getItem().getAttackDamageBonus(targetEntity, damage, damageSource); + + final var bonusDamageFunc = DamageEventUtil.provideWeaponAttackDamageBonusFunction( this.forgeAttackImpl$attack.target(), this.forgeAttackImpl$attack.weapon(), this.forgeAttackImpl$attack.dmgSource()); + this.forgeAttackImpl$attack.functions().add(bonusDamageFunc); + } + + /** + * Crit Hook - Before vanilla decides + * Also captures the crit multiplier as a function + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 1), + to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;walkDist:F")), + at = @At(value = "INVOKE", target = "Lnet/minecraftforge/event/entity/player/CriticalHitEvent;getDamageModifier()F") + ) + public float attackImpl$critHook(final CriticalHitEvent forgeEvent) { + final var bonusDamageFunc = DamageEventUtil.provideCriticalAttackFunction(this.forgeAttackImpl$attack.sourceEntity(), forgeEvent.getDamageModifier()); + this.forgeAttackImpl$attack.functions().add(bonusDamageFunc); + return forgeEvent.getDamageModifier(); + } + + /** + * Capture damageSource for sweep attacks event later + * Calculate knockback earlier than vanilla for event + * call the AttackEntityEvent + * Play prevented sound from {@link #attackImpl$preventSprintingAttackSound} + * returns false if canceled, appearing for vanilla as an invulnerable target. {@link #attackImpl$onNoDamageSound} + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getDeltaMovement()Lnet/minecraft/world/phys/Vec3;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")) + public boolean attackImpl$onHurt(final Entity targetEntity, final DamageSource damageSource, final float mcDamage) { + + float knockbackModifier = this.shadow$getKnockback(targetEntity, damageSource) + (this.forgeAttackImpl$isStrongSprintAttack ? 1.0F : 0.0F); + this.forgeAttackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(this.forgeAttackImpl$attack, knockbackModifier); + + if (this.forgeAttackImpl$attackEvent.isCancelled()) { + // TODO this is actually not really doing anything because a ServerboundSwingPacket also resets it immediatly after + this.attackStrengthTicker = this.forgeAttackImpl$attackStrengthTicker; // Reset to old value + return false; + } + + this.forgeAttackImpl$finalDamageAmounts = AbstractModifierEvent.finalAmounts(this.forgeAttackImpl$attackEvent.originalDamage(), this.forgeAttackImpl$attackEvent.modifiers()); + + if (this.forgeAttackImpl$isStrongSprintAttack) { + // Play prevented sprint attack sound + this.impl$playAttackSound(this.forgeAttackImpl$attack.sourceEntity(), SoundEvents.PLAYER_ATTACK_KNOCKBACK); + } + + return targetEntity.hurt(damageSource, (float) this.forgeAttackImpl$attackEvent.finalOutputDamage()); + } + + /** + * Set enchantment damage with value from event + */ + @ModifyVariable(method = "attack", ordinal = 1, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V", ordinal = 0)), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$enchentmentDamageFromEvent(final float enchDmg) { + return this.forgeAttackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_enchantment"), 0.0).floatValue(); + } + + /** + * Redirects Player#getKnockback to the attack event value + */ + @Redirect(method = "attack", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$sweepHook(final Player instance, final Entity entity, final DamageSource damageSource) { + return this.forgeAttackImpl$attackEvent.knockbackModifier(); + } + + /** + * Prevents the {@link SoundEvents#PLAYER_ATTACK_NODAMAGE} when event was canceled + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;causeFoodExhaustion(F)V")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + public void attackImpl$onNoDamageSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, + final SoundEvent $$4, final SoundSource $$5, final float $$6, final float $$7) { + if (!this.forgeAttackImpl$attackEvent.isCancelled()) { + this.impl$playAttackSound($$0, SoundEvents.PLAYER_ATTACK_NODAMAGE); + } + } + + + /** + * Call Sweep Attack Events + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;distanceToSqr(Lnet/minecraft/world/entity/Entity;)D")) + public double attackImpl$beforeSweepHurt(final Player instance, final Entity sweepTarget) { + final var distanceToSqr = instance.distanceToSqr(sweepTarget); + if (!(distanceToSqr < 9.0)) { + return distanceToSqr; // Too far - no event + } + + final var mainAttack = this.forgeAttackImpl$attack; + final var mainAttackDamage = this.forgeAttackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_damage"), 0.0).floatValue(); + + var sweepAttack = new DamageEventUtil.Attack<>(mainAttack.sourceEntity(), sweepTarget, mainAttack.weapon(), mainAttack.dmgSource(), mainAttack.strengthScale(), 1, new ArrayList<>()); + // float sweepBaseDamage = 1.0F + (float)this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * attackDamage; + sweepAttack.functions().add(DamageEventUtil.provideSweepingDamageRatioFunction(mainAttack.weapon(), mainAttack.sourceEntity(), mainAttackDamage)); + // float sweepFullDamage = this.getEnchantedDamage(sweepTarget, sweepBaseDamage, $$3) * strengthScale; + sweepAttack.functions().addAll(DamageEventUtil.createAttackEnchantmentFunction(mainAttack.weapon(), sweepTarget, mainAttack.dmgSource())); + sweepAttack.functions().add(DamageEventUtil.provideCooldownEnchantmentStrengthFunction(mainAttack.weapon(), mainAttack.strengthScale())); + + this.forgeAttackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(sweepAttack, 1.0F); + if (forgeAttackImpl$attackEvent.isCancelled()) { + return Double.MAX_VALUE; + } + + return distanceToSqr; + } + + /** + * Redirect Player#getEnchantedDamage to sweep event value + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) + public float attackImpl$beforeSweepHurt(final Player instance, final Entity $$0, final float $$1, final DamageSource $$2) { + return (float) this.forgeAttackImpl$attackEvent.finalOutputDamage(); + } + + /** + * Redirect {@link LivingEntity#knockback} to use modified event knockback + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V")) + public void attackImpl$modifyKnockback(final LivingEntity instance, final double $$0, final double $$1, final double $$2) { + instance.knockback($$0 * this.forgeAttackImpl$attackEvent.knockbackModifier(), $$1, $$2); + } + + + /** + * Prevent vanilla {@link net.minecraft.world.entity.boss.EnderDragonPart#parentMob} resolution + * We use {@link #attackImpl$parentPartsHook} instead + */ + @Redirect(method = "attack", + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setLastHurtMob(Lnet/minecraft/world/entity/Entity;)V"), + to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;")), + at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/entity/boss/EnderDragonPart", ordinal = 0)) + public boolean attackImpl$parentPartsHookInstanceOf(final Object instance, final Class type) { + return false; + } + + /** + * Hook parent part resolution + */ + // TODO - Remove once https://github.com/MinecraftForge/MinecraftForge/pull/10011 is merged + @ModifyVariable(method = "attack", ordinal = 1, + slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;hurtEnemy(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/player/Player;)Z")), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;level()Lnet/minecraft/world/level/Level;")) + public Entity attackImpl$parentPartsHook(final Entity entity) { + if (entity instanceof PartEntity pe) { + return pe.getParent(); + } + return entity; + } + + /** + * Captures inventory changes + */ + @Redirect(method = "attack", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setItemInHand(Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;)V")) + public void attackImpl$causeInventoryCapture(final Player instance, final InteractionHand interactionHand, final ItemStack stack) { + instance.setItemInHand(interactionHand, stack); + + // Capture... + final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); + final TransactionalCaptureSupplier transactor = context.getTransactor(); + transactor.logPlayerInventoryChange(instance, PlayerInventoryTransaction.EventCreator.STANDARD); + this.inventoryMenu.broadcastChanges(); + } + + @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) + public boolean attackImpl$startActuallyHurt(final Player instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { + if (instance.isInvulnerableTo(damageSource)) { + return true; + } + // Call platform hook for adjusting damage + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + // TODO check for direct call? + this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); + return false; + } + + /** + * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 1, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", shift = At.Shift.AFTER)) + public float attackImpl$setFinalDamage(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtFinalDamage; + } + + /** + * Set absorbed damage after calling {@link Player#setAbsorptionAmount} in which we called the event + */ + @ModifyVariable(method = "actuallyHurt", ordinal = 2, + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V")), + at = @At(value = "STORE", ordinal = 0)) + public float attackImpl$setAbsorbed(final float value) { + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { + return 0; + } + return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); + } + + /** + * Cleanup + */ + @Inject(method = "actuallyHurt", at = @At("RETURN")) + public void attackImpl$afterActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$actuallyHurt = null; + this.attackImpl$actuallyHurtResult = null; + } + + +} diff --git a/forge/src/mixins/resources/mixins.spongeforge.core.json b/forge/src/mixins/resources/mixins.spongeforge.core.json index 5cfd7523621..d64113e6b66 100644 --- a/forge/src/mixins/resources/mixins.spongeforge.core.json +++ b/forge/src/mixins/resources/mixins.spongeforge.core.json @@ -1,45 +1,47 @@ { - "required": true, - "minVersion": "0.8", - "package": "org.spongepowered.forge.mixin.core", - "plugin": "org.spongepowered.forge.mixin.plugin.ForgeCorePlugin", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8", - "priority": 1301, - "mixins": [ - "api.event.EventMixin_Forge", - "api.event.block.ChangeBlockEvent_AllMixin_Forge", - "api.event.entity.ChangeEntityWorldEvent_PreMixin_Forge", - "api.event.entity.ChangeEventWorldEvent_PostMixin_Forge", - "commands.CommandsMixin_Forge", - "minecraftforge.MinecraftForgeMixin_Forge", - "minecraftforge.event.entity.EntityTravelToDimensionEventMixin_Forge", - "minecraftforge.event.entity.player.PlayerEvent_PlayerChangedDimensionEventMixin_Forge", - "minecraftforge.event.world.BlockEvent_BreakEventMixin_Forge", - "minecraftforge.event.world.BlockEventMixin_Forge", - "minecraftforge.internal.BrandingControlMixin_Forge", - "minecraftforge.registries.ForgeRegistryMixin_Forge", - "minecraftforge.registries.RegistryManagerMixin_Forge", - "network.ConnectionMixin_Forge", - "server.BootstrapMixin_Forge", - "server.MinecraftServerMixin_Forge", - "server.commands.SpreadPlayersCommandMixin_Forge", - "server.level.ServerPlayerMixin_Forge", - "server.network.ServerGamePacketListenerImplMixin_Forge", - "server.network.ServerLoginPacketListenerImplMixin_Forge", - "world.entity.LivingEntityMixin_Forge", - "world.entity.item.ItemEntityMixin_Forge", - "world.entity.player.PlayerMixin_Forge", - "world.entity.projectile.ThrownEnderpealMixin_Forge", - "world.entity.vehicle.BoatMixin_Forge", - "world.level.block.FireBlockMixin_Forge", - "world.level.block.entity.AbstractFurnaceBlockEntityMixin_Forge" - ], - "client": [ - "client.MinecraftMixin_Forge", - "client.main.MainMixin_Forge" - ], - "server": [ - "server.MainMixin_Forge" + "required": true, + "minVersion": "0.8", + "package": "org.spongepowered.forge.mixin.core", + "plugin": "org.spongepowered.forge.mixin.plugin.ForgeCorePlugin", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8", + "priority": 1301, + "mixins": [ + "api.event.EventMixin_Forge", + "api.event.block.ChangeBlockEvent_AllMixin_Forge", + "api.event.entity.ChangeEntityWorldEvent_PreMixin_Forge", + "api.event.entity.ChangeEventWorldEvent_PostMixin_Forge", + "commands.CommandsMixin_Forge", + "minecraftforge.MinecraftForgeMixin_Forge", + "minecraftforge.event.entity.EntityTravelToDimensionEventMixin_Forge", + "minecraftforge.event.entity.player.PlayerEvent_PlayerChangedDimensionEventMixin_Forge", + "minecraftforge.event.world.BlockEvent_BreakEventMixin_Forge", + "minecraftforge.event.world.BlockEventMixin_Forge", + "minecraftforge.internal.BrandingControlMixin_Forge", + "minecraftforge.registries.ForgeRegistryMixin_Forge", + "minecraftforge.registries.RegistryManagerMixin_Forge", + "network.ConnectionMixin_Forge", + "server.BootstrapMixin_Forge", + "server.MinecraftServerMixin_Forge", + "server.commands.SpreadPlayersCommandMixin_Forge", + "server.level.ServerPlayerMixin_Forge", + "server.network.ServerGamePacketListenerImplMixin_Forge", + "server.network.ServerLoginPacketListenerImplMixin_Forge", + "world.entity.LivingEntityMixin_Forge", + "world.entity.LivingEntityMixin_Forge_Attack_impl", + "world.entity.item.ItemEntityMixin_Forge", + "world.entity.player.PlayerMixin_Forge", + "world.entity.player.PlayerMixin_Forge_Attack_Impl", + "world.entity.projectile.ThrownEnderpealMixin_Forge", + "world.entity.vehicle.BoatMixin_Forge", + "world.level.block.FireBlockMixin_Forge", + "world.level.block.entity.AbstractFurnaceBlockEntityMixin_Forge" + ], + "client": [ + "client.MinecraftMixin_Forge", + "client.main.MainMixin_Forge" + ], + "server": [ + "server.MainMixin_Forge" ] } From 6b09c6964342aa8d96790085eef38bca750bd956 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 16 Jun 2024 21:08:28 -0700 Subject: [PATCH 172/226] chore: clean up unused hooks for vanilla attack implementation --- .../spongepowered/forge/SpongeForgeMod.java | 2 - .../forge/hook/ForgeEntityHooks.java | 41 ----------------- .../forge/hook/ForgeItemHooks.java | 13 ------ .../LivingEntityMixin_Forge_Attack_impl.java | 6 --- .../player/PlayerMixin_Forge_Attack_Impl.java | 1 - .../common/hooks/EntityHooks.java | 5 --- .../spongepowered/common/hooks/ItemHooks.java | 11 ----- .../player/PlayerMixin_Attack_Impl.java | 44 ------------------- 8 files changed, 123 deletions(-) delete mode 100644 forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java diff --git a/forge/src/main/java/org/spongepowered/forge/SpongeForgeMod.java b/forge/src/main/java/org/spongepowered/forge/SpongeForgeMod.java index ab7f881d4e0..200740664e5 100644 --- a/forge/src/main/java/org/spongepowered/forge/SpongeForgeMod.java +++ b/forge/src/main/java/org/spongepowered/forge/SpongeForgeMod.java @@ -54,7 +54,6 @@ import org.spongepowered.common.network.channel.SpongeChannelManager; import org.spongepowered.common.network.packet.SpongePacketHandler; import org.spongepowered.forge.hook.ForgeChannelHooks; -import org.spongepowered.forge.hook.ForgeEntityHooks; import org.spongepowered.forge.hook.ForgeEventHooks; import org.spongepowered.forge.hook.ForgeGeneralHooks; import org.spongepowered.forge.hook.ForgeItemHooks; @@ -81,7 +80,6 @@ public SpongeForgeMod() { // Set platform hooks as required PlatformHooks.INSTANCE.setEventHooks(new ForgeEventHooks()); - PlatformHooks.INSTANCE.setEntityHooks(new ForgeEntityHooks()); PlatformHooks.INSTANCE.setWorldHooks(new ForgeWorldHooks()); PlatformHooks.INSTANCE.setGeneralHooks(new ForgeGeneralHooks()); PlatformHooks.INSTANCE.setChannelHooks(new ForgeChannelHooks()); diff --git a/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java b/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java deleted file mode 100644 index 713b5710630..00000000000 --- a/forge/src/main/java/org/spongepowered/forge/hook/ForgeEntityHooks.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.forge.hook; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraftforge.common.ForgeHooks; -import net.minecraftforge.entity.PartEntity; -import org.spongepowered.common.hooks.EntityHooks; - -public class ForgeEntityHooks implements EntityHooks { - @Override - public Entity getParentPart(final Entity entity) { - if (entity instanceof PartEntity pe) { - return pe.getParent(); - } - return entity; - } -} diff --git a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java index d3e8d0437d8..7698314caa6 100644 --- a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java +++ b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java @@ -24,21 +24,8 @@ */ package org.spongepowered.forge.hook; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.common.ToolActions; import org.spongepowered.common.hooks.ItemHooks; public class ForgeItemHooks implements ItemHooks { - @Override - public boolean canPerformSweepAttack(ItemStack heldItem) { - return heldItem.canPerformAction(ToolActions.SWORD_SWEEP); - } - @Override - public AABB getSweepingHitBox(Player player, ItemStack itemStack, Entity targetEntity) { - return itemStack.getSweepHitBox(player, targetEntity); - } } diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java index 2f8216ad561..85a85492994 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java @@ -24,7 +24,6 @@ */ package org.spongepowered.forge.mixin.core.world.entity; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.stats.Stat; @@ -36,18 +35,13 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; -import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.Level; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Coerce; -import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java index d0ad3615fba..8a30349cb21 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java @@ -55,7 +55,6 @@ import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.hooks.PlatformHooks; import org.spongepowered.common.util.DamageEventUtil; import org.spongepowered.forge.mixin.core.world.entity.LivingEntityMixin_Forge_Attack_impl; diff --git a/src/main/java/org/spongepowered/common/hooks/EntityHooks.java b/src/main/java/org/spongepowered/common/hooks/EntityHooks.java index 1253b826244..471609a73b9 100644 --- a/src/main/java/org/spongepowered/common/hooks/EntityHooks.java +++ b/src/main/java/org/spongepowered/common/hooks/EntityHooks.java @@ -26,14 +26,9 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.boss.EnderDragonPart; -import net.minecraft.world.entity.player.Player; public interface EntityHooks { - default boolean checkAttackEntity(final Player player, final Entity victim) { - return true; - } - default Entity getParentPart(final Entity entity) { if (entity instanceof EnderDragonPart edp) { return edp.parentMob; diff --git a/src/main/java/org/spongepowered/common/hooks/ItemHooks.java b/src/main/java/org/spongepowered/common/hooks/ItemHooks.java index 04438eb698f..0c2c4c94d67 100644 --- a/src/main/java/org/spongepowered/common/hooks/ItemHooks.java +++ b/src/main/java/org/spongepowered/common/hooks/ItemHooks.java @@ -24,12 +24,8 @@ */ package org.spongepowered.common.hooks; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.SwordItem; import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.phys.AABB; public interface ItemHooks { @@ -37,11 +33,4 @@ default boolean canEnchantmentBeAppliedToItem(final Enchantment enchantment, fin return enchantment.canEnchant(stack); } - default boolean canPerformSweepAttack(ItemStack heldItem) { - return heldItem.getItem() instanceof SwordItem; - } - - default AABB getSweepingHitBox(Player player, ItemStack itemStack, Entity targetEntity) { - return targetEntity.getBoundingBox().inflate(1.0D, 0.25D, 1.0D); - } } diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index 366ad6c33c7..c951983a976 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -35,7 +35,6 @@ import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; import org.checkerframework.checker.nullness.qual.NonNull; import org.objectweb.asm.Opcodes; import org.spongepowered.api.ResourceKey; @@ -95,17 +94,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i this.attackImpl$finalDamageAmounts = null; } - /** - * checkAttackEntity Hook - */ - @Inject(method = "attack", cancellable = true, at = @At("HEAD")) - public void attackImpl$beforeAttackStart(final Entity target, final CallbackInfo ci){ - final var thisPlayer = (Player) (Object) this; - if (!PlatformHooks.INSTANCE.getEntityHooks().checkAttackEntity(thisPlayer, target)) { - ci.cancel(); - } - } - /** * Captures the base damage for the {@link AttackEntityEvent} in {@link #attackImpl$attack} * and the {@link #attackStrengthTicker} in case we need to roll it back. @@ -197,18 +185,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i return critResult.criticalHit; } - /** - * Sweep Hook - Redirects instanceOf SwordItem - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getHealth()F", ordinal = 0)), - at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/item/SwordItem")) - public boolean attackImpl$sweepHook(final Object instance, final Class type) { - var stack = this.shadow$getItemInHand(InteractionHand.MAIN_HAND); - return PlatformHooks.INSTANCE.getItemHooks().canPerformSweepAttack(stack); - } - /** * Capture damageSource for sweep attacks event later * Calculate knockback earlier than vanilla for event @@ -274,15 +250,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i } } - /** - * Sweep hit box Hook - */ - @Redirect(method = "attack", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/AABB;inflate(DDD)Lnet/minecraft/world/phys/AABB;")) - public AABB attackImpl$onSweepHitBox(final AABB instance, final double $$0, final double $$1, final double $$2) { - final var thisPlayer = (Player) (Object) this; - return PlatformHooks.INSTANCE.getItemHooks().getSweepingHitBox(thisPlayer, thisPlayer.getWeaponItem(), this.attackImpl$attack.target()); - } /** * Call Sweep Attack Events @@ -348,17 +315,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i return false; } - /** - * Hook parent part resolution - */ - @ModifyVariable(method = "attack", ordinal = 1, - slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;hurtEnemy(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/player/Player;)Z")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;level()Lnet/minecraft/world/level/Level;")) - public Entity attackImpl$parentPartsHook(final Entity entity) { - return PlatformHooks.INSTANCE.getEntityHooks().getParentPart(entity); - } - /** * Captures inventory changes */ From d44f62de80b87e8eea37fd1965199894395571b6 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sat, 22 Jun 2024 20:39:06 -0700 Subject: [PATCH 173/226] chore(deps): update forge pointer --- forge/gradle.properties | 2 +- gradle/verification-metadata.xml | 78 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/forge/gradle.properties b/forge/gradle.properties index e201e5ab1f5..1867ebeceef 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -2,7 +2,7 @@ name=SpongeForge implementation=Forge description=The SpongeAPI implementation for MinecraftForge -forgeVersion=51.0.0 +forgeVersion=51.0.17 loom.platform=forge fabric.loom.dontRemap=true mixinConfigs=mixins.spongeforge.accessors.json,mixins.spongeforge.api.json,mixins.spongeforge.inventory.json,mixins.spongeforge.core.json,mixins.spongeforge.tracker.json \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 9cc87ecb6c9..a0d0b90c2b0 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -138,6 +138,14 @@ + + + + + + + + @@ -162,6 +170,14 @@ + + + + + + + + @@ -2553,6 +2569,14 @@ + + + + + + + + @@ -2577,6 +2601,14 @@ + + + + + + + + @@ -2601,6 +2633,14 @@ + + + + + + + + @@ -2643,6 +2683,20 @@ + + + + + + + + + + + + + + @@ -2691,6 +2745,14 @@ + + + + + + + + @@ -2715,6 +2777,14 @@ + + + + + + + + @@ -2739,6 +2809,14 @@ + + + + + + + + From 0bfd06118fc5ce3b7e7e0147887bbc779cab7caf Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 23 Jun 2024 19:46:42 -0700 Subject: [PATCH 174/226] fix: re-merge attack implementation Also updates Forge dependency for forge related fixes Signed-off-by: Gabriel Harris-Rouquette --- .../player/PlayerMixin_Forge_Attack_Impl.java | 389 --------------- .../resources/mixins.spongeforge.core.json | 2 - .../mixin/core/world/entity/EntityMixin.java | 1 - .../entity/LivingEntityMixin_Attack_Impl.java | 44 +- .../world/entity/MobMixin_Attack_Impl.java | 8 +- .../player/PlayerMixin_Attack_Impl.java | 20 +- src/mixins/resources/mixins.sponge.core.json | 3 + .../entity/LivingEntityMixin_Attack_impl.java | 446 +----------------- .../resources/mixins.spongevanilla.core.json | 2 - 9 files changed, 44 insertions(+), 871 deletions(-) delete mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java rename forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java => src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java (93%) rename {vanilla/src/mixins/java/org/spongepowered/vanilla => src/mixins/java/org/spongepowered/common}/mixin/core/world/entity/MobMixin_Attack_Impl.java (93%) rename {vanilla/src/mixins/java/org/spongepowered/vanilla => src/mixins/java/org/spongepowered/common}/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java (95%) diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java deleted file mode 100644 index 8a30349cb21..00000000000 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/player/PlayerMixin_Forge_Attack_Impl.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.forge.mixin.core.world.entity.player; - -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.entity.PartEntity; -import net.minecraftforge.event.entity.player.CriticalHitEvent; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.event.entity.AttackEntityEvent; -import org.spongepowered.api.event.impl.entity.AbstractModifierEvent; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import org.spongepowered.common.event.tracking.PhaseContext; -import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.util.DamageEventUtil; -import org.spongepowered.forge.mixin.core.world.entity.LivingEntityMixin_Forge_Attack_impl; - -import java.util.ArrayList; -import java.util.Map; - -@SuppressWarnings("ConstantConditions") -@Mixin(value = Player.class, priority = 900) -public abstract class PlayerMixin_Forge_Attack_Impl extends LivingEntityMixin_Forge_Attack_impl { - - //@formatter:off - @Shadow @Final public InventoryMenu inventoryMenu; - @Shadow public abstract float shadow$getAttackStrengthScale(final float $$0); - - //@formatter:on - - private void impl$playAttackSound(Player thisPlayer, SoundEvent sound) { - if (this.bridge$vanishState().createsSounds()) { - thisPlayer.level().playSound(null, thisPlayer.getX(), thisPlayer.getY(), thisPlayer.getZ(), sound, thisPlayer.getSoundSource()); - } - } - - private DamageEventUtil.Attack forgeAttackImpl$attack; - private AttackEntityEvent forgeAttackImpl$attackEvent; - private Map forgeAttackImpl$finalDamageAmounts; - - private int forgeAttackImpl$attackStrengthTicker; - private boolean forgeAttackImpl$isStrongSprintAttack; - - /** - * Cleanup - */ - @Inject(method = "attack", at = @At("RETURN")) - public void attackImpl$onReturnCleanup(final Entity $$0, final CallbackInfo ci) { - this.forgeAttackImpl$attack = null; - this.forgeAttackImpl$attackEvent = null; - this.forgeAttackImpl$finalDamageAmounts = null; - } - - /** - * Captures the base damage for the {@link AttackEntityEvent} in {@link #forgeAttackImpl$attack} - * and the {@link #attackStrengthTicker} in case we need to roll it back. - * Reset {@link #forgeAttackImpl$isStrongSprintAttack} - */ - @Inject(method = "attack", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F", shift = At.Shift.BEFORE)) - public void attackImpl$captureAttackStart(final Entity target, final CallbackInfo ci, final float baseDamage, final ItemStack weapon, final DamageSource source) { - final var strengthScale = this.shadow$getAttackStrengthScale(0.5F); - this.forgeAttackImpl$attack = new DamageEventUtil.Attack<>((Player) (Object) this, target, weapon, source, strengthScale, baseDamage, new ArrayList<>()); - this.forgeAttackImpl$attackStrengthTicker = this.attackStrengthTicker; - this.forgeAttackImpl$isStrongSprintAttack = false; - } - - /** - * Captures the enchantment damage calculations as functions - */ - @Inject(method = "attack", at = @At(value = "INVOKE", ordinal = 0, - target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) - public void attackImpl$enchanttDamageFunc(final Entity $$0, final CallbackInfo ci) { - final var weapon = this.forgeAttackImpl$attack.weapon(); - // this.getEnchantedDamage(targetEntity, damage, damageSource) - damage; - final var functions = DamageEventUtil.createAttackEnchantmentFunction(weapon, this.forgeAttackImpl$attack.target(), this.forgeAttackImpl$attack.dmgSource()); - final var separateFunc = DamageEventUtil.provideSeparateEnchantmentFromBaseDamageFunction(this.forgeAttackImpl$attack.baseDamage(), weapon); - // enchantmentDamage *= attackStrength; - final var strengthScaleFunc = DamageEventUtil.provideCooldownEnchantmentStrengthFunction(weapon, this.forgeAttackImpl$attack.strengthScale()); - - this.forgeAttackImpl$attack.functions().addAll(functions); - this.forgeAttackImpl$attack.functions().add(separateFunc); - this.forgeAttackImpl$attack.functions().add(strengthScaleFunc); - } - - /** - * Captures the attack-strength damage scaling as a function - */ - @Inject(method = "attack", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/player/Player;resetAttackStrengthTicker()V")) - public void attackImpl$attackStrengthScalingDamageFunc(final Entity $$0, final CallbackInfo ci) { - // damage *= 0.2F + attackStrength * attackStrength * 0.8F; - final var strengthScaleFunc = DamageEventUtil.provideCooldownAttackStrengthFunction((Player) (Object) this, this.forgeAttackImpl$attack.strengthScale()); - this.forgeAttackImpl$attack.functions().add(strengthScaleFunc); - } - - /** - * Prevents the {@link SoundEvents#PLAYER_ATTACK_KNOCKBACK} from playing before the event. - * Captures if {@link #forgeAttackImpl$isStrongSprintAttack} for later - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 0), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) - public void attackImpl$preventSprintingAttackSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, final SoundEvent $$4, - final SoundSource $$5, final float $$6, final float $$7) { - // prevent sound - this.forgeAttackImpl$isStrongSprintAttack = true; - } - - /** - * Captures the weapon bonus damage as a function - */ - @Inject(method = "attack", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/item/Item;getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) - public void attackImpl$attackDamageFunc(final Entity $$0, final CallbackInfo ci) { - // damage += weaponItem.getItem().getAttackDamageBonus(targetEntity, damage, damageSource); - - final var bonusDamageFunc = DamageEventUtil.provideWeaponAttackDamageBonusFunction( this.forgeAttackImpl$attack.target(), this.forgeAttackImpl$attack.weapon(), this.forgeAttackImpl$attack.dmgSource()); - this.forgeAttackImpl$attack.functions().add(bonusDamageFunc); - } - - /** - * Crit Hook - Before vanilla decides - * Also captures the crit multiplier as a function - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 1), - to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;walkDist:F")), - at = @At(value = "INVOKE", target = "Lnet/minecraftforge/event/entity/player/CriticalHitEvent;getDamageModifier()F") - ) - public float attackImpl$critHook(final CriticalHitEvent forgeEvent) { - final var bonusDamageFunc = DamageEventUtil.provideCriticalAttackFunction(this.forgeAttackImpl$attack.sourceEntity(), forgeEvent.getDamageModifier()); - this.forgeAttackImpl$attack.functions().add(bonusDamageFunc); - return forgeEvent.getDamageModifier(); - } - - /** - * Capture damageSource for sweep attacks event later - * Calculate knockback earlier than vanilla for event - * call the AttackEntityEvent - * Play prevented sound from {@link #attackImpl$preventSprintingAttackSound} - * returns false if canceled, appearing for vanilla as an invulnerable target. {@link #attackImpl$onNoDamageSound} - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getDeltaMovement()Lnet/minecraft/world/phys/Vec3;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")) - public boolean attackImpl$onHurt(final Entity targetEntity, final DamageSource damageSource, final float mcDamage) { - - float knockbackModifier = this.shadow$getKnockback(targetEntity, damageSource) + (this.forgeAttackImpl$isStrongSprintAttack ? 1.0F : 0.0F); - this.forgeAttackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(this.forgeAttackImpl$attack, knockbackModifier); - - if (this.forgeAttackImpl$attackEvent.isCancelled()) { - // TODO this is actually not really doing anything because a ServerboundSwingPacket also resets it immediatly after - this.attackStrengthTicker = this.forgeAttackImpl$attackStrengthTicker; // Reset to old value - return false; - } - - this.forgeAttackImpl$finalDamageAmounts = AbstractModifierEvent.finalAmounts(this.forgeAttackImpl$attackEvent.originalDamage(), this.forgeAttackImpl$attackEvent.modifiers()); - - if (this.forgeAttackImpl$isStrongSprintAttack) { - // Play prevented sprint attack sound - this.impl$playAttackSound(this.forgeAttackImpl$attack.sourceEntity(), SoundEvents.PLAYER_ATTACK_KNOCKBACK); - } - - return targetEntity.hurt(damageSource, (float) this.forgeAttackImpl$attackEvent.finalOutputDamage()); - } - - /** - * Set enchantment damage with value from event - */ - @ModifyVariable(method = "attack", ordinal = 1, - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V", ordinal = 0)), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) - public float attackImpl$enchentmentDamageFromEvent(final float enchDmg) { - return this.forgeAttackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_enchantment"), 0.0).floatValue(); - } - - /** - * Redirects Player#getKnockback to the attack event value - */ - @Redirect(method = "attack", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getKnockback(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)F")) - public float attackImpl$sweepHook(final Player instance, final Entity entity, final DamageSource damageSource) { - return this.forgeAttackImpl$attackEvent.knockbackModifier(); - } - - /** - * Prevents the {@link SoundEvents#PLAYER_ATTACK_NODAMAGE} when event was canceled - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;causeFoodExhaustion(F)V")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) - public void attackImpl$onNoDamageSound(final Level instance, final Player $$0, final double $$1, final double $$2, final double $$3, - final SoundEvent $$4, final SoundSource $$5, final float $$6, final float $$7) { - if (!this.forgeAttackImpl$attackEvent.isCancelled()) { - this.impl$playAttackSound($$0, SoundEvents.PLAYER_ATTACK_NODAMAGE); - } - } - - - /** - * Call Sweep Attack Events - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;distanceToSqr(Lnet/minecraft/world/entity/Entity;)D")) - public double attackImpl$beforeSweepHurt(final Player instance, final Entity sweepTarget) { - final var distanceToSqr = instance.distanceToSqr(sweepTarget); - if (!(distanceToSqr < 9.0)) { - return distanceToSqr; // Too far - no event - } - - final var mainAttack = this.forgeAttackImpl$attack; - final var mainAttackDamage = this.forgeAttackImpl$finalDamageAmounts.getOrDefault(ResourceKey.minecraft("attack_damage"), 0.0).floatValue(); - - var sweepAttack = new DamageEventUtil.Attack<>(mainAttack.sourceEntity(), sweepTarget, mainAttack.weapon(), mainAttack.dmgSource(), mainAttack.strengthScale(), 1, new ArrayList<>()); - // float sweepBaseDamage = 1.0F + (float)this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * attackDamage; - sweepAttack.functions().add(DamageEventUtil.provideSweepingDamageRatioFunction(mainAttack.weapon(), mainAttack.sourceEntity(), mainAttackDamage)); - // float sweepFullDamage = this.getEnchantedDamage(sweepTarget, sweepBaseDamage, $$3) * strengthScale; - sweepAttack.functions().addAll(DamageEventUtil.createAttackEnchantmentFunction(mainAttack.weapon(), sweepTarget, mainAttack.dmgSource())); - sweepAttack.functions().add(DamageEventUtil.provideCooldownEnchantmentStrengthFunction(mainAttack.weapon(), mainAttack.strengthScale())); - - this.forgeAttackImpl$attackEvent = DamageEventUtil.callPlayerAttackEntityEvent(sweepAttack, 1.0F); - if (forgeAttackImpl$attackEvent.isCancelled()) { - return Double.MAX_VALUE; - } - - return distanceToSqr; - } - - /** - * Redirect Player#getEnchantedDamage to sweep event value - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getEnchantedDamage(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F")) - public float attackImpl$beforeSweepHurt(final Player instance, final Entity $$0, final float $$1, final DamageSource $$2) { - return (float) this.forgeAttackImpl$attackEvent.finalOutputDamage(); - } - - /** - * Redirect {@link LivingEntity#knockback} to use modified event knockback - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getEntitiesOfClass(Ljava/lang/Class;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V")) - public void attackImpl$modifyKnockback(final LivingEntity instance, final double $$0, final double $$1, final double $$2) { - instance.knockback($$0 * this.forgeAttackImpl$attackEvent.knockbackModifier(), $$1, $$2); - } - - - /** - * Prevent vanilla {@link net.minecraft.world.entity.boss.EnderDragonPart#parentMob} resolution - * We use {@link #attackImpl$parentPartsHook} instead - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setLastHurtMob(Lnet/minecraft/world/entity/Entity;)V"), - to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;")), - at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/entity/boss/EnderDragonPart", ordinal = 0)) - public boolean attackImpl$parentPartsHookInstanceOf(final Object instance, final Class type) { - return false; - } - - /** - * Hook parent part resolution - */ - // TODO - Remove once https://github.com/MinecraftForge/MinecraftForge/pull/10011 is merged - @ModifyVariable(method = "attack", ordinal = 1, - slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;hurtEnemy(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/player/Player;)Z")), - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;level()Lnet/minecraft/world/level/Level;")) - public Entity attackImpl$parentPartsHook(final Entity entity) { - if (entity instanceof PartEntity pe) { - return pe.getParent(); - } - return entity; - } - - /** - * Captures inventory changes - */ - @Redirect(method = "attack", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setItemInHand(Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;)V")) - public void attackImpl$causeInventoryCapture(final Player instance, final InteractionHand interactionHand, final ItemStack stack) { - instance.setItemInHand(interactionHand, stack); - - // Capture... - final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); - final TransactionalCaptureSupplier transactor = context.getTransactor(); - transactor.logPlayerInventoryChange(instance, PlayerInventoryTransaction.EventCreator.STANDARD); - this.inventoryMenu.broadcastChanges(); - } - - @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/player/Player;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) - public boolean attackImpl$startActuallyHurt(final Player instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { - if (instance.isInvulnerableTo(damageSource)) { - return true; - } - // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); - // TODO check for direct call? - this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); - return false; - } - - /** - * Set final damage after calling {@link Player#setAbsorptionAmount} in which we called the event - */ - @ModifyVariable(method = "actuallyHurt", ordinal = 1, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V", shift = At.Shift.AFTER)) - public float attackImpl$setFinalDamage(final float value) { - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - return 0; - } - return this.attackImpl$actuallyHurtFinalDamage; - } - - /** - * Set absorbed damage after calling {@link Player#setAbsorptionAmount} in which we called the event - */ - @ModifyVariable(method = "actuallyHurt", ordinal = 2, - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setAbsorptionAmount(F)V")), - at = @At(value = "STORE", ordinal = 0)) - public float attackImpl$setAbsorbed(final float value) { - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - return 0; - } - return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); - } - - /** - * Cleanup - */ - @Inject(method = "actuallyHurt", at = @At("RETURN")) - public void attackImpl$afterActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { - this.attackImpl$actuallyHurt = null; - this.attackImpl$actuallyHurtResult = null; - } - - -} diff --git a/forge/src/mixins/resources/mixins.spongeforge.core.json b/forge/src/mixins/resources/mixins.spongeforge.core.json index d64113e6b66..3df2dd135bc 100644 --- a/forge/src/mixins/resources/mixins.spongeforge.core.json +++ b/forge/src/mixins/resources/mixins.spongeforge.core.json @@ -28,10 +28,8 @@ "server.network.ServerGamePacketListenerImplMixin_Forge", "server.network.ServerLoginPacketListenerImplMixin_Forge", "world.entity.LivingEntityMixin_Forge", - "world.entity.LivingEntityMixin_Forge_Attack_impl", "world.entity.item.ItemEntityMixin_Forge", "world.entity.player.PlayerMixin_Forge", - "world.entity.player.PlayerMixin_Forge_Attack_Impl", "world.entity.projectile.ThrownEnderpealMixin_Forge", "world.entity.vehicle.BoatMixin_Forge", "world.level.block.FireBlockMixin_Forge", diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java index fc75500c9d8..62911ab93fe 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/EntityMixin.java @@ -181,7 +181,6 @@ public abstract class EntityMixin implements EntityBridge, PlatformEntityBridge, @Shadow public abstract boolean shadow$onGround(); @Shadow @Nullable protected abstract String shadow$getEncodeId(); @Shadow @javax.annotation.Nullable public PortalProcessor portalProcess; - // @formatter:on private boolean impl$isConstructing = true; diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java similarity index 93% rename from forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java rename to src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 85a85492994..2232f04e7c2 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -22,14 +22,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.forge.mixin.core.world.entity; +package org.spongepowered.common.mixin.core.world.entity; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; -import net.minecraft.stats.Stat; import net.minecraft.stats.Stats; import net.minecraft.tags.DamageTypeTags; -import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -40,11 +39,7 @@ import org.apache.logging.log4j.Level; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @@ -53,14 +48,15 @@ import org.spongepowered.common.bridge.world.entity.PlatformLivingEntityBridge; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.mixin.core.world.entity.EntityMixin; import org.spongepowered.common.util.DamageEventUtil; import org.spongepowered.common.util.PrettyPrinter; import java.util.ArrayList; +import javax.annotation.Nonnull; + @Mixin(value = LivingEntity.class, priority = 900) -public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin +public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin implements LivingEntityBridge, PlatformLivingEntityBridge { //@formatter:off @@ -70,14 +66,15 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin @Shadow protected abstract void shadow$blockUsingShield(final LivingEntity $$0); @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); @Shadow protected abstract float shadow$getKnockback(final Entity $$0, final DamageSource $$1); - @Shadow public abstract ItemStack shadow$getItemInHand(final InteractionHand $$0); @Shadow public abstract float shadow$getAbsorptionAmount(); @Shadow public abstract void setAbsorptionAmount(final float $$0); + @Shadow @Nonnull public abstract ItemStack shadow$getWeaponItem(); + @Shadow protected int attackStrengthTicker; @Shadow protected float lastHurt; - - + private float attackImpl$baseDamage; // @formatter:on + private float attackImpl$lastHurt; private int attackImpl$InvulnerableTime; @@ -108,6 +105,7 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, damageTaken)) { cir.setReturnValue(false); } + this.attackImpl$baseDamage = damageTaken; } /** @@ -176,6 +174,16 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin return 0; } + @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 0)) + private float attackImp$useBaseDamage1(final float $$0) { + return this.attackImpl$baseDamage - this.attackImpl$lastHurt; + } + + @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 1)) + private float attackImp$useBaseDamage2(final float $$0) { + return this.attackImpl$baseDamage; + } + /** * After calling #actuallyHurt (even when invulnerable), if cancelled return early or is still invulnerable * and reset {@link #lastHurt} and {@link #invulnerableTime} @@ -296,8 +304,8 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin * Prevents {@link ServerPlayer#awardStat} from running before event */ @Redirect(method = "getDamageAfterMagicAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/stats/Stat;I)V")) - public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final Stat stat, final int i) { + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/resources/ResourceLocation;I)V")) + public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final ResourceLocation resourceLocation, final int i) { // do nothing } @@ -386,10 +394,9 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin * * And capture inventory changes if needed */ - @Inject(method = "setHealth", at = @At("HEAD")) - public void attackImpl$afterActuallyHurtEvent(final float $$0, final CallbackInfo ci) { + protected void attackImpl$handlePostDamage() { final var result = this.attackImpl$actuallyHurtResult; - if (result != null) { + if (result != null && !this.attackImpl$actuallyHurtCancelled) { final var damageSource = result.source(); result.damageToShield().ifPresent(dmg -> { this.shadow$hurtCurrentlyUsedShield(dmg); @@ -428,6 +435,7 @@ public abstract class LivingEntityMixin_Forge_Attack_impl extends EntityMixin */ @Inject(method = "actuallyHurt", at = @At("RETURN")) public void attackImpl$cleanupActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { + this.attackImpl$handlePostDamage(); this.attackImpl$actuallyHurt = null; this.attackImpl$actuallyHurtResult = null; this.lastHurt = this.attackImpl$lastHurt; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin_Attack_Impl.java similarity index 93% rename from vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java rename to src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin_Attack_Impl.java index 4944659bdae..4142c751fad 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/MobMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/MobMixin_Attack_Impl.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.vanilla.mixin.core.world.entity; +package org.spongepowered.common.mixin.core.world.entity; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; @@ -37,7 +37,7 @@ import java.util.ArrayList; @Mixin(Mob.class) -public abstract class MobMixin_Attack_Impl extends LivingEntityMixin_Attack_impl { +public abstract class MobMixin_Attack_Impl extends LivingEntityMixin_Attack_Impl { private double impl$hurtTargetDamage; private double impl$knockbackModifier; @@ -56,8 +56,8 @@ public abstract class MobMixin_Attack_Impl extends LivingEntityMixin_Attack_impl float knockbackModifier = this.shadow$getKnockback(targetEntity, damageSource); - var attack = new DamageEventUtil.Attack<>(thisEntity, targetEntity, thisEntity.getWeaponItem(), damageSource, 1, (float) this.impl$hurtTargetDamage, new ArrayList<>()); - if (thisEntity.level() instanceof ServerLevel) { + var attack = new DamageEventUtil.Attack<>(thisEntity, targetEntity, this.shadow$getWeaponItem(), damageSource, 1, (float) this.impl$hurtTargetDamage, new ArrayList<>()); + if (this.shadow$level() instanceof ServerLevel) { // baseDamage = EnchantmentHelper.modifyDamage(level, thisEntity.getWeaponItem(), targetEntity, damageSource, baseDamage);// attack.functions().addAll(DamageEventUtil.createAttackEnchantmentFunction(attack.weapon(), targetEntity, damageSource)); } diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java similarity index 95% rename from vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java rename to src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index c951983a976..cccccefb39c 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.vanilla.mixin.core.world.entity.player; +package org.spongepowered.common.mixin.core.world.entity.player; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; @@ -55,15 +55,15 @@ import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.hooks.PlatformHooks; +import org.spongepowered.common.mixin.core.world.entity.LivingEntityMixin_Attack_Impl; import org.spongepowered.common.util.DamageEventUtil; -import org.spongepowered.vanilla.mixin.core.world.entity.LivingEntityMixin_Attack_impl; import java.util.ArrayList; import java.util.Map; @SuppressWarnings("ConstantConditions") @Mixin(value = Player.class, priority = 900) -public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_impl { +public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_Impl { //@formatter:off @Shadow @Final public InventoryMenu inventoryMenu; @@ -250,7 +250,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i } } - /** * Call Sweep Attack Events */ @@ -302,19 +301,6 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_i instance.knockback($$0 * this.attackImpl$attackEvent.knockbackModifier(), $$1, $$2); } - - /** - * Prevent vanilla {@link net.minecraft.world.entity.boss.EnderDragonPart#parentMob} resolution - * We use {@link #attackImpl$parentPartsHook} instead - */ - @Redirect(method = "attack", - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setLastHurtMob(Lnet/minecraft/world/entity/Entity;)V"), - to = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/EnderDragonPart;parentMob:Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;")), - at = @At(value = "CONSTANT", args = "classValue=net/minecraft/world/entity/boss/EnderDragonPart", ordinal = 0)) - public boolean attackImpl$parentPartsHookInstanceOf(final Object instance, final Class type) { - return false; - } - /** * Captures inventory changes */ diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 638b497bde8..b844181843a 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -117,7 +117,9 @@ "world.entity.LeashableMixin", "world.entity.LightningBoltMixin", "world.entity.LivingEntityMixin", + "world.entity.LivingEntityMixin_Attack_Impl", "world.entity.MobMixin", + "world.entity.MobMixin_Attack_Impl", "world.entity.PortalProcessorMixin", "world.entity.ai.goal.BreakDoorGoalMixin", "world.entity.ai.goal.BreedGoalMixin", @@ -158,6 +160,7 @@ "world.entity.npc.VillagerMixin", "world.entity.npc.WanderingTraderMixin", "world.entity.player.PlayerMixin", + "world.entity.player.PlayerMixin_Attack_Impl", "world.entity.projectile.AbstractArrowMixin", "world.entity.projectile.AbstractHurtingProjectileMixin", "world.entity.projectile.EyeOfEnderMixin", diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java index ce4e59cf7ec..1b539f7b9c0 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -24,465 +24,35 @@ */ package org.spongepowered.vanilla.mixin.core.world.entity; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.stats.Stats; -import net.minecraft.tags.DamageTypeTags; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.damagesource.CombatRules; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.animal.Wolf; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import org.apache.logging.log4j.Level; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Coerce; import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.bridge.world.entity.LivingEntityBridge; -import org.spongepowered.common.bridge.world.entity.PlatformLivingEntityBridge; -import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.mixin.core.world.entity.EntityMixin; -import org.spongepowered.common.util.DamageEventUtil; -import org.spongepowered.common.util.PrettyPrinter; -import java.util.ArrayList; @Mixin(value = LivingEntity.class, priority = 900) -public abstract class LivingEntityMixin_Attack_impl extends EntityMixin - implements LivingEntityBridge, PlatformLivingEntityBridge { - - //@formatter:off - @Shadow protected abstract void shadow$playHurtSound(DamageSource param0); - @Shadow protected abstract void shadow$hurtHelmet(final DamageSource $$0, final float $$1); - @Shadow protected abstract void shadow$hurtCurrentlyUsedShield(final float $$0); - @Shadow protected abstract void shadow$blockUsingShield(final LivingEntity $$0); - @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); - @Shadow protected abstract float shadow$getKnockback(final Entity $$0, final DamageSource $$1); - @Shadow public abstract ItemStack shadow$getItemInHand(final InteractionHand $$0); - @Shadow public abstract float shadow$getAbsorptionAmount(); - @Shadow public abstract void setAbsorptionAmount(final float $$0); - @Shadow protected int attackStrengthTicker; - @Shadow protected float lastHurt; - - - // @formatter:on - private float attackImpl$lastHurt; - private float attackImpl$baseDamage; - private int attackImpl$InvulnerableTime; - - protected DamageEventUtil.Hurt attackImpl$hurt; - protected DamageEventUtil.ActuallyHurt attackImpl$actuallyHurt; - protected DamageEventUtil.DamageEventResult attackImpl$actuallyHurtResult; - protected float attackImpl$actuallyHurtFinalDamage; - protected boolean attackImpl$actuallyHurtCancelled; - protected float attackImpl$actuallyHurtBlockedDamage; - protected boolean attackImpl$wasInInvulnerableTime; - - /** - * Forge onLivingAttack Hook - */ - @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) - private void attackImpl$beforeHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { - if (source == null) { - new PrettyPrinter(60).centre().add("Null DamageSource").hr() - .addWrapped("Sponge has found a null damage source! This should NEVER happen " - + "as the DamageSource is used for all sorts of calculations. Usually" - + " this can be considered developer error. Please report the following" - + " stacktrace to the most appropriate mod/plugin available.") - .add() - .add(new IllegalArgumentException("Null DamageSource")) - .log(SpongeCommon.logger(), Level.WARN); - cir.setReturnValue(false); - } - // Sponge - This hook is for forge use mainly - if (!this.bridge$onLivingAttack((LivingEntity) (Object) this, source, damageTaken)) { - cir.setReturnValue(false); - } - this.attackImpl$baseDamage = damageTaken; - } - - /** - * Prepare {@link org.spongepowered.common.util.DamageEventUtil.Hurt} for damage event - */ - @Inject(method = "hurt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;noActionTime:I")) - private void attackImpl$preventEarlyBlock1(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { - this.attackImpl$hurt = new DamageEventUtil.Hurt($$0, new ArrayList<>()); - } - - /** - * Prevents shield usage before event - * Captures the blocked damage as a function - */ - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtCurrentlyUsedShield(F)V")) - private void attackImpl$preventEarlyBlock1(final LivingEntity instance, final float damageToShield) { - // this.hurtCurrentlyUsedShield(damageToShield); - this.attackImpl$hurt.functions().add(DamageEventUtil.createShieldFunction(instance)); - } - - /** - * Prevents shield usage before event - */ - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;blockUsingShield(Lnet/minecraft/world/entity/LivingEntity;)V")) - private void attackImpl$preventEarlyBlock2(final LivingEntity instance, final LivingEntity livingDamageSource) { - // this.blockUsingShield(livingDamageSource); - } - - /** - * Capture the bonus freezing damage as a function - */ - @Inject(method = "hurt", at = @At(value = "CONSTANT", args = "floatValue=5.0F")) - private void attackImpl$freezingBonus(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { - this.attackImpl$hurt.functions().add(DamageEventUtil.createFreezingBonus((LivingEntity) (Object) this, $$0, 5.0F)); - } - - /** - * Prevents {@link #shadow$hurtHelmet} before the event - * Captures the hard hat damage reduction as a function - */ - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtHelmet(Lnet/minecraft/world/damagesource/DamageSource;F)V")) - private void attackImpl$hardHat(final LivingEntity instance, final DamageSource $$0, final float $$1) { - // this.hurtHelmet($$0, $$1); - this.attackImpl$hurt.functions().add(DamageEventUtil.createHardHatModifier(instance.getItemBySlot(EquipmentSlot.HEAD), 0.75F)); - } - - /** - * Capture the old values to reset if we end up cancelling or blocking. - * Also reset {@link #attackImpl$wasInInvulnerableTime} - */ - @Inject(method = "hurt", at = @At(value = "FIELD", - target = "Lnet/minecraft/world/entity/LivingEntity;walkAnimation:Lnet/minecraft/world/entity/WalkAnimationState;")) - private void attackImpl$beforeActuallyHurt(final DamageSource source, final float damageTaken, final CallbackInfoReturnable cir) { - // Save old values - this.attackImpl$lastHurt = this.lastHurt; - this.attackImpl$InvulnerableTime = this.invulnerableTime; - this.attackImpl$actuallyHurtCancelled = false; - - this.attackImpl$wasInInvulnerableTime = false; - } - - /** - * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable and remember that we did - */ - @Redirect(method = "hurt", - at = @At(value = "FIELD", ordinal = 0, - target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) - private float attackImpl$afterActuallyHurt(final LivingEntity instance) { - this.attackImpl$wasInInvulnerableTime = true; - return 0; - } - - @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 0)) - private float attackImp$useBaseDamage1(final float $$0) { - return this.attackImpl$baseDamage - this.attackImpl$lastHurt; - } - - @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 1)) - private float attackImp$useBaseDamage2(final float $$0) { - return this.attackImpl$baseDamage; - } - - /** - * After calling #actuallyHurt (even when invulnerable), if cancelled return early or is still invulnerable - * and reset {@link #lastHurt} and {@link #invulnerableTime} - */ - @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, - at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 0, - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) - private void attackImpl$afterActuallyHurt1(final DamageSource $$0, - final float damageTaken, - final CallbackInfoReturnable cir, - final float dealtDamage, - final boolean isBlocked - ) { - if (this.attackImpl$actuallyHurtCancelled || damageTaken <= this.lastHurt) { - this.invulnerableTime = this.attackImpl$InvulnerableTime; - this.lastHurt = this.attackImpl$lastHurt; - cir.setReturnValue(false); - } - } - - /** - * After calling #actuallyHurt, if cancelled return early - * Also reset values - */ - @Inject(method = "hurt", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, - at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 1, - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V")) - private void attackImpl$afterActuallyHurt2(final DamageSource $$0, - final float damageTaken, - final CallbackInfoReturnable cir, - final float dealtDamage, - final boolean isBlocked - ) { - if (this.attackImpl$actuallyHurtCancelled) { - this.invulnerableTime = this.attackImpl$InvulnerableTime; - cir.setReturnValue(false); - } - } - - - /** - * Set final damage after #actuallyHurt - */ - @ModifyVariable(method = "hurt", argsOnly = true, - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", - shift = At.Shift.AFTER)) - private float attackImpl$modifyDamageTaken(float damageTaken) { - return this.attackImpl$actuallyHurtFinalDamage; - } - - /** - * Sets blocked damage after #actuallyHurt - */ - @ModifyVariable(method = "hurt", ordinal = 2, - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", - shift = At.Shift.AFTER)) - private float attackImpl$modifyBlockedDamage(float damageBlocked) { - return this.attackImpl$actuallyHurtBlockedDamage; - } +public abstract class LivingEntityMixin_Attack_impl { @ModifyConstant(method = "hurt", constant = @Constant(classValue = Wolf.class, ordinal = 0)) - private Class attackImpl$onWolfCast(final Object entity, final Class wolf) { - // TODO for forge? check if this is actually working + private Class attackImpl$onWolfCast(Class constant) { return TamableAnimal.class; } - @Redirect(method = "hurt", - at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;isTame()Z")) - private boolean attackImpl$onWolfIsTame(@Coerce final Object instance) { - // TODO for forge? check if this is actually working - return ((TamableAnimal)instance).isTame(); - } + @Redirect(method = "hurt", + at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;isTame()Z")) + private boolean attackImpl$onWolfIsTame(@Coerce final Object instance) { + return ((TamableAnimal)instance).isTame(); + } @Redirect(method = "hurt", - at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;getOwner()Lnet/minecraft/world/entity/LivingEntity;")) + at = @At(value = "INVOKE" , target = "Lnet/minecraft/world/entity/animal/Wolf;getOwner()Lnet/minecraft/world/entity/LivingEntity;")) private LivingEntity attackImpl$onWolfGetOwner(@Coerce final Object instance) { - // TODO for forge? check if this is actually working return ((TamableAnimal)instance).getOwner(); } - - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;playHurtSound(Lnet/minecraft/world/damagesource/DamageSource;)V")) - private void attackImpl$onHurtSound(final LivingEntity instance, final DamageSource $$0) { - if (this.bridge$vanishState().createsSounds()) { - this.shadow$playHurtSound($$0); - } - } - - @Redirect(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;makeSound(Lnet/minecraft/sounds/SoundEvent;)V")) - private void attackImpl$onMakeSound(final LivingEntity instance, final SoundEvent $$0) { - if (this.bridge$vanishState().createsSounds()) { - instance.makeSound($$0); - } - } - - @Redirect(method = "actuallyHurt", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;isInvulnerableTo(Lnet/minecraft/world/damagesource/DamageSource;)Z")) - public boolean attackImpl$startActuallyHurt(final LivingEntity instance, final DamageSource damageSource, final DamageSource $$0, final float originalDamage) { - if (instance.isInvulnerableTo(damageSource)) { - return true; - } - var realOriginalDamage = originalDamage; - if (this.attackImpl$wasInInvulnerableTime) { - realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime - } - - // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); - // TODO check for direct call? - this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); - return false; - } - - /** - * Prevents LivingEntity#hurtArmor from running before event - * and capture the armor absorption as a function - */ - @Redirect(method = "getDamageAfterArmorAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtArmor(Lnet/minecraft/world/damagesource/DamageSource;F)V")) - public void attackImpl$onDamageAfterArmorAbsorb(final LivingEntity instance, final DamageSource $$0, final float $$1) { - if (this.attackImpl$actuallyHurt != null) { - // prevents this.hurtArmor($$0, $$1); - // $$1 = CombatRules.getDamageAfterAbsorb(this, $$1, $$0, (float)this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); - var func = DamageEventUtil.createArmorModifiers(instance, this.attackImpl$actuallyHurt.dmgSource()); - this.attackImpl$actuallyHurt.functions().add(func); - } - } - - /** - * Captures the damage resistance as a function - */ - @Inject(method = "getDamageAfterMagicAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getEffect(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/effect/MobEffectInstance;")) - public void attackImpl$onDamageAfterMagicAbsorb(final DamageSource $$0, final float $$1, final CallbackInfoReturnable cir) { - if (this.attackImpl$actuallyHurt != null) { - var func = DamageEventUtil.createResistanceModifier(this.attackImpl$actuallyHurt.entity()); - this.attackImpl$actuallyHurt.functions().add(func); - } - } - - /** - * Prevents {@link ServerPlayer#awardStat} from running before event - */ - @Redirect(method = "getDamageAfterMagicAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/resources/ResourceLocation;I)V")) - public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final ResourceLocation resourceLocation, final int i) { - // do nothing - } - - /** - * Captures the damage protection as a function - */ - @Redirect(method = "getDamageAfterMagicAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/CombatRules;getDamageAfterMagicAbsorb(FF)F")) - public float attackImpl$onDetDamageProtection(final float damage, final float protection) { - if (this.attackImpl$actuallyHurt != null) { - var func = DamageEventUtil.createEnchantmentModifiers(this.attackImpl$actuallyHurt.entity(), protection); - this.attackImpl$actuallyHurt.functions().add(func); - } - return CombatRules.getDamageAfterMagicAbsorb(damage, protection); - } - - /** - * Prevents setting absorption before event - * Captures the absorption amount as a functions - * Then calls the DamageEntityEvent - */ - @Inject(method = "setAbsorptionAmount", cancellable = true, at = @At("HEAD")) - public void attackImpl$onSetAbsorptionAmount(final float newAmount, final CallbackInfo ci) { - if (this.attackImpl$actuallyHurt != null) { - ci.cancel(); // Always cancel this - var oldAmount = this.shadow$getAbsorptionAmount(); - if (oldAmount > 0) { - var func = DamageEventUtil.createAbsorptionModifier(this.attackImpl$actuallyHurt.entity(), oldAmount); - this.attackImpl$actuallyHurt.functions().add(func); - } - - this.attackImpl$actuallyHurtResult = DamageEventUtil.callLivingDamageEntityEvent(this.attackImpl$hurt, this.attackImpl$actuallyHurt); - this.attackImpl$actuallyHurt = null; - - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - this.attackImpl$actuallyHurtCancelled = true; - this.attackImpl$actuallyHurtFinalDamage = 0; - this.attackImpl$actuallyHurtBlockedDamage = 0; - return; // Cancel vanilla behaviour by setting absorbed & finalDamage to 0 - } - - // TODO is this actually wrong? we are actually after functions - // (old comment was: Allow the platform to adjust damage before applying armor/etc) - this.attackImpl$actuallyHurtFinalDamage = this.bridge$applyModDamageBeforeFunctions( - (LivingEntity) (Object) (this), - this.attackImpl$actuallyHurtResult.source(), - (float) this.attackImpl$actuallyHurtResult.event().finalDamage()); - - this.attackImpl$actuallyHurtResult.damageAbsorbed().ifPresent(absorbed -> this.setAbsorptionAmount(oldAmount - absorbed)); - this.attackImpl$actuallyHurtBlockedDamage = this.attackImpl$actuallyHurtResult.damageBlockedByShield().orElse(0f); - } - } - - /** - * Set final damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event - * !!NOTE that var9 is actually decompiled incorrectly!! - * It is NOT the final damage value instead the method parameter is mutated - */ - @ModifyVariable(method = "actuallyHurt", ordinal = 0, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", - ordinal = 0, shift = At.Shift.AFTER), argsOnly = true) - public float attackImpl$setFinalDamage(final float value) { - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - return 0; - } - return this.attackImpl$actuallyHurtFinalDamage; - } - - /** - * Set absorbed damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event - */ - @ModifyVariable(method = "actuallyHurt", ordinal = 2, - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0)), - at = @At(value = "STORE", ordinal = 0)) - public float attackImpl$setAbsorbed(final float value) { - if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { - return 0; - } - return this.attackImpl$actuallyHurtResult.damageAbsorbed().orElse(0f); - } - - /** - * Replay prevented - * {@link #shadow$hurtCurrentlyUsedShield} and {@link #shadow$blockUsingShield} - * {@link #shadow$hurtHelmet} - * {@link #shadow$hurtArmor} - * {@link ServerPlayer#awardStat} for {@link Stats#DAMAGE_RESISTED} and {@link Stats#DAMAGE_DEALT} - * from {@link LivingEntity#hurt} and #actuallyHurt - * - * And capture inventory changes if needed - */ - protected void attackImpl$handlePostDamage() { - final var result = this.attackImpl$actuallyHurtResult; - if (result != null && !this.attackImpl$actuallyHurtCancelled) { - final var damageSource = result.source(); - result.damageToShield().ifPresent(dmg -> { - this.shadow$hurtCurrentlyUsedShield(dmg); - if (!damageSource.is(DamageTypeTags.IS_PROJECTILE)) { - if (damageSource.getDirectEntity() instanceof LivingEntity livingSource) { - this.shadow$blockUsingShield(livingSource); - } - } - }); - result.damageToHelmet().ifPresent(dmg -> - this.shadow$hurtHelmet(damageSource, dmg)); - result.damageToArmor().ifPresent(dmg -> - this.shadow$hurtArmor(damageSource, dmg)); - result.damageResisted().ifPresent(dmg -> { - if ((Object) this instanceof ServerPlayer player) { - player.awardStat(Stats.DAMAGE_RESISTED, Math.round(dmg * 10.0F)); - } else if (damageSource.getEntity() instanceof ServerPlayer player) { - player.awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(dmg * 10.0F)); - } - }); - - // Capture inventory change if we modified stacks - if ((result.damageToShield().isPresent() || - result.damageToHelmet().isPresent() || - result.damageToArmor().isPresent()) - && (Object) this instanceof Player player) { - PhaseTracker.SERVER.getPhaseContext().getTransactor().logPlayerInventoryChange(player, PlayerInventoryTransaction.EventCreator.STANDARD); - player.inventoryMenu.broadcastChanges(); // capture - } - } - } - - /** - * Cleanup - * also reverts {@link #attackImpl$beforeActuallyHurt} - */ - @Inject(method = "actuallyHurt", at = @At("RETURN")) - public void attackImpl$cleanupActuallyHurt(final DamageSource $$0, final float $$1, final CallbackInfo ci) { - this.attackImpl$handlePostDamage(); - this.attackImpl$actuallyHurt = null; - this.attackImpl$actuallyHurtResult = null; - this.lastHurt = this.attackImpl$lastHurt; - } - } diff --git a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json index 8110e3c8a58..fbdbc16fff4 100644 --- a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json +++ b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json @@ -37,10 +37,8 @@ "world.entity.EntityTypeMixin_Vanilla", "world.entity.LivingEntityMixin_Attack_impl", "world.entity.LivingEntityMixin_Vanilla", - "world.entity.MobMixin_Attack_Impl", "world.entity.ai.attributes.DefaultAttributesMixin", "world.entity.item.ItemEntityMixin_Vanilla", - "world.entity.player.PlayerMixin_Attack_Impl", "world.entity.vehicle.BoatMixin_Vanilla", "world.level.block.FireBlockMixin_Vanilla", "world.level.block.entity.AbstractFurnaceBlockEntityMixin_Vanilla", From 44fb9ed046728f35bf74c3ef7524f9aa0d63b78b Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 23 Jun 2024 20:05:11 -0700 Subject: [PATCH 175/226] fix: forge altered a small injection point for attack implementation --- .../LivingEntityMixin_Forge_Attack_Impl.java | 46 +++++++++++++++++++ .../resources/mixins.spongeforge.core.json | 1 + .../entity/LivingEntityMixin_Attack_Impl.java | 9 ---- .../entity/LivingEntityMixin_Attack_impl.java | 12 +++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_Impl.java diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_Impl.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_Impl.java new file mode 100644 index 00000000000..1cb83895595 --- /dev/null +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/entity/LivingEntityMixin_Forge_Attack_Impl.java @@ -0,0 +1,46 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.forge.mixin.core.world.entity; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin_Forge_Attack_Impl { + + /** + * Prevents {@link ServerPlayer#awardStat} from running before event + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/stats/Stat;I)V")) + public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final Stat resourceLocation, final int i) { + // do nothing + } + +} diff --git a/forge/src/mixins/resources/mixins.spongeforge.core.json b/forge/src/mixins/resources/mixins.spongeforge.core.json index 3df2dd135bc..2a80060ac44 100644 --- a/forge/src/mixins/resources/mixins.spongeforge.core.json +++ b/forge/src/mixins/resources/mixins.spongeforge.core.json @@ -28,6 +28,7 @@ "server.network.ServerGamePacketListenerImplMixin_Forge", "server.network.ServerLoginPacketListenerImplMixin_Forge", "world.entity.LivingEntityMixin_Forge", + "world.entity.LivingEntityMixin_Forge_Attack_Impl", "world.entity.item.ItemEntityMixin_Forge", "world.entity.player.PlayerMixin_Forge", "world.entity.projectile.ThrownEnderpealMixin_Forge", diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 2232f04e7c2..0e7f6a61739 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -24,7 +24,6 @@ */ package org.spongepowered.common.mixin.core.world.entity; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.stats.Stats; @@ -300,14 +299,6 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin } } - /** - * Prevents {@link ServerPlayer#awardStat} from running before event - */ - @Redirect(method = "getDamageAfterMagicAbsorb", - at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/resources/ResourceLocation;I)V")) - public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final ResourceLocation resourceLocation, final int i) { - // do nothing - } /** * Captures the damage protection as a function diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java index 1b539f7b9c0..8eb50752f01 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java @@ -24,6 +24,8 @@ */ package org.spongepowered.vanilla.mixin.core.world.entity; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.animal.Wolf; @@ -55,4 +57,14 @@ public abstract class LivingEntityMixin_Attack_impl { return ((TamableAnimal)instance).getOwner(); } + /** + * Prevents {@link ServerPlayer#awardStat} from running before event + */ + @Redirect(method = "getDamageAfterMagicAbsorb", + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;awardStat(Lnet/minecraft/resources/ResourceLocation;I)V")) + public void attackImpl$onAwardStatDamageResist(final ServerPlayer instance, final ResourceLocation resourceLocation, final int i) { + // do nothing + } + + } From b23af9f5f4a1251d2861132619f98d34a3f3b114 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 23 Jun 2024 20:05:32 -0700 Subject: [PATCH 176/226] fix: forge uses mojang named classes again --- forge/src/main/resources/forge.superclasschange | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/src/main/resources/forge.superclasschange b/forge/src/main/resources/forge.superclasschange index 8308902835f..d6e2705c885 100644 --- a/forge/src/main/resources/forge.superclasschange +++ b/forge/src/main/resources/forge.superclasschange @@ -1,3 +1,3 @@ { - "org.spongepowered.api.entity.ai.goal.AbstractGoal": "net.minecraft.entity.ai.goal.Goal" + "org.spongepowered.api.entity.ai.goal.AbstractGoal": "net.minecraft.world.entity.ai.goal.Goal" } \ No newline at end of file From 5e4edc46e8ed897002c2e6a0bef7b25750a5bef7 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 14 Jul 2024 19:18:13 -0700 Subject: [PATCH 177/226] chore: update Attack implementation mixin --- forge/gradle.properties | 2 +- gradle/verification-metadata.xml | 70 +++++++++++++++++++ .../entity/LivingEntityMixin_Attack_Impl.java | 28 +++++--- 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/forge/gradle.properties b/forge/gradle.properties index 1867ebeceef..23637da245d 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -2,7 +2,7 @@ name=SpongeForge implementation=Forge description=The SpongeAPI implementation for MinecraftForge -forgeVersion=51.0.17 +forgeVersion=51.0.22 loom.platform=forge fabric.loom.dontRemap=true mixinConfigs=mixins.spongeforge.accessors.json,mixins.spongeforge.api.json,mixins.spongeforge.inventory.json,mixins.spongeforge.core.json,mixins.spongeforge.tracker.json \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a0d0b90c2b0..0f01e33a5e0 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2545,6 +2545,14 @@ + + + + + + + + @@ -2577,6 +2585,14 @@ + + + + + + + + @@ -2609,6 +2625,14 @@ + + + + + + + + @@ -2641,6 +2665,14 @@ + + + + + + + + @@ -2697,6 +2729,20 @@ + + + + + + + + + + + + + + @@ -2753,6 +2799,14 @@ + + + + + + + + @@ -2785,6 +2839,14 @@ + + + + + + + + @@ -2817,6 +2879,14 @@ + + + + + + + + diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 0e7f6a61739..55bf60f9b28 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -28,6 +28,7 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.stats.Stats; import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -36,6 +37,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.Level; +import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.*; @@ -52,8 +54,6 @@ import java.util.ArrayList; -import javax.annotation.Nonnull; - @Mixin(value = LivingEntity.class, priority = 900) public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin implements LivingEntityBridge, PlatformLivingEntityBridge { @@ -65,10 +65,10 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin @Shadow protected abstract void shadow$blockUsingShield(final LivingEntity $$0); @Shadow protected abstract void shadow$hurtArmor(DamageSource source, float damage); @Shadow protected abstract float shadow$getKnockback(final Entity $$0, final DamageSource $$1); + @Shadow public abstract ItemStack shadow$getItemInHand(final InteractionHand $$0); @Shadow public abstract float shadow$getAbsorptionAmount(); + @Shadow public abstract @NonNull ItemStack shadow$getWeaponItem(); @Shadow public abstract void setAbsorptionAmount(final float $$0); - @Shadow @Nonnull public abstract ItemStack shadow$getWeaponItem(); - @Shadow protected int attackStrengthTicker; @Shadow protected float lastHurt; private float attackImpl$baseDamage; @@ -83,6 +83,7 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin protected float attackImpl$actuallyHurtFinalDamage; protected boolean attackImpl$actuallyHurtCancelled; protected float attackImpl$actuallyHurtBlockedDamage; + protected boolean attackImpl$wasInInvulnerableTime; /** * Forge onLivingAttack Hook @@ -153,6 +154,7 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin /** * Capture the old values to reset if we end up cancelling or blocking. + * Also reset {@link #attackImpl$wasInInvulnerableTime} */ @Inject(method = "hurt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;walkAnimation:Lnet/minecraft/world/entity/WalkAnimationState;")) @@ -161,15 +163,17 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin this.attackImpl$lastHurt = this.lastHurt; this.attackImpl$InvulnerableTime = this.invulnerableTime; this.attackImpl$actuallyHurtCancelled = false; + this.attackImpl$wasInInvulnerableTime = false; } /** - * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable. + * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable and remember that we did */ @Redirect(method = "hurt", at = @At(value = "FIELD", ordinal = 0, target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) private float attackImpl$afterActuallyHurt(final LivingEntity instance) { + this.attackImpl$wasInInvulnerableTime = true; return 0; } @@ -265,8 +269,13 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin if (instance.isInvulnerableTo(damageSource)) { return true; } + var realOriginalDamage = originalDamage; + if (this.attackImpl$wasInInvulnerableTime) { + realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime + } + // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); // TODO check for direct call? this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); return false; @@ -352,9 +361,12 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin /** * Set final damage after calling {@link LivingEntity#setAbsorptionAmount} in which we called the event + * !!NOTE that var9 is actually decompiled incorrectly!! + * It is NOT the final damage value instead the method parameter is mutated */ - @ModifyVariable(method = "actuallyHurt", ordinal = 1, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", ordinal = 0, shift = At.Shift.AFTER)) + @ModifyVariable(method = "actuallyHurt", ordinal = 0, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V", + ordinal = 0, shift = At.Shift.AFTER), argsOnly = true) public float attackImpl$setFinalDamage(final float value) { if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { return 0; From 4fddf8a49b367411e3a28e7b7c3b5108808ac1c6 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 11 Aug 2024 13:16:13 +0200 Subject: [PATCH 178/226] Fix wolf cast attack injection --- ...n_Attack_impl.java => LivingEntityMixin_Attack_Impl.java} | 5 +++-- vanilla/src/mixins/resources/mixins.spongevanilla.core.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) rename vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/{LivingEntityMixin_Attack_impl.java => LivingEntityMixin_Attack_Impl.java} (94%) diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java similarity index 94% rename from vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java rename to vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 8eb50752f01..0e03da3251f 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_impl.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -38,10 +38,11 @@ @Mixin(value = LivingEntity.class, priority = 900) -public abstract class LivingEntityMixin_Attack_impl { +public abstract class LivingEntityMixin_Attack_Impl { + @SuppressWarnings("InvalidInjectorMethodSignature") @ModifyConstant(method = "hurt", constant = @Constant(classValue = Wolf.class, ordinal = 0)) - private Class attackImpl$onWolfCast(Class constant) { + private Class attackImpl$onWolfCast(final Object entity, final Class wolf) { return TamableAnimal.class; } diff --git a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json index fbdbc16fff4..cbbac4390be 100644 --- a/vanilla/src/mixins/resources/mixins.spongevanilla.core.json +++ b/vanilla/src/mixins/resources/mixins.spongevanilla.core.json @@ -35,7 +35,7 @@ "server.packs.repository.PackRepositoryMixin_Vanilla", "world.entity.EntityMixin_Vanilla", "world.entity.EntityTypeMixin_Vanilla", - "world.entity.LivingEntityMixin_Attack_impl", + "world.entity.LivingEntityMixin_Attack_Impl", "world.entity.LivingEntityMixin_Vanilla", "world.entity.ai.attributes.DefaultAttributesMixin", "world.entity.item.ItemEntityMixin_Vanilla", From b0430ad0691b493beac9559f320c9cdb4b1d0ea3 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Tue, 13 Aug 2024 20:53:51 +0200 Subject: [PATCH 179/226] Update Forge to 52.0.3 --- forge/build.gradle.kts | 4 + forge/gradle.properties | 2 +- .../resource-templates/META-INF/mods.toml | 4 +- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 86 +++++++++++++++++++ 5 files changed, 94 insertions(+), 4 deletions(-) diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index 6e655604e1f..813a250e365 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -158,6 +158,10 @@ extensions.configure(LoomGradleExtensionAPI::class) { useLegacyMixinAp.set(false) } + forge { + useCustomMixin.set(false) + } + mods { named("main") { sourceSet(forgeMixins) diff --git a/forge/gradle.properties b/forge/gradle.properties index 23637da245d..6617e1b146e 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -2,7 +2,7 @@ name=SpongeForge implementation=Forge description=The SpongeAPI implementation for MinecraftForge -forgeVersion=51.0.22 +forgeVersion=52.0.3 loom.platform=forge fabric.loom.dontRemap=true mixinConfigs=mixins.spongeforge.accessors.json,mixins.spongeforge.api.json,mixins.spongeforge.inventory.json,mixins.spongeforge.core.json,mixins.spongeforge.tracker.json \ No newline at end of file diff --git a/forge/src/main/resource-templates/META-INF/mods.toml b/forge/src/main/resource-templates/META-INF/mods.toml index 2c2c89be5f3..b6a82ce527b 100644 --- a/forge/src/main/resource-templates/META-INF/mods.toml +++ b/forge/src/main/resource-templates/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[51,)" +loaderVersion="[52,)" license="MIT License" issueTrackerURL="https://github.com/SpongePowered/Sponge/issues" @@ -17,7 +17,7 @@ description = "{{ description }}" [[dependencies.spongeforge]] modId="forge" mandatory=true -versionRange="[51,)" +versionRange="[52,)" ordering="AFTER" side="BOTH" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 28e92afaa13..805458ce703 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ format = { version = "1.1" } asm = "9.7" log4j = "2.22.1" forgeAutoRenamingTool = "1.0.6" -mixin = "0.8.6" +mixin = "0.8.7" modlauncher = "8.1.3" guava = "32.1.2-jre" mockito = "5.11.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 0f01e33a5e0..dc6fd67f2f8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1364,6 +1364,14 @@ + + + + + + + + @@ -1854,6 +1862,14 @@ + + + + + + + + @@ -2593,6 +2609,14 @@ + + + + + + + + @@ -2633,6 +2657,14 @@ + + + + + + + + @@ -2673,6 +2705,14 @@ + + + + + + + + @@ -2743,6 +2783,20 @@ + + + + + + + + + + + + + + @@ -2807,6 +2861,14 @@ + + + + + + + + @@ -2847,6 +2909,14 @@ + + + + + + + + @@ -2887,6 +2957,14 @@ + + + + + + + + @@ -5686,6 +5764,14 @@ + + + + + + + + From 60bc74e42e3218a2302c13b12f6c326fa95706f2 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sat, 24 Aug 2024 01:06:12 +0200 Subject: [PATCH 180/226] Fix broken injections due to LVT changes --- ...AbstractFurnaceBlockEntityMixin_Forge.java | 26 ++++++------- .../entity/LivingEntityMixin_Attack_Impl.java | 2 +- .../world/level/block/CampfireBlockMixin.java | 25 ++++-------- .../entity/BrewingStandBlockEntityMixin.java | 22 ++++++----- ...stractFurnaceBlockEntityMixin_Vanilla.java | 39 +++++++++---------- 5 files changed, 53 insertions(+), 61 deletions(-) diff --git a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Forge.java b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Forge.java index ebff4495789..17110388566 100644 --- a/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Forge.java +++ b/forge/src/mixins/java/org/spongepowered/forge/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Forge.java @@ -147,16 +147,16 @@ public abstract class AbstractFurnaceBlockEntityMixin_Forge implements AbstractF final RegistryAccess registryAccess, final RecipeHolder recipe, final NonNullList slots, final int var2, final CallbackInfoReturnable cir, - final ItemStack $$4, final ItemStack $$5, final ItemStack $$6 + final ItemStack itemIn, final ItemStack recipeResult, final ItemStack itemOut ) { final AbstractFurnaceBlockEntityMixin_Forge mixinSelf = MixinTargetHelper.cast(this); final FurnaceBlockEntity entity = (FurnaceBlockEntity) this; final List transactions = new ArrayList<>(); - $$4.grow(1); - final ItemStackSnapshot originalSmeltItem = ItemStackUtil.snapshotOf($$4); - $$4.shrink(1); - transactions.add(new SlotTransaction(entity.inventory().slot(0).get(), originalSmeltItem, ItemStackUtil.snapshotOf($$4))); + itemIn.grow(1); + final ItemStackSnapshot originalSmeltItem = ItemStackUtil.snapshotOf(itemIn); + itemIn.shrink(1); + transactions.add(new SlotTransaction(entity.inventory().slot(0).get(), originalSmeltItem, ItemStackUtil.snapshotOf(itemIn))); final boolean hasFuel = !mixinSelf.forgeImpl$filledWaterBucket; if (mixinSelf.forgeImpl$filledWaterBucket) { @@ -164,17 +164,17 @@ public abstract class AbstractFurnaceBlockEntityMixin_Forge implements AbstractF } mixinSelf.forgeImpl$filledWaterBucket = false; - if ($$6.isEmpty()) { - transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), ItemStackSnapshot.empty(), ItemStackUtil.snapshotOf($$5))); - } else if (ItemStack.isSameItemSameComponents($$6, $$5)) { - $$6.shrink(1); - final ItemStackSnapshot originalResult = ItemStackUtil.snapshotOf($$6); - $$6.grow(1); - transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), originalResult, ItemStackUtil.snapshotOf($$6))); + if (itemOut.isEmpty()) { + transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), ItemStackSnapshot.empty(), ItemStackUtil.snapshotOf(recipeResult))); + } else if (ItemStack.isSameItemSameComponents(itemOut, recipeResult)) { + itemOut.shrink(1); + final ItemStackSnapshot originalResult = ItemStackUtil.snapshotOf(itemOut); + itemOut.grow(1); + transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), originalResult, ItemStackUtil.snapshotOf(itemOut))); } final Optional fuel = hasFuel && !slots.get(1).isEmpty() ? Optional.of(ItemStackUtil.snapshotOf(slots.get(1))) : Optional.empty(); final CookingEvent.Finish event = SpongeEventFactory.createCookingEventFinish(PhaseTracker.getCauseStackManager().currentCause(), entity, - fuel, Optional.ofNullable((CookingRecipe) recipe.value()), Optional.of((ResourceKey) (Object) recipe.id()), Collections.unmodifiableList(transactions)); + fuel, Optional.of((CookingRecipe) recipe.value()), Optional.of((ResourceKey) (Object) recipe.id()), Collections.unmodifiableList(transactions)); SpongeCommon.post(event); for (final SlotTransaction transaction : transactions) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 55bf60f9b28..4af5ed8c700 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -243,7 +243,7 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin */ @ModifyVariable(method = "hurt", ordinal = 2, at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", + target = "Lnet/minecraft/advancements/critereon/EntityHurtPlayerTrigger;trigger(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/damagesource/DamageSource;FFZ)V", shift = At.Shift.AFTER)) private float attackImpl$modifyBlockedDamage(float damageBlocked) { return this.attackImpl$actuallyHurtBlockedDamage; diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java index 9f394ecba60..8837646fa7d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/CampfireBlockMixin.java @@ -25,34 +25,23 @@ package org.spongepowered.common.mixin.core.world.level.block; import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSources; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CampfireCookingRecipe; -import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.CampfireBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.CampfireBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; 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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.common.bridge.world.level.block.entity.CampfireBlockEntityBridge; import org.spongepowered.common.mixin.core.block.BlockMixin; -import java.util.Optional; - @Mixin(CampfireBlock.class) public abstract class CampfireBlockMixin extends BlockMixin { @@ -71,11 +60,13 @@ public abstract class CampfireBlockMixin extends BlockMixin { return (DamageSource) blockSource; } - @Inject(method = "useItemOn", locals = LocalCapture.CAPTURE_FAILEXCEPTION, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/CampfireBlockEntity;placeFood(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;I)Z")) - public void impl$placeFood(ItemStack $$0, BlockState $$1, Level $$2, BlockPos $$3, Player $$4, InteractionHand $$5, BlockHitResult $$6, - CallbackInfoReturnable cir, - BlockEntity tileEntity, CampfireBlockEntity campfire, ItemStack itemStack, Optional> optional) { - ((CampfireBlockEntityBridge) campfire).bridge$placeRecipe(optional.get()); + @Redirect(method = "useItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/CampfireBlockEntity;placeFood(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;I)Z")) + public boolean impl$placeFood(final CampfireBlockEntity instance, final LivingEntity player, final ItemStack item, final int cookingTime) { + if (instance.placeFood(player, item, cookingTime)) { + ((CampfireBlockEntityBridge) instance).bridge$placeRecipe(instance.getCookableRecipe(item).get()); + return true; + } + return false; } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/BrewingStandBlockEntityMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/BrewingStandBlockEntityMixin.java index 970839e1867..f8991658e1a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/BrewingStandBlockEntityMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/entity/BrewingStandBlockEntityMixin.java @@ -47,6 +47,7 @@ import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.common.accessor.world.level.block.entity.BrewingStandBlockEntityAccessor; import org.spongepowered.common.inventory.adapter.InventoryAdapter; import org.spongepowered.common.inventory.adapter.impl.slots.SlotAdapter; import org.spongepowered.common.inventory.lens.Lens; @@ -105,18 +106,21 @@ public class BrewingStandBlockEntityMixin { } @Inject(method = "serverTick", - locals = LocalCapture.CAPTURE_FAILEXCEPTION, slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/world/item/alchemy/PotionBrewing;Lnet/minecraft/core/NonNullList;)Z")), at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;" + "setChanged(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V")) - private static void impl$callBrewEvents(final Level param0, final BlockPos param1, final BlockState param2, final BrewingStandBlockEntity param3, - final CallbackInfo ci, final ItemStack fuelStack, final boolean isBrewable, final boolean isBrewing, final ItemStack ingredientStack) { + private static void impl$callBrewEvents(final Level level, final BlockPos pos, final BlockState state, final BrewingStandBlockEntity entity, final CallbackInfo ci) { + final NonNullList items = ((BrewingStandBlockEntityAccessor) entity).accessor$items(); + final boolean isBrewable = BrewingStandBlockEntityAccessor.invoker$isBrewable(level.potionBrewing(), items); + final boolean isBrewing = ((BrewingStandBlockEntityAccessor) entity).accessor$brewTime() > 0; + final ItemStack ingredientStack = items.get(3); + final Cause currentCause = Sponge.server().causeStackManager().currentCause(); - final BrewingStandBlockEntityMixin mixinSelf = (BrewingStandBlockEntityMixin) (Object) param3; + final BrewingStandBlockEntityMixin mixinSelf = (BrewingStandBlockEntityMixin) (Object) entity; if (isBrewing) { if (mixinSelf.brewTime == 0 && isBrewable) { final List transactions = new ArrayList<>(); - final Lens lens = ((InventoryAdapter) param3).inventoryAdapter$getRootLens(); + final Lens lens = ((InventoryAdapter) entity).inventoryAdapter$getRootLens(); for (int i = 0; i < 4; ++i) { final ItemStack original = mixinSelf.impl$originalSlots[i]; final ItemStack replace = mixinSelf.items.get(i); @@ -125,23 +129,23 @@ public class BrewingStandBlockEntityMixin { continue; } transactions.add(new SlotTransaction( - (Slot) lens.getLens(i).getAdapter(((InventoryAdapter) param3).inventoryAdapter$getFabric(), ((BrewingStand) param3).inventory()), + (Slot) lens.getLens(i).getAdapter(((InventoryAdapter) entity).inventoryAdapter$getFabric(), ((BrewingStand) entity).inventory()), ItemStackUtil.snapshotOf(original), ItemStackUtil.snapshotOf(replace) )); } - final BrewingEvent.Finish event = SpongeEventFactory.createBrewingEventFinish(currentCause, (BrewingStand) param3, ItemStackUtil.snapshotOf(ingredientStack), Collections.unmodifiableList(transactions)); + final BrewingEvent.Finish event = SpongeEventFactory.createBrewingEventFinish(currentCause, (BrewingStand) entity, ItemStackUtil.snapshotOf(ingredientStack), Collections.unmodifiableList(transactions)); Sponge.eventManager().post(event); for (final SlotTransaction transaction : transactions) { transaction.custom().ifPresent(item -> mixinSelf.items.set(((SlotAdapter) transaction.slot()).getOrdinal(), ItemStackUtil.fromSnapshotToNative(item))); } } else if (!isBrewable || mixinSelf.ingredient != ingredientStack.getItem()) { - final BrewingEvent.Interrupt event = SpongeEventFactory.createBrewingEventInterrupt(currentCause, (BrewingStand) param3, ItemStackUtil.snapshotOf(ingredientStack)); + final BrewingEvent.Interrupt event = SpongeEventFactory.createBrewingEventInterrupt(currentCause, (BrewingStand) entity, ItemStackUtil.snapshotOf(ingredientStack)); Sponge.eventManager().post(event); } } else if (isBrewable && mixinSelf.fuel > 0) { - final BrewingEvent.Start event = SpongeEventFactory.createBrewingEventStart(currentCause, (BrewingStand) param3, ItemStackUtil.snapshotOf(ingredientStack)); + final BrewingEvent.Start event = SpongeEventFactory.createBrewingEventStart(currentCause, (BrewingStand) entity, ItemStackUtil.snapshotOf(ingredientStack)); if (Sponge.eventManager().post(event)) { mixinSelf.brewTime = 0; mixinSelf.ingredient = Items.AIR; diff --git a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Vanilla.java b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Vanilla.java index e83fa458bca..17c1a96221a 100644 --- a/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Vanilla.java +++ b/vanilla/src/mixins/java/org/spongepowered/vanilla/mixin/core/world/level/block/entity/AbstractFurnaceBlockEntityMixin_Vanilla.java @@ -50,7 +50,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.common.MixinTargetHelper; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.bridge.block.entity.AbstractFurnaceBlockEntityBridge; @@ -134,24 +133,22 @@ public abstract class AbstractFurnaceBlockEntityMixin_Vanilla extends BaseContai mixinSelf.vanilla$filledWaterBucket = true; } - @Inject( - method = "burn", - locals = LocalCapture.CAPTURE_FAILHARD, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;shrink(I)V", shift = At.Shift.AFTER)) - private static void vanillaImpl$afterSmeltItem(final RegistryAccess registryAccess, - final RecipeHolder recipe, final NonNullList slots, final int var2, final CallbackInfoReturnable cir, - final ItemStack $$4, final ItemStack $$5, final ItemStack $$6 - ) { + @Inject(method = "burn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;shrink(I)V", shift = At.Shift.AFTER)) + private static void vanillaImpl$afterSmeltItem(final RegistryAccess registryAccess, final RecipeHolder recipe, final NonNullList slots, final int var2, final CallbackInfoReturnable cir) { + final ItemStack itemIn = slots.get(0); + final ItemStack recipeResult = recipe.value().getResultItem(registryAccess); + final ItemStack itemOut = slots.get(2); + final Cause cause = PhaseTracker.getCauseStackManager().currentCause(); final FurnaceBlockEntity entity = cause.first(FurnaceBlockEntity.class) .orElseThrow(() -> new IllegalStateException("Expected to have a FurnaceBlockEntity in the Cause")); final AbstractFurnaceBlockEntityMixin_Vanilla mixinSelf = MixinTargetHelper.cast(entity); final List transactions = new ArrayList<>(); - $$4.grow(1); - final ItemStackSnapshot originalSmeltItem = ItemStackUtil.snapshotOf($$4); - $$4.shrink(1); - transactions.add(new SlotTransaction(entity.inventory().slot(0).get(), originalSmeltItem, ItemStackUtil.snapshotOf($$4))); + itemIn.grow(1); + final ItemStackSnapshot originalSmeltItem = ItemStackUtil.snapshotOf(itemIn); + itemIn.shrink(1); + transactions.add(new SlotTransaction(entity.inventory().slot(0).get(), originalSmeltItem, ItemStackUtil.snapshotOf(itemIn))); final boolean hasFuel = !mixinSelf.vanilla$filledWaterBucket; if (mixinSelf.vanilla$filledWaterBucket) { @@ -159,17 +156,17 @@ public abstract class AbstractFurnaceBlockEntityMixin_Vanilla extends BaseContai } mixinSelf.vanilla$filledWaterBucket = false; - if ($$6.isEmpty()) { - transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), ItemStackSnapshot.empty(), ItemStackUtil.snapshotOf($$5))); - } else if (ItemStack.isSameItemSameComponents($$6, $$5)) { - $$6.shrink(1); - final ItemStackSnapshot originalResult = ItemStackUtil.snapshotOf($$6); - $$6.grow(1); - transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), originalResult, ItemStackUtil.snapshotOf($$6))); + if (itemOut.isEmpty()) { + transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), ItemStackSnapshot.empty(), ItemStackUtil.snapshotOf(recipeResult))); + } else if (ItemStack.isSameItemSameComponents(itemOut, recipeResult)) { + itemOut.shrink(1); + final ItemStackSnapshot originalResult = ItemStackUtil.snapshotOf(itemOut); + itemOut.grow(1); + transactions.add(new SlotTransaction(entity.inventory().slot(2).get(), originalResult, ItemStackUtil.snapshotOf(itemOut))); } final Optional fuel = hasFuel && !slots.get(1).isEmpty() ? Optional.of(ItemStackUtil.snapshotOf(slots.get(1))) : Optional.empty(); final CookingEvent.Finish event = SpongeEventFactory.createCookingEventFinish(cause, entity, - fuel, Optional.ofNullable((CookingRecipe) recipe.value()), Optional.of((ResourceKey) (Object) recipe.id()), Collections.unmodifiableList(transactions)); + fuel, Optional.of((CookingRecipe) recipe.value()), Optional.of((ResourceKey) (Object) recipe.id()), Collections.unmodifiableList(transactions)); SpongeCommon.post(event); for (final SlotTransaction transaction : transactions) { From 2d52f70f2822e6e177e1be59bff9fdde81c9ec76 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sun, 25 Aug 2024 17:55:21 +0300 Subject: [PATCH 181/226] Fix SOE with DamageEntityEvent --- .../core/world/entity/LivingEntityMixin_Attack_Impl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 4af5ed8c700..55173c67718 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -337,9 +337,12 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin this.attackImpl$actuallyHurt.functions().add(func); } - this.attackImpl$actuallyHurtResult = DamageEventUtil.callLivingDamageEntityEvent(this.attackImpl$hurt, this.attackImpl$actuallyHurt); + // Use local and clear the variable to prevent re-entry if a plugin modifies the absorption hearts inside the event. + final DamageEventUtil.ActuallyHurt actuallyHurt = this.attackImpl$actuallyHurt; this.attackImpl$actuallyHurt = null; + this.attackImpl$actuallyHurtResult = DamageEventUtil.callLivingDamageEntityEvent(this.attackImpl$hurt, actuallyHurt); + if (this.attackImpl$actuallyHurtResult.event().isCancelled()) { this.attackImpl$actuallyHurtCancelled = true; this.attackImpl$actuallyHurtFinalDamage = 0; From 79abad414668d608ee8756036fdad911fcd6d78d Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 13 Aug 2024 03:42:26 +0700 Subject: [PATCH 182/226] Implement ItemStackLike --- SpongeAPI | 2 +- .../common/item/SpongeItemStackSnapshot.java | 61 +++++++++++++------ .../world/item/ItemStackMixin_API.java | 20 +++--- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 42dc372340a..2bc0eec7f1c 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 42dc372340aa68a7ea28a5ffa90b68c25af09661 +Subproject commit 2bc0eec7f1c4a7312a8c5dd7382331c208997112 diff --git a/src/main/java/org/spongepowered/common/item/SpongeItemStackSnapshot.java b/src/main/java/org/spongepowered/common/item/SpongeItemStackSnapshot.java index abd9ecd8a4b..989ec9f0261 100644 --- a/src/main/java/org/spongepowered/common/item/SpongeItemStackSnapshot.java +++ b/src/main/java/org/spongepowered/common/item/SpongeItemStackSnapshot.java @@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; import net.minecraft.core.component.DataComponentPatch; import org.checkerframework.checker.nullness.qual.Nullable; @@ -40,15 +41,19 @@ import org.spongepowered.api.data.persistence.InvalidDataException; import org.spongepowered.api.data.value.MergeFunction; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.type.AttributeType; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.data.SpongeDataHolderBridge; import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.common.util.Constants; +import java.util.Collection; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -119,20 +124,13 @@ public boolean isEmpty() { return this.privateStack.isEmpty(); } - public boolean isNone() { - throw new UnsupportedOperationException("Implement is empty"); + @Override + public Collection attributeModifiers(AttributeType attributeType, EquipmentType equipmentType) { + return this.privateStack.attributeModifiers(attributeType, equipmentType); } - @Override - public ItemStack createStack() { - final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.cloneDefensiveNative(ItemStackUtil.toNative(this.privateStack.copy())); - if(this.components != null) { - nativeStack.applyComponents(this.components); - } - for (final DataManipulator.Immutable manipulator : this.manipulators) { - ((ItemStack) (Object) nativeStack).copyFrom(manipulator); - } - return ItemStackUtil.fromNative(nativeStack); + public boolean isNone() { + throw new UnsupportedOperationException("Implement is empty"); } @Override @@ -142,7 +140,7 @@ public int contentVersion() { @Override public DataContainer toContainer() { - return SpongeItemStack.getDataContainer((net.minecraft.world.item.ItemStack) (Object) this.createStack()); + return SpongeItemStack.getDataContainer((net.minecraft.world.item.ItemStack) (Object) this.asMutable()); } @Override @@ -152,7 +150,7 @@ public Optional transform(final Key> k if (result.type() != DataTransactionResult.Type.SUCCESS) { return Optional.empty(); } - return Optional.of(copy.createSnapshot()); + return Optional.of(copy.asImmutable()); } @Override @@ -162,7 +160,7 @@ public Optional with(final Key> key, f if (result.type() != DataTransactionResult.Type.SUCCESS) { return Optional.empty(); } - return Optional.of(copy.createSnapshot()); + return Optional.of(copy.asImmutable()); } @Override @@ -186,6 +184,28 @@ public boolean supports(final Key key) { return this.privateStack.supports(key); } + @Override + public ItemStack asMutable() { + final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.cloneDefensiveNative(ItemStackUtil.toNative(this.privateStack.copy())); + if (this.components != null) { + nativeStack.applyComponents(this.components); + } + for (final DataManipulator.Immutable manipulator : this.manipulators) { + ((ItemStack) (Object) nativeStack).copyFrom(manipulator); + } + return ItemStackUtil.fromNative(nativeStack); + } + + @Override + public ItemStack asMutableCopy() { + return this.asMutable(); + } + + @Override + public ItemStackSnapshot asImmutable() { + return this; + } + @Override public ItemStackSnapshot copy() { return this; @@ -233,7 +253,7 @@ public void setCreator(final @Nullable UUID uuid) { public ItemStackSnapshot withRawData(DataView container) throws InvalidDataException { final ItemStack copy = this.privateStack.copy(); copy.setRawData(container); - return copy.createSnapshot(); + return copy.asImmutable(); } @Override @@ -243,14 +263,14 @@ public Optional without(Key key) { if (result.type() != DataTransactionResult.Type.SUCCESS) { return Optional.empty(); } - return Optional.of(copy.createSnapshot()); + return Optional.of(copy.asImmutable()); } @Override public ItemStackSnapshot mergeWith(ItemStackSnapshot that, MergeFunction function) { final ItemStack copy = this.privateStack.copy(); copy.copyFrom(that, function); - return copy.createSnapshot(); + return copy.asImmutable(); } @Override @@ -280,6 +300,11 @@ public int hashCode() { return Objects.hash(this.itemType, this.quantity, this.damageValue, this.components, this.creatorUniqueId); } + @Override + public Component asComponent() { + return this.privateStack.asComponent(); + } + @Override public HoverEvent asHoverEvent(final UnaryOperator op) { final ResourceKey resourceKey = Sponge.game().registry(RegistryTypes.ITEM_TYPE).valueKey(this.itemType); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/ItemStackMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/ItemStackMixin_API.java index 4f57f1d9060..cca0e04b102 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/ItemStackMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/ItemStackMixin_API.java @@ -97,10 +97,6 @@ public abstract class ItemStackMixin_API implements SerializableDataHolder.Mutab this.shadow$setCount(quantity); } - public int itemStack$maxStackQuantity() { - return this.shadow$getMaxStackSize(); - } - @Override public boolean validateRawData(final DataView container) { Objects.requireNonNull(container); @@ -122,6 +118,18 @@ public void setRawData(final DataView container) throws InvalidDataException { } } + public ItemStack itemStack$asMutable() { + return (ItemStack) this; + } + + public ItemStack itemStack$asMutableCopy() { + return this.itemStack$copy(); + } + + public ItemStackSnapshot itemStack$asImmutable() { + return new SpongeItemStackSnapshot((ItemStack) this); + } + @Override public SerializableDataHolder.Mutable copy() { return this.itemStack$copy(); @@ -168,10 +176,6 @@ public DataContainer toContainer() { return SpongeItemStack.getDataContainer((net.minecraft.world.item.ItemStack) (Object) this); } - public ItemStackSnapshot itemStack$createSnapshot() { - return new SpongeItemStackSnapshot((ItemStack) this); - } - public boolean itemStack$equalTo(final ItemStack that) { return net.minecraft.world.item.ItemStack.matches( (net.minecraft.world.item.ItemStack) (Object) this, From 59c0dfc7c772b3d610df4a781fa83f19b2b81261 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 13 Aug 2024 03:42:50 +0700 Subject: [PATCH 183/226] replace: createStack() -> asMutable() & createSnapshot() -> asImmutable() --- .../common/advancement/SpongeDisplayInfoBuilder.java | 2 +- .../common/command/sponge/SpongeCommand.java | 4 ++-- .../item/SpongeItemStackSnapshotDataBuilder.java | 2 +- .../common/event/inventory/InventoryEventFactory.java | 2 +- .../inventory/ClickCreativeMenuTransaction.java | 2 +- .../event/tracking/phase/packet/PacketContext.java | 2 +- .../event/tracking/phase/packet/PacketPhaseUtil.java | 4 ++-- .../inventory/InventoryTransactionResultImpl.java | 4 ++-- .../common/inventory/adapter/impl/AdapterLogic.java | 2 +- .../custom/SpongeViewableInventoryBuilder.java | 2 +- .../common/item/merchant/SpongeTradeOfferBuilder.java | 6 +++--- .../recipe/cooking/SpongeCookingRecipeBuilder.java | 2 +- .../shaped/SpongeShapedCraftingRecipeBuilder.java | 2 +- .../SpongeShapelessCraftingRecipeBuilder.java | 2 +- .../recipe/ingredient/SpongeIngredientBuilder.java | 2 +- .../recipe/smithing/SpongeSmithingRecipeBuilder.java | 2 +- .../stonecutting/SpongeStoneCutterRecipeBuilder.java | 2 +- .../spongepowered/common/item/util/ItemStackUtil.java | 8 ++++---- .../spongepowered/common/util/ParticleOptionUtil.java | 2 +- .../world/item/trading/MerchantOfferMixin_API.java | 6 +++--- .../common/mixin/core/item/EmptyMapItemMixin.java | 2 +- .../core/world/entity/projectile/FishingHookMixin.java | 2 +- .../java/org/spongepowered/test/data/DataTest.java | 8 ++++---- .../spongepowered/test/entity/DisplayEntityTest.java | 10 +++++----- .../java/org/spongepowered/test/entity/EntityTest.java | 2 +- .../spongepowered/test/inventory/InventoryTest.java | 4 ++-- .../org/spongepowered/test/particle/ParticleTest.java | 2 +- 27 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java b/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java index 51e7890f6ad..c65e7071f48 100644 --- a/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java +++ b/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java @@ -104,7 +104,7 @@ public DisplayInfo build() { final net.minecraft.network.chat.Component title = SpongeAdventure.asVanilla(this.title); final net.minecraft.network.chat.Component description = SpongeAdventure.asVanilla(this.description); final net.minecraft.advancements.AdvancementType frameType = (net.minecraft.advancements.AdvancementType) (Object) this.advancementType; - final ItemStack icon = (ItemStack) (Object) this.icon.createStack(); + final ItemStack icon = (ItemStack) (Object) this.icon.asMutable(); return (DisplayInfo) new net.minecraft.advancements.DisplayInfo(icon, title, description, null, frameType, this.showToast, this.announceToChat, this.hidden); } diff --git a/src/main/java/org/spongepowered/common/command/sponge/SpongeCommand.java b/src/main/java/org/spongepowered/common/command/sponge/SpongeCommand.java index fc787c07789..18627faedec 100644 --- a/src/main/java/org/spongepowered/common/command/sponge/SpongeCommand.java +++ b/src/main/java/org/spongepowered/common/command/sponge/SpongeCommand.java @@ -288,7 +288,7 @@ private Command.Parameterized infoSubcommand() { .content("Block Info: ") .color(TextColor.color(SpongeCommand.GREEN)) .append(Component.text(serverLocation.blockPosition().toString()) - .hoverEvent(ItemStack.builder().fromBlockState(serverLocation.block()).build().createSnapshot()) + .hoverEvent(ItemStack.builder().fromBlockState(serverLocation.block()).build().asImmutable()) ) .append(Component.newline()) .append(Component.text("Creator: ", TextColor.color(SpongeCommand.MINT))) @@ -324,7 +324,7 @@ private Command.Parameterized infoSubcommand() { .content("Block Info: ") .color(TextColor.color(SpongeCommand.GREEN)) .append(Component.text(locatableBlock.blockPosition().toString()) - .hoverEvent(ItemStack.builder().fromBlockState(locatableBlock.blockState()).build().createSnapshot()) + .hoverEvent(ItemStack.builder().fromBlockState(locatableBlock.blockState()).build().asImmutable()) ) .append(Component.newline()) .append(Component.text("Creator: ", TextColor.color(SpongeCommand.MINT))) diff --git a/src/main/java/org/spongepowered/common/data/builder/item/SpongeItemStackSnapshotDataBuilder.java b/src/main/java/org/spongepowered/common/data/builder/item/SpongeItemStackSnapshotDataBuilder.java index d9bae61a122..3f69d6d43be 100644 --- a/src/main/java/org/spongepowered/common/data/builder/item/SpongeItemStackSnapshotDataBuilder.java +++ b/src/main/java/org/spongepowered/common/data/builder/item/SpongeItemStackSnapshotDataBuilder.java @@ -43,6 +43,6 @@ public SpongeItemStackSnapshotDataBuilder() { @Override protected Optional buildContent(DataView container) throws InvalidDataException { - return SpongeItemStack.createItemStack(container).map(ItemStack::createSnapshot); + return SpongeItemStack.createItemStack(container).map(ItemStack::asImmutable); } } diff --git a/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java b/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java index 07c6de04c64..8bbf9b9fd43 100644 --- a/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java +++ b/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java @@ -110,7 +110,7 @@ public static boolean callPlayerInventoryPickupEvent(final Player player, final final TransactionalCaptureSupplier transactor = context.getTransactor(); try (final EffectTransactor ignored = transactor.logPlayerInventoryChangeWithEffect(player, PlayerInventoryTransaction.EventCreator.PICKUP)) { for (final ItemStackSnapshot item : list) { - final org.spongepowered.api.item.inventory.ItemStack itemStack = item.createStack(); + final org.spongepowered.api.item.inventory.ItemStack itemStack = item.asMutable(); player.getInventory().add(ItemStackUtil.toNative(itemStack)); if (!itemStack.isEmpty()) { // Modified pickup items do not fit inventory - pre-cancel ChangeInventoryEvent.Pickup diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ClickCreativeMenuTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ClickCreativeMenuTransaction.java index b8f7fcc5b66..281f3025672 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ClickCreativeMenuTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/ClickCreativeMenuTransaction.java @@ -74,7 +74,7 @@ Optional createInventoryEvent( ) { if (slotTransactions.isEmpty() && this.slotNum >= 0 && this.slot != null) { // No SlotTransaction was captured. So we add the clicked slot as a transaction with the creative stack - final ItemStackSnapshot item = this.slot.peek().createSnapshot(); + final ItemStackSnapshot item = this.slot.peek().asImmutable(); slotTransactions.add(new SlotTransaction(this.slot, item, this.creativeStack)); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketContext.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketContext.java index 136d919fb31..578068f5a90 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketContext.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketContext.java @@ -77,7 +77,7 @@ public > K getPacket() { public P itemUsed(final ItemStack stack) { this.itemUsed = stack; - this.itemUsedSnapshot = this.itemUsed.createSnapshot(); + this.itemUsedSnapshot = this.itemUsed.asImmutable(); return (P) this; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java index 3e6f610aaa2..aea3d5d144c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java @@ -92,10 +92,10 @@ public static void handleSlotRestore(@Nullable final Player player, final @Nulla final org.spongepowered.api.item.inventory.Slot slot = slotTransaction.slot(); final ItemStackSnapshot snapshot = eventCancelled || !slotTransaction.isValid() ? slotTransaction.original() : slotTransaction.custom().get(); if (containerMenu == null || slot.viewedSlot() instanceof Slot) { - slot.set(snapshot.createStack()); + slot.set(snapshot.asMutable()); } else if (player instanceof ServerPlayer serverPlayer && containerMenu != player.inventoryMenu && serverPlayer.inventory().containsInventory(slot)) { - final org.spongepowered.api.item.inventory.ItemStack stack = snapshot.createStack(); + final org.spongepowered.api.item.inventory.ItemStack stack = snapshot.asMutable(); slot.set(stack); ((net.minecraft.server.level.ServerPlayer) player).connection.send( new ClientboundContainerSetSlotPacket(-2, player.inventoryMenu.getStateId(), ((SlotAdapter) slot).getOrdinal(), ItemStackUtil.toNative(stack))); diff --git a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java index faff14a5820..709e711abf3 100644 --- a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java +++ b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java @@ -75,7 +75,7 @@ public InventoryTransactionResult and(InventoryTransactionResult other) { @Override public void revert() { for (SlotTransaction transaction : Lists.reverse(this.slotTransactions)) { - transaction.slot().set(transaction.original().createStack()); + transaction.slot().set(transaction.original().asMutable()); } } @@ -142,7 +142,7 @@ public InventoryTransactionResult.Builder reject(ItemStack... itemStacks) { } for (ItemStack itemStack1 : itemStacks) { if (!itemStack1.isEmpty()) { - this.rejected.add(itemStack1.createSnapshot()); + this.rejected.add(itemStack1.asImmutable()); } } return this; diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java index cbf15b4aa19..6ab2d5548f4 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java @@ -109,7 +109,7 @@ public static InventoryTransactionResult.Poll pollSequential(Fabric fabric, @Nul removedType.setQuantity(totalPolled); } - return result.poll(removedType.createSnapshot()).build(); + return result.poll(removedType.asImmutable()).build(); } public static Optional peekSequential(Fabric fabric, @Nullable Lens lens) { diff --git a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java index 4d04c948206..7c303f793e0 100644 --- a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java +++ b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java @@ -215,7 +215,7 @@ public BuildingStep grid(List source, Vector2i size, int offset) { // dummy @Override public BuildingStep item(ItemStackSnapshot item) { - this.lastSlot.set(item.createStack()); + this.lastSlot.set(item.asMutable()); return this; } diff --git a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java index 69dd24557da..39e2778eb6b 100644 --- a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java +++ b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java @@ -66,20 +66,20 @@ public SpongeTradeOfferBuilder() { @Override public TradeOffer.Builder firstBuyingItem(final ItemStack item) { Objects.requireNonNull(item, "Buying item cannot be null"); - this.firstItem = item.createSnapshot(); + this.firstItem = item.asImmutable(); return this; } @SuppressWarnings("ConstantConditions") @Override public TradeOffer.Builder secondBuyingItem(final ItemStack item) { - this.secondItem = item != null ? item.createSnapshot() : ItemStackSnapshot.empty(); + this.secondItem = item != null ? item.asImmutable() : ItemStackSnapshot.empty(); return this; } @Override public TradeOffer.Builder sellingItem(final ItemStack item) { - this.sellingItem = item.createSnapshot(); + this.sellingItem = item.asImmutable(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java index ba328b162e8..8f9929f9e78 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java @@ -100,7 +100,7 @@ public EndStep result(final org.spongepowered.api.item.inventory.ItemStack resul @Override public EndStep result(final ItemStackSnapshot result) { - return this.result(result.createStack()); + return this.result(result.asMutable()); } // currently unused diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java index cbc3331d1d2..0d17c326eaa 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java @@ -150,7 +150,7 @@ public ShapedCraftingRecipe.Builder.ResultStep remainingItems(Function snapshotOf(final List items) { @@ -155,11 +155,11 @@ public static List snapshotOf(final List, Object> generateDefaultsForNamed(P || type == ParticleTypes.FALLING_DUST || type == ParticleTypes.DUST_PILLAR) { options.put(ParticleOptions.BLOCK_STATE.get(), BlockTypes.AIR.get().defaultState()); } else if (type == ParticleTypes.ITEM) { - options.put(ParticleOptions.ITEM_STACK_SNAPSHOT.get(), ItemStack.of(ItemTypes.STONE).createSnapshot()); + options.put(ParticleOptions.ITEM_STACK_SNAPSHOT.get(), ItemStack.of(ItemTypes.STONE).asImmutable()); } else if (type == ParticleTypes.DUST) { options.put(ParticleOptions.COLOR.get(), Color.RED); options.put(ParticleOptions.SCALE.get(), 1.0d); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/trading/MerchantOfferMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/trading/MerchantOfferMixin_API.java index b3b25f14fb4..894ff40cded 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/trading/MerchantOfferMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/trading/MerchantOfferMixin_API.java @@ -55,7 +55,7 @@ public abstract class MerchantOfferMixin_API implements TradeOffer { @Override public ItemStackSnapshot firstBuyingItem() { - return ((ItemStack) (Object) this.shadow$getCostA()).createSnapshot(); + return ((ItemStack) (Object) this.shadow$getCostA()).asImmutable(); } @Override @@ -68,12 +68,12 @@ public Optional secondBuyingItem() { if (this.shadow$getCostB() == null) { return Optional.empty(); } - return Optional.of(((ItemStack) (Object) this.shadow$getCostB()).createSnapshot()); + return Optional.of(((ItemStack) (Object) this.shadow$getCostB()).asImmutable()); } @Override public ItemStackSnapshot sellingItem() { - return ((ItemStack) (Object) this.shadow$getResult()).createSnapshot(); + return ((ItemStack) (Object) this.shadow$getResult()).asImmutable(); } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/item/EmptyMapItemMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/item/EmptyMapItemMixin.java index 6bb0aeb5a62..9dd8afdc082 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/item/EmptyMapItemMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/item/EmptyMapItemMixin.java @@ -78,7 +78,7 @@ public abstract class EmptyMapItemMixin { frame.addContext(EventContextKeys.PLAYER, player); final HandType handType = (HandType) (Object) usedHand; frame.addContext(EventContextKeys.USED_HAND, handType); - frame.addContext(EventContextKeys.USED_ITEM, player.itemInHand(handType).createSnapshot()); + frame.addContext(EventContextKeys.USED_ITEM, player.itemInHand(handType).asImmutable()); final Set> mapValues = Sets.newHashSet( Value.immutableOf(Keys.MAP_LOCATION, Vector2i.from((int)playerIn.getX(), (int)playerIn.getZ())), diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/FishingHookMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/FishingHookMixin.java index 323795d0834..470c0bd30fb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/FishingHookMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/projectile/FishingHookMixin.java @@ -144,7 +144,7 @@ public int retrieve(final ItemStack stack) { if (!transaction.isValid()) { continue; } - final ItemStack itemstack = (ItemStack) (Object) transaction.finalReplacement().createStack(); + final ItemStack itemstack = (ItemStack) (Object) transaction.finalReplacement().asMutable(); // Sponge end final ItemEntity entityitem = new ItemEntity(this.shadow$level(), this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), itemstack); diff --git a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java index 84541eb6c7e..67d263c5a9d 100644 --- a/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/data/DataTest.java @@ -482,7 +482,7 @@ public void testData(final ServerPlayer player) { this.checkGetData(jungleAxe, Keys.DISPLAY_NAME, Component.translatable("chat.square_brackets").args(Component.empty().append(Component.text("Jungle Axe")).decorate(TextDecoration.ITALIC)) - .color(NamedTextColor.WHITE).hoverEvent(jungleAxe.createSnapshot().asHoverEvent())); + .color(NamedTextColor.WHITE).hoverEvent(jungleAxe.asImmutable().asHoverEvent())); this.checkGetData(shulkerBullet, Keys.DISPLAY_NAME, Component.text("Angry Shulker Bullet") .hoverEvent(HoverEvent.showEntity(ResourceKey.minecraft("shulker_bullet"), shulkerBullet.uniqueId(), Component.text("Angry Shulker Bullet"))) .insertion(shulkerBullet.uniqueId().toString())); @@ -968,14 +968,14 @@ public void testData(final ServerPlayer player) { this.checkGetData(jungleAxe, Keys.ITEM_RARITY, ItemRarities.COMMON.get()); this.checkGetData(playerHeadStack, Keys.ITEM_RARITY, ItemRarities.UNCOMMON.get()); - this.checkOfferData(itemEntity, Keys.ITEM_STACK_SNAPSHOT, jungleAxe.createSnapshot()); + this.checkOfferData(itemEntity, Keys.ITEM_STACK_SNAPSHOT, jungleAxe.asImmutable()); final Entity itemFrame = world.createEntity(EntityTypes.ITEM_FRAME.get(), position); - this.checkOfferData(itemFrame, Keys.ITEM_STACK_SNAPSHOT, stoneStack.createSnapshot()); + this.checkOfferData(itemFrame, Keys.ITEM_STACK_SNAPSHOT, stoneStack.asImmutable()); // TODO JukeBox // TODO Lectern final Entity potionEntity = world.createEntity(EntityTypes.POTION.get(), position); - this.checkOfferData(potionEntity, Keys.ITEM_STACK_SNAPSHOT, splashPotion.createSnapshot()); // TODO unset original value causes logging error + this.checkOfferData(potionEntity, Keys.ITEM_STACK_SNAPSHOT, splashPotion.asImmutable()); // TODO unset original value causes logging error // TODO Keys.KNOCKBACK_STRENGTH diff --git a/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java b/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java index 3d9c74a991a..f0317c60f4f 100644 --- a/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/entity/DisplayEntityTest.java @@ -94,7 +94,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { textDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.FIXED.get()); var itemDisplay = spawnEntity(player.world(), EntityTypes.ITEM_DISPLAY, centerPos, forwardDir, col2, 0); - itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.NETHERITE_INGOT).createSnapshot()); + itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.NETHERITE_INGOT).asImmutable()); itemDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.FIXED.get()); textDisplay = spawnEntity(player.world(), EntityTypes.TEXT_DISPLAY, centerPos, forwardDir, col1, 0); @@ -105,7 +105,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { textDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.CENTER.get()); itemDisplay = spawnEntity(player.world(), EntityTypes.ITEM_DISPLAY, centerPos, forwardDir, col2, 1); - itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.DIAMOND).createSnapshot()); + itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.DIAMOND).asImmutable()); itemDisplay.offer(Keys.BLOCK_LIGHT, 15); itemDisplay.offer(Keys.SKY_LIGHT, 15); itemDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.CENTER.get()); @@ -118,7 +118,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { textDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.HORIZONTAL.get()); itemDisplay = spawnEntity(player.world(), EntityTypes.ITEM_DISPLAY, centerPos, forwardDir, col2, 2); - itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.IRON_INGOT).createSnapshot()); + itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.IRON_INGOT).asImmutable()); itemDisplay.offer(Keys.BLOCK_LIGHT, 15); itemDisplay.offer(Keys.SKY_LIGHT, 0); itemDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.HORIZONTAL.get()); @@ -132,7 +132,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { textDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.VERTICAL.get()); itemDisplay = spawnEntity(player.world(), EntityTypes.ITEM_DISPLAY, centerPos, forwardDir, col2, 3); - itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.GOLD_INGOT).createSnapshot()); + itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.GOLD_INGOT).asImmutable()); itemDisplay.offer(Keys.BLOCK_LIGHT, 0); itemDisplay.offer(Keys.SKY_LIGHT, 15); itemDisplay.offer(Keys.BILLBOARD_TYPE, BillboardTypes.VERTICAL.get()); @@ -144,7 +144,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { textDisplay.offer(Keys.DISPLAY_NAME, Component.text("Low\nViewRange")); itemDisplay = spawnEntity(player.world(), EntityTypes.ITEM_DISPLAY, centerPos, forwardDir, col2, 4); - itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.EMERALD).createSnapshot()); + itemDisplay.offer(Keys.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.EMERALD).asImmutable()); itemDisplay.offer(Keys.VIEW_RANGE, 0.02); // 1 is supposed to be view range for fireballs in vanilla, 0.02 seems to be around a block diff --git a/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java b/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java index 7fb814a7561..e8a0a1c2338 100644 --- a/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/entity/EntityTest.java @@ -92,7 +92,7 @@ public void onRegisterCommand(final RegisterCommandEvent event) { final var item = Objects.requireNonNull(node.node("item").get(ItemStackSnapshot.class)); - player.setItemInHand(HandTypes.MAIN_HAND, item.createStack()); + player.setItemInHand(HandTypes.MAIN_HAND, item.asMutable()); } catch (ConfigurateException e) { throw new RuntimeException(e); } diff --git a/testplugins/src/main/java/org/spongepowered/test/inventory/InventoryTest.java b/testplugins/src/main/java/org/spongepowered/test/inventory/InventoryTest.java index 813a30d99a4..1af8e34d919 100644 --- a/testplugins/src/main/java/org/spongepowered/test/inventory/InventoryTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/inventory/InventoryTest.java @@ -194,7 +194,7 @@ private void onInteractContainer(final InteractContainerEvent event) { @Listener private void beforePickup(final ChangeInventoryEvent.Pickup.Pre event) { if (event.originalStack().type().isAnyOf(ItemTypes.BEDROCK)) { - final ItemStackSnapshot stack = ItemStack.of(ItemTypes.COBBLESTONE, 64).createSnapshot(); + final ItemStackSnapshot stack = ItemStack.of(ItemTypes.COBBLESTONE, 64).asImmutable(); final ArrayList items = new ArrayList<>(); event.setCustom(items); for (int i = 0; i < 100; i++) { @@ -333,7 +333,7 @@ public boolean handle(final Cause cause, final Container container, final Slot s case 45: case 53: this.last = ViewableInventory.builder().type(ContainerTypes.GENERIC_9X6.get()) - .fillDummy().item(slot.peek().createSnapshot()) + .fillDummy().item(slot.peek().asImmutable()) .completeStructure().plugin(this.plugin).build(); Sponge.server().scheduler().submit(Task.builder().execute(() -> this.menu.setCurrentInventory(this.last)).plugin(this.plugin).build()); break; diff --git a/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java b/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java index 0a101f6c267..e58f70dfdee 100644 --- a/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/particle/ParticleTest.java @@ -87,7 +87,7 @@ private void spawnParticles(ServerPlayer serverPlayer, ParticleType type) { .type(type) .option(ParticleOptions.BLOCK_STATE, BlockTypes.DIAMOND_BLOCK.get().defaultState()) .option(ParticleOptions.COLOR, Color.LIME) - .option(ParticleOptions.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.GOLDEN_APPLE.get()).createSnapshot()) + .option(ParticleOptions.ITEM_STACK_SNAPSHOT, ItemStack.of(ItemTypes.GOLDEN_APPLE.get()).asImmutable()) .offset(Vector3d.from(0, 1, 1)) .velocity(Vector3d.RIGHT.mul(0.5)) .quantity(20) From eff3d9302599870fba9fc61ce5388e31afcd21a6 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 10 Sep 2024 18:25:35 +0300 Subject: [PATCH 184/226] Update verification-metadata.xml --- gradle/verification-metadata.xml | 46 +++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 9f191f07979..71a029b3f74 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -501,6 +501,14 @@ + + + + + + + + @@ -524,6 +532,11 @@ + + + + + @@ -603,6 +616,14 @@ + + + + + + + + @@ -681,6 +702,11 @@ + + + + + @@ -1876,12 +1902,12 @@ - - - - - - + + + + + + @@ -2322,6 +2348,14 @@ + + + + + + + + From 858d535361178003f7d191f918ff8fc340605e86 Mon Sep 17 00:00:00 2001 From: aromaa Date: Fri, 13 Sep 2024 00:38:39 +0300 Subject: [PATCH 185/226] Don't fire damage event for invulnerability ticks --- .../entity/LivingEntityMixin_Attack_Impl.java | 19 +------------------ .../player/PlayerMixin_Attack_Impl.java | 7 +------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 55173c67718..4b342a73720 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -83,7 +83,6 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin protected float attackImpl$actuallyHurtFinalDamage; protected boolean attackImpl$actuallyHurtCancelled; protected float attackImpl$actuallyHurtBlockedDamage; - protected boolean attackImpl$wasInInvulnerableTime; /** * Forge onLivingAttack Hook @@ -163,18 +162,6 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin this.attackImpl$lastHurt = this.lastHurt; this.attackImpl$InvulnerableTime = this.invulnerableTime; this.attackImpl$actuallyHurtCancelled = false; - this.attackImpl$wasInInvulnerableTime = false; - } - - /** - * Fake {@link #lastHurt} to be 0 so that we go to #actuallyHurt even if we are invulnerable and remember that we did - */ - @Redirect(method = "hurt", - at = @At(value = "FIELD", ordinal = 0, - target = "Lnet/minecraft/world/entity/LivingEntity;lastHurt:F")) - private float attackImpl$afterActuallyHurt(final LivingEntity instance) { - this.attackImpl$wasInInvulnerableTime = true; - return 0; } @ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", ordinal = 0)) @@ -269,13 +256,9 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin if (instance.isInvulnerableTo(damageSource)) { return true; } - var realOriginalDamage = originalDamage; - if (this.attackImpl$wasInInvulnerableTime) { - realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime - } // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); // TODO check for direct call? this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); return false; diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java index cccccefb39c..b1de769b275 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java @@ -323,13 +323,8 @@ public abstract class PlayerMixin_Attack_Impl extends LivingEntityMixin_Attack_I return true; } - var realOriginalDamage = originalDamage; - if (this.attackImpl$wasInInvulnerableTime) { - realOriginalDamage = Math.max(0, realOriginalDamage); // No negative damage because of invulnerableTime - } - // Call platform hook for adjusting damage - final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, realOriginalDamage); + final var modAdjustedDamage = this.bridge$applyModDamage(instance, damageSource, originalDamage); // TODO check for direct call? this.attackImpl$actuallyHurt = new DamageEventUtil.ActuallyHurt(instance, new ArrayList<>(), damageSource, modAdjustedDamage); return false; From 345aa1d82b942e2be41a98fc2b58e71415761822 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Fri, 13 Sep 2024 17:12:01 +0300 Subject: [PATCH 186/226] Bump API --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 2bc0eec7f1c..c55e532c5e1 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 2bc0eec7f1c4a7312a8c5dd7382331c208997112 +Subproject commit c55e532c5e19dc6b0dcd2f62cc8989a949611dcb From 108b6c4b524c28028dec524a5011bb79641adbc8 Mon Sep 17 00:00:00 2001 From: aromaa Date: Fri, 13 Sep 2024 19:00:44 +0300 Subject: [PATCH 187/226] Pin VanillaGradle versio --- gradle/verification-metadata.xml | 51 ++++++++++++++++++++++++++++---- settings.gradle.kts | 2 +- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 9f191f07979..e3db472c750 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -501,6 +501,14 @@ + + + + + + + + @@ -524,6 +532,11 @@ + + + + + @@ -603,6 +616,14 @@ + + + + + + + + @@ -681,6 +702,11 @@ + + + + + @@ -1876,12 +1902,12 @@ - - - - - - + + + + + + @@ -2322,6 +2348,14 @@ + + + + + + + + @@ -5844,6 +5878,11 @@ + + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index 6ad57d49c5e..24cd27fbdf6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,7 +9,7 @@ pluginManagement { } plugins { - id("org.spongepowered.gradle.vanilla") version "0.2.1-SNAPSHOT" + id("org.spongepowered.gradle.vanilla") version "0.2.1-20240904.014811-86" id("implementation-structure") } } From 8bcb310ea4fe769f8af6581df23dba9dafd12636 Mon Sep 17 00:00:00 2001 From: aromaa Date: Fri, 13 Sep 2024 19:01:47 +0300 Subject: [PATCH 188/226] Move attack impl modifyDamageTaken after lastHurt --- .../core/world/entity/LivingEntityMixin_Attack_Impl.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java index 4b342a73720..19af0cfbaac 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java @@ -215,12 +215,13 @@ public abstract class LivingEntityMixin_Attack_Impl extends EntityMixin /** - * Set final damage after #actuallyHurt + * Set final damage after #actuallyHurt and lastHurt has been set. */ @ModifyVariable(method = "hurt", argsOnly = true, - at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSource;getEntity()Lnet/minecraft/world/entity/Entity;"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSource;getEntity()Lnet/minecraft/world/entity/Entity;"))) private float attackImpl$modifyDamageTaken(float damageTaken) { return this.attackImpl$actuallyHurtFinalDamage; } From 114d05882d6ea9bc5729c61f0a554b12e06f8ee1 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sat, 14 Sep 2024 04:00:32 +0300 Subject: [PATCH 189/226] Migrate recipes to ItemStackLike --- SpongeAPI | 2 +- .../item/recipe/SpongeRecipeInputFactory.java | 10 ++++----- .../cooking/SpongeCookingRecipeBuilder.java | 17 +++++--------- .../SpongeSpecialCraftingRecipeBuilder.java | 13 ++++++----- .../SpongeShapedCraftingRecipeBuilder.java | 22 +++++++------------ .../SpongeShapelessCraftingRecipeBuilder.java | 22 ++++++------------- .../recipe/ingredient/IngredientUtil.java | 3 ++- .../recipe/ingredient/SpongeIngredient.java | 3 ++- .../ingredient/SpongeIngredientBuilder.java | 21 ++++++------------ .../smithing/SpongeSmithingRecipeBuilder.java | 19 +++++----------- .../SpongeStoneCutterRecipeBuilder.java | 19 +++++----------- .../common/item/util/ItemStackUtil.java | 5 +++++ .../AbstractCookingRecipeMixin_API.java | 8 +++---- .../item/crafting/RecipeManagerMixin_API.java | 10 ++++----- 14 files changed, 71 insertions(+), 103 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index c55e532c5e1..6ddddd40ee3 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit c55e532c5e19dc6b0dcd2f62cc8989a949611dcb +Subproject commit 6ddddd40ee390b9441bf8b225684ff6d8a338e97 diff --git a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java index 0f591977d30..487cb57c392 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java +++ b/src/main/java/org/spongepowered/common/item/recipe/SpongeRecipeInputFactory.java @@ -27,7 +27,7 @@ import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.SmithingRecipeInput; -import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.type.GridInventory; import org.spongepowered.api.item.recipe.crafting.RecipeInput; @@ -36,13 +36,13 @@ public final class SpongeRecipeInputFactory implements RecipeInput.Factory { @Override - public RecipeInput.Single single(final ItemStack stack) { - return (RecipeInput.Single) (Object) new SingleRecipeInput(ItemStackUtil.toNative(stack)); + public RecipeInput.Single single(final ItemStackLike stack) { + return (RecipeInput.Single) (Object) new SingleRecipeInput(ItemStackUtil.fromLikeToNative(stack)); } @Override - public RecipeInput.Smithing smithing(final ItemStack template, final ItemStack base, final ItemStack addtion) { - return (RecipeInput.Smithing) (Object) new SmithingRecipeInput(ItemStackUtil.toNative(template), ItemStackUtil.toNative(base), ItemStackUtil.toNative(addtion)); + public RecipeInput.Smithing smithing(final ItemStackLike template, final ItemStackLike base, final ItemStackLike addtion) { + return (RecipeInput.Smithing) (Object) new SmithingRecipeInput(ItemStackUtil.fromLikeToNative(template), ItemStackUtil.fromLikeToNative(base), ItemStackUtil.fromLikeToNative(addtion)); } @Override diff --git a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java index 8f9929f9e78..d173ba4a708 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/cooking/SpongeCookingRecipeBuilder.java @@ -35,7 +35,7 @@ import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.RecipeType; import org.spongepowered.api.item.recipe.cooking.CookingRecipe; @@ -92,21 +92,16 @@ public EndStep result(final ItemType result) { } @Override - public EndStep result(final org.spongepowered.api.item.inventory.ItemStack result) { - this.result = ItemStackUtil.toNative(result); + public EndStep result(final ItemStackLike result) { + this.result = ItemStackUtil.fromLikeToNative(result); this.resultFunction = null; return this; } - @Override - public EndStep result(final ItemStackSnapshot result) { - return this.result(result.asMutable()); - } - // currently unused - public EndStep result(final Function resultFunction, final org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { - this.result = ItemStackUtil.toNative(exemplaryResult); - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); + public EndStep result(final Function resultFunction, final ItemStackLike exemplaryResult) { + this.result = ItemStackUtil.fromLikeToNative(exemplaryResult); + this.resultFunction = (inv) -> ItemStackUtil.fromLikeToNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java index 0fc65ff976c..358ecafd86e 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/custom/SpongeSpecialCraftingRecipeBuilder.java @@ -30,6 +30,7 @@ import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.SpecialCraftingRecipe; @@ -57,20 +58,20 @@ public ResultStep matching(BiPredicate biPred } @Override - public ResultStep remainingItems(Function> remainingItemsFunction) { - this.remainingItemsFunction = remainingItemsFunction; + public ResultStep remainingItems(Function> remainingItemsFunction) { + this.remainingItemsFunction = inv -> remainingItemsFunction.apply(inv).stream().map(ItemStackLike::asMutable).toList(); return this; } @Override - public EndStep result(Function resultFunction) { - this.resultFunction = resultFunction; + public EndStep result(Function resultFunction) { + this.resultFunction = inv -> resultFunction.apply(inv).asMutable(); return this; } @Override - public EndStep result(ItemStack result) { - final ItemStack copy = result.copy(); + public EndStep result(ItemStackLike result) { + final ItemStack copy = result.asMutableCopy(); this.resultFunction = inv -> copy.copy(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java index 0d17c326eaa..58022355737 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shaped/SpongeShapedCraftingRecipeBuilder.java @@ -37,7 +37,7 @@ import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.Ingredient; import org.spongepowered.api.item.recipe.crafting.RecipeInput; @@ -138,33 +138,27 @@ public RowsStep.ResultStep row(final int skip, final Ingredient... ingredients) } @Override - public ShapedCraftingRecipe.Builder.ResultStep remainingItems(Function> remainingItemsFunction) { + public ShapedCraftingRecipe.Builder.ResultStep remainingItems(Function> remainingItemsFunction) { this.remainingItemsFunction = grid -> { final NonNullList mcList = NonNullList.create(); - remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); + remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.fromLikeToNative(stack))); return mcList; }; return this; } @Override - public EndStep result(ItemStackSnapshot result) { + public EndStep result(final ItemStackLike result) { Objects.requireNonNull(result, "result"); - return this.result(result.asMutable()); - } - - @Override - public EndStep result(final ItemStack result) { - Objects.requireNonNull(result, "result"); - this.result = result.copy(); + this.result = result.asMutableCopy(); this.resultFunction = null; return this; } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); - this.result = exemplaryResult.copy(); + public EndStep result(Function resultFunction, ItemStackLike exemplaryResult) { + this.resultFunction = (inv) -> ItemStackUtil.fromLikeToNative(resultFunction.apply(InventoryUtil.toSponge(inv))); + this.result = exemplaryResult.asMutableCopy(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java index d808ba3183c..f048d2256e0 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/crafting/shapeless/SpongeShapelessCraftingRecipeBuilder.java @@ -37,7 +37,7 @@ import org.spongepowered.api.datapack.DataPack; import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.crafting.ShapelessCraftingRecipe; @@ -90,17 +90,17 @@ public ResultStep addIngredients(org.spongepowered.api.item.recipe.crafting.Ingr } @Override - public ResultStep remainingItems(Function> remainingItemsFunction) { + public ResultStep remainingItems(Function> remainingItemsFunction) { this.remainingItemsFunction = grid -> { final NonNullList mcList = NonNullList.create(); - remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.toNative(stack))); + remainingItemsFunction.apply(InventoryUtil.toSponge(grid)).forEach(stack -> mcList.add(ItemStackUtil.fromLikeToNative(stack))); return mcList; }; return this; } @Override - public EndStep result(final ItemStackSnapshot result) { + public EndStep result(ItemStackLike result) { Objects.requireNonNull(result, "result"); this.result = result.asMutable(); this.resultFunction = null; @@ -108,17 +108,9 @@ public EndStep result(final ItemStackSnapshot result) { } @Override - public EndStep result(org.spongepowered.api.item.inventory.ItemStack result) { - Objects.requireNonNull(result, "result"); - this.result = result; - this.resultFunction = null; - return this; - } - - @Override - public EndStep result(Function resultFunction, org.spongepowered.api.item.inventory.ItemStack exemplaryResult) { - this.resultFunction = (input) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(input))); - this.result = exemplaryResult.copy(); + public EndStep result(Function resultFunction, ItemStackLike exemplaryResult) { + this.resultFunction = (input) -> ItemStackUtil.fromLikeToNative(resultFunction.apply(InventoryUtil.toSponge(input))); + this.result = exemplaryResult.asMutableCopy(); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientUtil.java b/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientUtil.java index 6dfd4c78f46..23c02c5921f 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientUtil.java +++ b/src/main/java/org/spongepowered/common/item/recipe/ingredient/IngredientUtil.java @@ -34,6 +34,7 @@ import org.spongepowered.api.ResourceKey; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.common.item.util.ItemStackUtil; import java.util.Arrays; @@ -70,7 +71,7 @@ public static org.spongepowered.api.item.recipe.crafting.Ingredient of(ItemStack return IngredientUtil.fromNative(ingredient); } - public static org.spongepowered.api.item.recipe.crafting.Ingredient of(ResourceKey key, Predicate predicate, ItemStack... stacks) { + public static org.spongepowered.api.item.recipe.crafting.Ingredient of(ResourceKey key, Predicate predicate, ItemStack... stacks) { final SpongeIngredient ingredient = SpongeIngredient.spongeFromPredicate(key, predicate, IngredientUtil.toNativeStacks(stacks)); return IngredientUtil.fromNative(ingredient); } diff --git a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java index 8f3cbb0ef54..887b9e888ff 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java +++ b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredient.java @@ -33,6 +33,7 @@ import net.minecraft.world.item.crafting.Ingredient; import org.apache.commons.lang3.NotImplementedException; import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.item.util.ItemStackUtil; @@ -154,7 +155,7 @@ public static SpongeIngredient spongeFromStacks(net.minecraft.world.item.ItemSta private final static Map> cachedPredicates = new HashMap<>(); - public static SpongeIngredient spongeFromPredicate(ResourceKey key, Predicate predicate, + public static SpongeIngredient spongeFromPredicate(ResourceKey key, Predicate predicate, net.minecraft.world.item.ItemStack... exemplaryIngredients) { final Predicate mcPredicate = stack -> predicate.test(ItemStackUtil.fromNative(stack)); final Predicate registeredPredicate = SpongeIngredient.cachedPredicates.get(key.toString()); diff --git a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredientBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredientBuilder.java index 4f333bda37b..f6f37dcee60 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredientBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/ingredient/SpongeIngredientBuilder.java @@ -27,7 +27,7 @@ import org.spongepowered.api.ResourceKey; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.crafting.Ingredient; import java.util.Arrays; @@ -39,7 +39,7 @@ public class SpongeIngredientBuilder implements Ingredient.Builder { private ItemType[] types; private ResourceKey itemTag; private ItemStack[] stacks; - private Predicate predicate; + private Predicate predicate; private ResourceKey key; @Override @@ -75,25 +75,18 @@ public Ingredient.Builder with(ResourceKey itemTag) { } @Override - public Ingredient.Builder with(ItemStack... types) { + public Ingredient.Builder with(ItemStackLike... types) { this.reset(); - this.stacks = types; + this.stacks = Arrays.stream(types).map(ItemStackLike::asMutable).toArray(ItemStack[]::new); return this; } @Override - public Ingredient.Builder with(ItemStackSnapshot... types) { + public Ingredient.Builder with(ResourceKey resourceKey, Predicate predicate, ItemStackLike... exemplaryTypes) { this.reset(); - this.stacks = Arrays.stream(types).map(ItemStackSnapshot::asMutable).toArray(ItemStack[]::new); - return this; - } - - @Override - public Ingredient.Builder with(ResourceKey key, Predicate predicate, ItemStack... exemplaryTypes) { - this.reset(); - this.stacks = exemplaryTypes; + this.stacks = Arrays.stream(exemplaryTypes).map(ItemStackLike::asMutable).toArray(ItemStack[]::new); this.predicate = predicate; - this.key = key; + this.key = resourceKey; return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java index 5d93bdae546..d7eeb1bd5e7 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/smithing/SpongeSmithingRecipeBuilder.java @@ -35,7 +35,7 @@ import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.smithing.SmithingRecipe; @@ -98,27 +98,20 @@ public ResultStep addition(org.spongepowered.api.item.recipe.crafting.Ingredient } @Override - public EndStep result(ItemStackSnapshot result) { - this.result = result.asMutable(); - this.resultFunction = null; - return this; - } - - @Override - public EndStep result(final ItemStack result) { + public EndStep result(final ItemStackLike result) { Objects.requireNonNull(result, "result"); - this.result = result; + this.result = result.asMutable(); this.resultFunction = null; return this; } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { + public EndStep result(Function resultFunction, ItemStackLike exemplaryResult) { Objects.requireNonNull(exemplaryResult, "exemplaryResult"); Preconditions.checkState(!exemplaryResult.isEmpty(), "exemplaryResult must not be empty"); - this.result = exemplaryResult; - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); + this.result = exemplaryResult.asMutable(); + this.resultFunction = (inv) -> ItemStackUtil.fromLikeToNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java index f3bc6bcb0ee..0c00ca927f2 100644 --- a/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java +++ b/src/main/java/org/spongepowered/common/item/recipe/stonecutting/SpongeStoneCutterRecipeBuilder.java @@ -35,7 +35,7 @@ import org.spongepowered.api.datapack.DataPacks; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.RecipeRegistration; import org.spongepowered.api.item.recipe.crafting.RecipeInput; import org.spongepowered.api.item.recipe.single.StoneCutterRecipe; @@ -72,27 +72,20 @@ public ResultStep ingredient(org.spongepowered.api.item.recipe.crafting.Ingredie } @Override - public EndStep result(ItemStackSnapshot result) { - this.result = result.asMutable(); - this.resultFunction = null; - return this; - } - - @Override - public EndStep result(final ItemStack result) { + public EndStep result(final ItemStackLike result) { Objects.requireNonNull(result, "result"); - this.result = result; + this.result = result.asMutable(); this.resultFunction = null; return this; } @Override - public EndStep result(Function resultFunction, ItemStack exemplaryResult) { + public EndStep result(Function resultFunction, ItemStackLike exemplaryResult) { Objects.requireNonNull(exemplaryResult, "exemplaryResult"); Preconditions.checkState(!exemplaryResult.isEmpty(), "exemplaryResult must not be empty"); - this.result = exemplaryResult; - this.resultFunction = (inv) -> ItemStackUtil.toNative(resultFunction.apply(InventoryUtil.toSponge(inv))); + this.result = exemplaryResult.asMutable(); + this.resultFunction = (inv) -> ItemStackUtil.fromLikeToNative(resultFunction.apply(InventoryUtil.toSponge(inv))); return this; } diff --git a/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java b/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java index 972cce79e2c..b6771315941 100644 --- a/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java +++ b/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java @@ -26,6 +26,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import java.util.Arrays; @@ -162,6 +163,10 @@ public static ItemStack fromSnapshot(@Nullable ItemStackSnapshot snapshot) { return snapshot == null ? ItemStackUtil.empty() : snapshot.isEmpty() ? ItemStackUtil.empty() : snapshot.asMutable(); } + public static net.minecraft.world.item.ItemStack fromLikeToNative(@Nullable ItemStackLike itemStack) { + return itemStack == null ? ItemStackUtil.emptyNative() : itemStack.isEmpty() ? ItemStackUtil.emptyNative() : ItemStackUtil.toNative(itemStack.asMutable()); + } + public static ItemStack empty() { return ItemStackUtil.fromNative(net.minecraft.world.item.ItemStack.EMPTY); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/AbstractCookingRecipeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/AbstractCookingRecipeMixin_API.java index 609b3a7dba5..9075a7f4354 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/AbstractCookingRecipeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/AbstractCookingRecipeMixin_API.java @@ -26,7 +26,7 @@ import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.Ingredient; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.cooking.CookingRecipe; import org.spongepowered.api.item.recipe.cooking.CookingResult; import org.spongepowered.api.util.Ticks; @@ -54,12 +54,12 @@ public org.spongepowered.api.item.recipe.crafting.Ingredient ingredient() { } @Override - public boolean isValid(final ItemStackSnapshot ingredient) { - return this.ingredient.test(ItemStackUtil.fromSnapshotToNative(ingredient)); + public boolean isValid(final ItemStackLike ingredient) { + return this.ingredient.test(ItemStackUtil.fromLikeToNative(ingredient)); } @Override - public Optional result(final ItemStackSnapshot ingredient) { + public Optional result(final ItemStackLike ingredient) { if (this.isValid(ingredient)) { return Optional.of(new CookingResult(this.exemplaryResult(), this.shadow$getExperience())); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java index efa6d8b2734..302ab6b23e0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/crafting/RecipeManagerMixin_API.java @@ -32,7 +32,7 @@ import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.level.Level; import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.recipe.Recipe; import org.spongepowered.api.item.recipe.RecipeManager; import org.spongepowered.api.item.recipe.RecipeType; @@ -79,11 +79,11 @@ public > Collection allOfType(final RecipeType type) { } @Override - public > Collection findByResult(final RecipeType type, final ItemStackSnapshot result) { + public > Collection findByResult(final RecipeType type, final ItemStackLike result) { Objects.requireNonNull(type); Objects.requireNonNull(result); return this.allOfType(type).stream() - .filter(r -> r.exemplaryResult().equals(result)) + .filter(r -> r.exemplaryResult().equals(result.asImmutable())) .collect(Collectors.toList()); } @@ -110,11 +110,11 @@ public Optional findCookingRecipe(final RecipeType type, final ItemStackSnapshot ingredient) { + public Optional findCookingRecipe(final RecipeType type, final ItemStackLike ingredient) { Objects.requireNonNull(type); Objects.requireNonNull(ingredient); - final SingleRecipeInput input = new SingleRecipeInput(ItemStackUtil.fromSnapshotToNative(ingredient)); + final SingleRecipeInput input = new SingleRecipeInput(ItemStackUtil.fromLikeToNative(ingredient)); return this.shadow$getRecipeFor((net.minecraft.world.item.crafting.RecipeType) type, input, null); } } From 6e636e0d94fa35cc8d48217e5fd2169463a6ef53 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sat, 14 Sep 2024 15:11:02 +0300 Subject: [PATCH 190/226] Migrate enchantments and trade offers --- SpongeAPI | 2 +- .../common/item/merchant/SpongeTradeOfferBuilder.java | 7 ++++--- .../world/item/enchantment/EnchantmentMixin_API.java | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 6ddddd40ee3..ffd4e09c7da 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 6ddddd40ee390b9441bf8b225684ff6d8a338e97 +Subproject commit ffd4e09c7da3ee7bd23297e47fbdf9250cf97659 diff --git a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java index 39e2778eb6b..c189fd8f13d 100644 --- a/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java +++ b/src/main/java/org/spongepowered/common/item/merchant/SpongeTradeOfferBuilder.java @@ -36,6 +36,7 @@ import org.spongepowered.api.data.persistence.DataView; import org.spongepowered.api.data.persistence.InvalidDataException; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.merchant.TradeOffer; import org.spongepowered.common.accessor.world.item.trading.MerchantOfferAccessor; @@ -64,7 +65,7 @@ public SpongeTradeOfferBuilder() { } @Override - public TradeOffer.Builder firstBuyingItem(final ItemStack item) { + public TradeOffer.Builder firstBuyingItem(final ItemStackLike item) { Objects.requireNonNull(item, "Buying item cannot be null"); this.firstItem = item.asImmutable(); return this; @@ -72,13 +73,13 @@ public TradeOffer.Builder firstBuyingItem(final ItemStack item) { @SuppressWarnings("ConstantConditions") @Override - public TradeOffer.Builder secondBuyingItem(final ItemStack item) { + public TradeOffer.Builder secondBuyingItem(final ItemStackLike item) { this.secondItem = item != null ? item.asImmutable() : ItemStackSnapshot.empty(); return this; } @Override - public TradeOffer.Builder sellingItem(final ItemStack item) { + public TradeOffer.Builder sellingItem(final ItemStackLike item) { this.sellingItem = item.asImmutable(); return this; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java index d8757a27774..8ed9fe87cf3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java @@ -29,6 +29,7 @@ import net.minecraft.world.item.enchantment.Enchantment; import org.spongepowered.api.item.enchantment.EnchantmentType; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -74,13 +75,13 @@ public int maximumEnchantabilityForLevel(final int level) { } @Override - public boolean canBeAppliedByTable(final ItemStack stack) { + public boolean canBeAppliedByTable(final ItemStackLike stack) { return this.canBeAppliedToStack(stack); } @Override - public boolean canBeAppliedToStack(final ItemStack stack) { - return PlatformHooks.INSTANCE.getItemHooks().canEnchantmentBeAppliedToItem((Enchantment) (Object) this, ItemStackUtil.toNative(stack)); + public boolean canBeAppliedToStack(final ItemStackLike stack) { + return PlatformHooks.INSTANCE.getItemHooks().canEnchantmentBeAppliedToItem((Enchantment) (Object) this, ItemStackUtil.fromLikeToNative(stack)); } @Override From 5694e1ace1373d259c107561c10ad5433feb23f3 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 00:46:15 +0300 Subject: [PATCH 191/226] Migrate Equipable a --- SpongeAPI | 2 +- .../common/entity/player/SpongeUserData.java | 19 ++++++++++--------- .../common/entity/player/SpongeUserView.java | 15 ++++++++------- .../impl/comp/EquipmentInventoryAdapter.java | 3 ++- ...aitMixin_ArmorEquipable_Inventory_API.java | 19 ++++++++++--------- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index ffd4e09c7da..68d2ef7fc47 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit ffd4e09c7da3ee7bd23297e47fbdf9250cf97659 +Subproject commit 68d2ef7fc47f158abeac97ba736b5c8c20f7bd9a diff --git a/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java b/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java index 4b24f5ddcda..6fe79650820 100644 --- a/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java +++ b/src/main/java/org/spongepowered/common/entity/player/SpongeUserData.java @@ -55,6 +55,7 @@ import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.entity.UserInventory; import org.spongepowered.api.item.inventory.equipment.EquipmentInventory; import org.spongepowered.api.item.inventory.equipment.EquipmentType; @@ -285,7 +286,7 @@ public boolean canEquip(final EquipmentType type) { } @Override - public boolean canEquip(final EquipmentType type, final @Nullable ItemStack equipment) { + public boolean canEquip(final EquipmentType type, final @Nullable ItemStackLike equipment) { return true; } @@ -295,7 +296,7 @@ public Optional equipped(final EquipmentType type) { } @Override - public boolean equip(final EquipmentType type, final @Nullable ItemStack equipment) { + public boolean equip(final EquipmentType type, final @Nullable ItemStackLike equipment) { if (this.canEquip(type, equipment)) { this.loadInventory(); this.setEquippedItem(type, equipment); @@ -330,7 +331,7 @@ public ItemStack head() { } @Override - public void setHead(final ItemStack helmet) { + public void setHead(final ItemStackLike helmet) { this.equip(EquipmentTypes.HEAD.get(), helmet); } @@ -340,7 +341,7 @@ public ItemStack chest() { } @Override - public void setChest(final ItemStack chestplate) { + public void setChest(final ItemStackLike chestplate) { this.equip(EquipmentTypes.CHEST.get(), chestplate); } @@ -350,7 +351,7 @@ public ItemStack legs() { } @Override - public void setLegs(final ItemStack leggings) { + public void setLegs(final ItemStackLike leggings) { this.equip(EquipmentTypes.LEGS.get(), leggings); } @@ -360,12 +361,12 @@ public ItemStack feet() { } @Override - public void setFeet(final ItemStack boots) { + public void setFeet(final ItemStackLike boots) { this.equip(EquipmentTypes.FEET.get(), boots); } @Override - public void setItemInHand(final HandType handType, final @Nullable ItemStack itemInHand) { + public void setItemInHand(final HandType handType, final @Nullable ItemStackLike itemInHand) { if (handType == HandTypes.MAIN_HAND.get()) { this.setEquippedItem(EquipmentTypes.MAINHAND, itemInHand); } else if (handType == HandTypes.OFF_HAND.get()) { @@ -439,11 +440,11 @@ public void save() throws IOException { // Helpers for Equipment: - private void setEquippedItem(final Supplier type, final @Nullable ItemStack item) { + private void setEquippedItem(final Supplier type, final @Nullable ItemStackLike item) { this.setEquippedItem(type.get(), item); } - private void setEquippedItem(final EquipmentType type, final @Nullable ItemStack item) { + private void setEquippedItem(final EquipmentType type, final @Nullable ItemStackLike item) { throw new MissingImplementationException("SpongeUser", "setEquippedItem"); } diff --git a/src/main/java/org/spongepowered/common/entity/player/SpongeUserView.java b/src/main/java/org/spongepowered/common/entity/player/SpongeUserView.java index 03bc5deb54f..421ff485aba 100644 --- a/src/main/java/org/spongepowered/common/entity/player/SpongeUserView.java +++ b/src/main/java/org/spongepowered/common/entity/player/SpongeUserView.java @@ -47,6 +47,7 @@ import org.spongepowered.api.item.inventory.Equipable; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.equipment.EquipmentInventory; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.item.inventory.type.CarriedInventory; @@ -267,7 +268,7 @@ public ItemStack head() { } @Override - public void setHead(final ItemStack head) { + public void setHead(final ItemStackLike head) { this.backingObjectConsumer(player -> player.setHead(head), user -> user.setHead(head)); } @@ -277,7 +278,7 @@ public ItemStack chest() { } @Override - public void setChest(final ItemStack chest) { + public void setChest(final ItemStackLike chest) { this.backingObjectConsumer(player -> player.setChest(chest), user -> user.setChest(chest)); } @@ -287,7 +288,7 @@ public ItemStack legs() { } @Override - public void setLegs(final ItemStack legs) { + public void setLegs(final ItemStackLike legs) { this.backingObjectConsumer(player -> player.setLegs(legs), user -> user.setLegs(legs)); } @@ -297,7 +298,7 @@ public ItemStack feet() { } @Override - public void setFeet(final ItemStack feet) { + public void setFeet(final ItemStackLike feet) { this.backingObjectConsumer(player -> player.setFeet(feet), user -> user.setFeet(feet)); } @@ -307,7 +308,7 @@ public ItemStack itemInHand(final HandType handType) { } @Override - public void setItemInHand(final HandType handType, final ItemStack itemInHand) { + public void setItemInHand(final HandType handType, final ItemStackLike itemInHand) { this.backingObjectConsumer(player -> player.setItemInHand(handType, itemInHand), user -> user.setItemInHand(handType, itemInHand)); } @@ -322,7 +323,7 @@ public boolean canEquip(final EquipmentType type) { } @Override - public boolean canEquip(final EquipmentType type, final ItemStack equipment) { + public boolean canEquip(final EquipmentType type, final ItemStackLike equipment) { return this.backingObject(player -> player.canEquip(type, equipment), user -> user.canEquip(type, equipment)); } @@ -332,7 +333,7 @@ public Optional equipped(final EquipmentType type) { } @Override - public boolean equip(final EquipmentType type, final ItemStack equipment) { + public boolean equip(final EquipmentType type, final ItemStackLike equipment) { return this.backingObject(player -> player.equip(type, equipment), user -> user.equip(type, equipment)); } diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/EquipmentInventoryAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/EquipmentInventoryAdapter.java index 90f1d32060c..ec6d65c208a 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/EquipmentInventoryAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/EquipmentInventoryAdapter.java @@ -29,6 +29,7 @@ import org.spongepowered.api.item.inventory.Equipable; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.equipment.EquipmentInventory; import org.spongepowered.api.item.inventory.equipment.EquipmentType; @@ -79,7 +80,7 @@ public Optional peek(EquipmentType equipmentType) { } @Override - public InventoryTransactionResult set(EquipmentType equipmentType, ItemStack stack) { + public InventoryTransactionResult set(EquipmentType equipmentType, ItemStackLike stack) { Inventory query = this.queryForType(equipmentType); if (query.capacity() == 0) { return InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.NO_SLOT).build(); diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/TraitMixin_ArmorEquipable_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/TraitMixin_ArmorEquipable_Inventory_API.java index 4ab4b5a313d..66569883a51 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/TraitMixin_ArmorEquipable_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/TraitMixin_ArmorEquipable_Inventory_API.java @@ -33,6 +33,7 @@ import org.spongepowered.api.data.type.HandType; import org.spongepowered.api.item.inventory.ArmorEquipable; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.item.inventory.equipment.EquipmentTypes; import org.spongepowered.asm.mixin.Mixin; @@ -61,7 +62,7 @@ public boolean canEquip(final EquipmentType type) { } @Override - public boolean canEquip(final EquipmentType type, @Nullable final ItemStack equipment) { + public boolean canEquip(final EquipmentType type, @Nullable final ItemStackLike equipment) { return true; } @@ -74,11 +75,11 @@ public Optional equipped(final EquipmentType type) { } @Override - public boolean equip(final EquipmentType type, @Nullable final ItemStack equipment) { + public boolean equip(final EquipmentType type, @Nullable final ItemStackLike equipment) { final InventoryAdapter inv = ((InventoryBridge) this).bridge$getAdapter(); final EquipmentInventoryLens lens = this.impl$equipmentInventory(inv); final Fabric fabric = inv.inventoryAdapter$getFabric(); - return lens.getSlotLens(type).setStack(fabric, ItemStackUtil.toNative(equipment)); + return lens.getSlotLens(type).setStack(fabric, ItemStackUtil.fromLikeToNative(equipment)); } @Override @@ -89,9 +90,9 @@ public ItemStack itemInHand(HandType handType) { } @Override - public void setItemInHand(HandType handType, @Nullable ItemStack itemInHand) { + public void setItemInHand(HandType handType, @Nullable ItemStackLike itemInHand) { Objects.requireNonNull(handType); - ((LivingEntity) (Object)this).setItemInHand((InteractionHand) (Object) handType, ItemStackUtil.toNative(itemInHand).copy()); + ((LivingEntity) (Object)this).setItemInHand((InteractionHand) (Object) handType, ItemStackUtil.fromLikeToNative(itemInHand).copy()); } @Override @@ -100,7 +101,7 @@ public ItemStack head() { } @Override - public void setHead(ItemStack head) { + public void setHead(ItemStackLike head) { this.equip(EquipmentTypes.HEAD, head); } @@ -110,7 +111,7 @@ public ItemStack chest() { } @Override - public void setChest(ItemStack chest) { + public void setChest(ItemStackLike chest) { this.equip(EquipmentTypes.CHEST, chest); } @@ -120,7 +121,7 @@ public ItemStack legs() { } @Override - public void setLegs(ItemStack legs) { + public void setLegs(ItemStackLike legs) { this.equip(EquipmentTypes.LEGS, legs); } @@ -130,7 +131,7 @@ public ItemStack feet() { } @Override - public void setFeet(ItemStack feet) { + public void setFeet(ItemStackLike feet) { this.equip(EquipmentTypes.FEET, feet); } From bd919dde930304b6e495dd213da907f7683c202b Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 01:42:34 +0300 Subject: [PATCH 192/226] Migrate item transactions --- .../InventoryTransactionResultImpl.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java index 709e711abf3..1cf39ad0bb4 100644 --- a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java +++ b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java @@ -29,6 +29,7 @@ import com.google.common.collect.Lists; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.api.item.inventory.transaction.SlotTransaction; @@ -75,7 +76,7 @@ public InventoryTransactionResult and(InventoryTransactionResult other) { @Override public void revert() { for (SlotTransaction transaction : Lists.reverse(this.slotTransactions)) { - transaction.slot().set(transaction.original().asMutable()); + transaction.slot().set(transaction.original()); } } @@ -127,20 +128,20 @@ public InventoryTransactionResult.Builder type(final InventoryTransactionResult. } @Override - public PollBuilder poll(ItemStackSnapshot itemStack) { + public PollBuilder poll(ItemStackLike itemStack) { if (this.polled == null) { this.polled = new ArrayList<>(); } - this.polled.add(itemStack); + this.polled.add(itemStack.asImmutable()); return this; } @Override - public InventoryTransactionResult.Builder reject(ItemStack... itemStacks) { + public InventoryTransactionResult.Builder reject(ItemStackLike... itemStacks) { if (this.rejected == null) { this.rejected = new ArrayList<>(); } - for (ItemStack itemStack1 : itemStacks) { + for (ItemStackLike itemStack1 : itemStacks) { if (!itemStack1.isEmpty()) { this.rejected.add(itemStack1.asImmutable()); } @@ -149,13 +150,13 @@ public InventoryTransactionResult.Builder reject(ItemStack... itemStacks) { } @Override - public InventoryTransactionResult.Builder reject(Iterable itemStacks) { + public InventoryTransactionResult.Builder reject(Iterable itemStacks) { if (this.rejected == null) { this.rejected = new ArrayList<>(); } - for (ItemStackSnapshot itemStack1 : itemStacks) { + for (ItemStackLike itemStack1 : itemStacks) { if (!itemStack1.isEmpty()) { - this.rejected.add(itemStack1); + this.rejected.add(itemStack1.asImmutable()); } } return this; From 610ef28b705c5da110eacb41b58d6a01d85d307a Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 02:05:33 +0300 Subject: [PATCH 193/226] Migrate slots --- .../common/inventory/EmptyInventoryImpl.java | 13 ++++----- .../DefaultImplementedAdapterInventory.java | 27 ++++++++++--------- .../impl/slots/FilteringSlotAdapter.java | 7 ++--- .../adapter/impl/slots/HeldSlotAdapter.java | 9 ++++--- .../adapter/impl/slots/SlotAdapter.java | 27 ++++++++++--------- .../lens/impl/slot/FilteringSlotLens.java | 5 ++-- .../lens/impl/slot/HeldHandSlotLens.java | 3 ++- .../common/item/util/ItemStackUtil.java | 2 +- .../ContainerMixin_Inventory_API.java | 5 ++-- .../inventory/SlotMixin_Inventory_API.java | 5 ++-- 10 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/spongepowered/common/inventory/EmptyInventoryImpl.java b/src/main/java/org/spongepowered/common/inventory/EmptyInventoryImpl.java index 5bd4a343b21..29724972bd8 100644 --- a/src/main/java/org/spongepowered/common/inventory/EmptyInventoryImpl.java +++ b/src/main/java/org/spongepowered/common/inventory/EmptyInventoryImpl.java @@ -33,6 +33,7 @@ import org.spongepowered.api.item.inventory.EmptyInventory; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.query.Query; @@ -105,12 +106,12 @@ public boolean hasChildren() { } @Override - public boolean contains(ItemStack stack) { + public boolean contains(ItemStackLike stack) { return false; } @Override - public boolean containsAny(ItemStack stack) { + public boolean containsAny(ItemStackLike stack) { return false; } @@ -193,7 +194,7 @@ public Inventory root() { } @Override - public InventoryTransactionResult offer(ItemStack... stacks) { + public InventoryTransactionResult offer(ItemStackLike... stacks) { return InventoryTransactionResult.builder().type(Type.FAILURE).reject(stacks).build(); } @@ -209,16 +210,16 @@ public Optional peekAt(int index) { return Optional.empty(); } - public InventoryTransactionResult offer(int index, ItemStack stack) { + public InventoryTransactionResult offer(int index, ItemStackLike stack) { return InventoryTransactionResult.builder().type(Type.NO_SLOT).reject(stack).build(); } - public InventoryTransactionResult set(int index, ItemStack stack) { + public InventoryTransactionResult set(int index, ItemStackLike stack) { return InventoryTransactionResult.builder().type(Type.NO_SLOT).reject(stack).build(); } @Override - public boolean canFit(ItemStack stack) { + public boolean canFit(ItemStackLike stack) { return false; } diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/DefaultImplementedAdapterInventory.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/DefaultImplementedAdapterInventory.java index b173dd8b3b7..5715c7e4927 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/DefaultImplementedAdapterInventory.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/DefaultImplementedAdapterInventory.java @@ -28,6 +28,7 @@ import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.query.Query; import org.spongepowered.api.item.inventory.query.QueryTypes; @@ -97,17 +98,17 @@ default ItemStack peek() { } @Override - default InventoryTransactionResult offer(ItemStack... stacks) { + default InventoryTransactionResult offer(ItemStackLike... stacks) { InventoryTransactionResult result = InventoryTransactionResult.successNoTransactions(); - for (ItemStack stack : stacks) { - result = result.and(AdapterLogic.appendSequential(this.impl$getFabric(), this.impl$getLens(), stack)); + for (ItemStackLike stack : stacks) { + result = result.and(AdapterLogic.appendSequential(this.impl$getFabric(), this.impl$getLens(), stack.asMutable())); } return result; } @Override - default boolean canFit(ItemStack stack) { - return AdapterLogic.canFit(this.impl$getFabric(), this.impl$getLens(), stack); + default boolean canFit(ItemStackLike stack) { + return AdapterLogic.canFit(this.impl$getFabric(), this.impl$getLens(), stack.asMutable()); } @Override @@ -131,13 +132,13 @@ default boolean hasChildren() { } @Override - default boolean contains(ItemStack stack) { - return AdapterLogic.contains(((InventoryBridge) this).bridge$getAdapter(), stack); + default boolean contains(ItemStackLike stack) { + return AdapterLogic.contains(((InventoryBridge) this).bridge$getAdapter(), stack.asMutable()); } @Override - default boolean containsAny(ItemStack stack) { - return AdapterLogic.contains(((InventoryBridge) this).bridge$getAdapter(), stack, 1); + default boolean containsAny(ItemStackLike stack) { + return AdapterLogic.contains(((InventoryBridge) this).bridge$getAdapter(), stack.asMutable(), 1); } @Override @@ -208,13 +209,13 @@ default Optional peekAt(int index) { } @Override - default InventoryTransactionResult set(int index, ItemStack stack) { - return AdapterLogic.insertSequential(this.impl$getFabric(), this.impl$getLens().getSlotLens(this.impl$getFabric(), index), stack); + default InventoryTransactionResult set(int index, ItemStackLike stack) { + return AdapterLogic.insertSequential(this.impl$getFabric(), this.impl$getLens().getSlotLens(this.impl$getFabric(), index), stack.asMutable()); } @Override - default InventoryTransactionResult offer(int index, ItemStack stack) { - return AdapterLogic.appendSequential(this.impl$getFabric(), this.impl$getLens().getSlotLens(this.impl$getFabric(), index), stack); + default InventoryTransactionResult offer(int index, ItemStackLike stack) { + return AdapterLogic.appendSequential(this.impl$getFabric(), this.impl$getLens().getSlotLens(this.impl$getFabric(), index), stack.asMutable()); } @Override diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java index 9a6d2634194..4bb84163a6d 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java @@ -27,6 +27,7 @@ import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.slot.FilteringSlot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.common.inventory.fabric.Fabric; @@ -43,7 +44,7 @@ public FilteringSlotAdapter(Fabric fabric, FilteringSlotLens lens, Inventory par } @Override - public boolean isValidItem(ItemStack stack) { + public boolean isValidItem(ItemStackLike stack) { FilteringSlotLens.ItemStackFilter filter = this.filteringSlot.getItemStackFilter(); return filter == null || filter.test(this.impl$getFabric(), stack); } @@ -68,11 +69,11 @@ public InventoryTransactionResult offer(ItemStack stack) { */ @Override - public InventoryTransactionResult set(ItemStack stack) { + public InventoryTransactionResult set(ItemStackLike stack) { final boolean canSet = this.isValidItem(stack); if (!canSet) { final InventoryTransactionResult.Builder result = InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.FAILURE); - result.reject(ItemStackUtil.cloneDefensive(stack)); + result.reject(stack); return result.build(); } diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java index 9db3afc51ea..fdbcf3632bd 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java @@ -27,6 +27,7 @@ import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.item.inventory.slot.EquipmentSlot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; @@ -52,8 +53,8 @@ public boolean isValidItem(EquipmentType type) { } @Override - public boolean isValidItem(ItemStack stack) { - Predicate filter = this.equipmentSlot.getItemStackFilter(); + public boolean isValidItem(ItemStackLike stack) { + Predicate filter = this.equipmentSlot.getItemStackFilter(); return filter == null || filter.test(stack); } @@ -64,11 +65,11 @@ public boolean isValidItem(ItemType type) { } @Override - public InventoryTransactionResult set(ItemStack stack) { + public InventoryTransactionResult set(ItemStackLike stack) { final boolean canSet = this.isValidItem(stack); if (!canSet) { final InventoryTransactionResult.Builder result = InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.FAILURE); - result.reject(ItemStackUtil.cloneDefensive(stack)); + result.reject(stack); return result.build(); } diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/SlotAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/SlotAdapter.java index 5627c398cf3..569c5c30bb2 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/SlotAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/SlotAdapter.java @@ -30,6 +30,7 @@ import org.spongepowered.api.item.ItemTypes; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; @@ -89,11 +90,11 @@ public ItemStack peek() { } @Override - public InventoryTransactionResult offer(final ItemStack... stacks) { + public InventoryTransactionResult offer(final ItemStackLike... stacks) { final InventoryTransactionResult.Builder result = InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.SUCCESS); - for (ItemStack stack : stacks) { - final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.toNative(stack); + for (ItemStackLike stack : stacks) { + final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.fromLikeToNative(stack); final int maxStackSize = this.slot.getMaxStackSize(this.inventoryAdapter$getFabric()); int remaining = stack.quantity(); @@ -105,7 +106,7 @@ public InventoryTransactionResult offer(final ItemStack... stacks) { if (old.isEmpty() && this.slot.setStack(this.inventoryAdapter$getFabric(), ItemStackUtil.cloneDefensiveNative(nativeStack, push))) { remaining -= push; newStack = ItemStackUtil.snapshotOf(stack); - } else if (!old.isEmpty() && ItemStackUtil.compareIgnoreQuantity(old, stack) && maxStackSize > old.getCount()) { + } else if (!old.isEmpty() && ItemStackUtil.compareIgnoreQuantity(old, nativeStack) && maxStackSize > old.getCount()) { this.inventoryAdapter$getFabric().fabric$markDirty(); push = Math.max(Math.min(maxStackSize - old.getCount(), remaining), 0); // max() accounts for oversized stacks old.setCount(old.getCount() + push); @@ -124,7 +125,7 @@ public InventoryTransactionResult offer(final ItemStack... stacks) { } @Override - public boolean canFit(final ItemStack stack) { + public boolean canFit(final ItemStackLike stack) { if (stack.isEmpty()) { return true; } @@ -133,13 +134,13 @@ public boolean canFit(final ItemStack stack) { if (old.isEmpty()) { return maxStackSize >= stack.quantity(); } - return ItemStackUtil.compareIgnoreQuantity(old, stack) && maxStackSize - old.getCount() >= stack.quantity(); + return ItemStackUtil.compareIgnoreQuantity(old, stack.asMutable()) && maxStackSize - old.getCount() >= stack.quantity(); } @Override - public InventoryTransactionResult set(final ItemStack stack) { + public InventoryTransactionResult set(final ItemStackLike stack) { final InventoryTransactionResult.Builder result = InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.SUCCESS); - final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.toNative(stack); + final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.fromLikeToNative(stack); final net.minecraft.world.item.ItemStack old = this.slot.getStack(this.inventoryAdapter$getFabric()); ItemStackSnapshot oldSnap = ItemStackUtil.snapshotOf(old); @@ -189,16 +190,16 @@ public boolean hasChildren() { } @Override - public boolean contains(final ItemStack stack) { + public boolean contains(final ItemStackLike stack) { final net.minecraft.world.item.ItemStack slotStack = this.slot.getStack(this.inventoryAdapter$getFabric()); - return slotStack.isEmpty() ? ItemStackUtil.toNative(stack).isEmpty() : - ItemStackUtil.compareIgnoreQuantity(slotStack, stack) && slotStack.getCount() >= stack.quantity(); + return slotStack.isEmpty() ? ItemStackUtil.fromLikeToNative(stack).isEmpty() : + ItemStackUtil.compareIgnoreQuantity(slotStack, stack.asMutable()) && slotStack.getCount() >= stack.quantity(); } @Override - public boolean containsAny(final ItemStack stack) { + public boolean containsAny(final ItemStackLike stack) { final net.minecraft.world.item.ItemStack slotStack = this.slot.getStack(this.inventoryAdapter$getFabric()); - return slotStack.isEmpty() ? ItemStackUtil.toNative(stack).isEmpty() : ItemStackUtil.compareIgnoreQuantity(slotStack, stack); + return slotStack.isEmpty() ? ItemStackUtil.fromLikeToNative(stack).isEmpty() : ItemStackUtil.compareIgnoreQuantity(slotStack, stack.asMutable()); } @Override diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java index 0938f34361d..54c9a27e42d 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java @@ -27,6 +27,7 @@ import net.minecraft.world.Container; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.common.bridge.world.inventory.InventoryBridge; import org.spongepowered.common.inventory.adapter.impl.slots.FilteringSlotAdapter; @@ -59,7 +60,7 @@ public Slot getAdapter(Fabric fabric, Inventory parent) { @FunctionalInterface public interface ItemStackFilter { - boolean test(Fabric fabric, ItemStack itemStack); + boolean test(Fabric fabric, ItemStackLike itemStack); static ItemStackFilter filterNone() { return (f, i) -> true; @@ -69,7 +70,7 @@ static ItemStackFilter filterIInventory(int slot) { return (fabric, item) -> { InventoryBridge inventory = fabric.fabric$get(slot); if (inventory instanceof Container) { - return ((Container) inventory).canPlaceItem(slot, ItemStackUtil.toNative(item)); + return ((Container) inventory).canPlaceItem(slot, ItemStackUtil.fromLikeToNative(item)); } return true; }; diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java index 17e5e74d0cc..92e0b4ec5eb 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/HeldHandSlotLens.java @@ -28,6 +28,7 @@ import org.spongepowered.api.data.Key; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.item.inventory.equipment.EquipmentTypes; @@ -151,7 +152,7 @@ public Predicate getEquipmentTypeFilter() { return (e) -> e == EquipmentTypes.MAINHAND.get(); } - public Predicate getItemStackFilter() { + public Predicate getItemStackFilter() { return (i) -> true; } diff --git a/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java b/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java index b6771315941..b9b30d606d2 100644 --- a/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java +++ b/src/main/java/org/spongepowered/common/item/util/ItemStackUtil.java @@ -146,7 +146,7 @@ public static ItemStackSnapshot snapshotOf(net.minecraft.world.item.ItemStack it return itemStack.isEmpty() ? ItemStackSnapshot.empty() : ItemStackUtil.fromNative(itemStack).asImmutable(); } - public static ItemStackSnapshot snapshotOf(@Nullable ItemStack itemStack) { + public static ItemStackSnapshot snapshotOf(@Nullable ItemStackLike itemStack) { return itemStack == null ? ItemStackSnapshot.empty() : itemStack.isEmpty() ? ItemStackSnapshot.empty() : itemStack.asImmutable(); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java index b553b02a922..993ad3a9af0 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/inventory/container/ContainerMixin_Inventory_API.java @@ -33,6 +33,7 @@ import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.item.inventory.ContainerType; import org.spongepowered.api.item.inventory.Inventory; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.menu.InventoryMenu; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -88,11 +89,11 @@ public List viewed() { } @Override - public boolean setCursor(org.spongepowered.api.item.inventory.ItemStack item) { + public boolean setCursor(ItemStackLike item) { if (!this.isOpen()) { return false; } - ItemStack nativeStack = ItemStackUtil.toNative(item); + ItemStack nativeStack = ItemStackUtil.fromLikeToNative(item); this.listeners().stream().findFirst() .ifPresent(p -> p.containerMenu.setCarried(nativeStack)); return true; diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java index 3b5837f2531..1b9a0ef5ae4 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java @@ -28,6 +28,7 @@ import net.minecraft.world.inventory.Slot; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.api.item.inventory.transaction.SlotTransaction; @@ -62,9 +63,9 @@ public org.spongepowered.api.item.inventory.Slot viewedSlot() { } @Override - public InventoryTransactionResult set(ItemStack stack) { + public InventoryTransactionResult set(ItemStackLike stack) { final InventoryTransactionResult.Builder result = InventoryTransactionResult.builder().type(InventoryTransactionResult.Type.SUCCESS); - final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.toNative(stack); + final net.minecraft.world.item.ItemStack nativeStack = ItemStackUtil.fromLikeToNative(stack); final net.minecraft.world.item.ItemStack old = this.shadow$getItem(); ItemStackSnapshot oldSnap = ItemStackUtil.snapshotOf(old); From 67f317fab373133cf2c04c337111884d56150935 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 02:18:23 +0300 Subject: [PATCH 194/226] Migrate inventory.type package --- SpongeAPI | 2 +- .../inventory/adapter/impl/comp/GridInventoryAdapter.java | 5 +++-- .../inventory/adapter/impl/comp/Inventory2DAdapter.java | 5 +++-- .../inventory/custom/SpongeViewableInventoryBuilder.java | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 68d2ef7fc47..26492d4356d 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 68d2ef7fc47f158abeac97ba736b5c8c20f7bd9a +Subproject commit 26492d4356d264efa4d8c95ca84854f95606fbf2 diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/GridInventoryAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/GridInventoryAdapter.java index 5e9b6f45c1d..56fc8e6a6a8 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/GridInventoryAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/GridInventoryAdapter.java @@ -26,6 +26,7 @@ import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.api.item.inventory.type.GridInventory; @@ -110,8 +111,8 @@ public Optional peek(int x, int y) { } @Override - public InventoryTransactionResult set(int x, int y, ItemStack stack) { - return AdapterLogic.insertSequential(this.inventoryAdapter$getFabric(), this.getSlotLens(x, y), stack); + public InventoryTransactionResult set(int x, int y, ItemStackLike stack) { + return AdapterLogic.insertSequential(this.inventoryAdapter$getFabric(), this.getSlotLens(x, y), stack.asMutable()); } } diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/Inventory2DAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/Inventory2DAdapter.java index 3bc74c369c5..43c7330af0d 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/Inventory2DAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/comp/Inventory2DAdapter.java @@ -26,6 +26,7 @@ import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.api.item.inventory.type.Inventory2D; @@ -76,8 +77,8 @@ public Optional peek(Vector2i pos) { } @Override - public InventoryTransactionResult set(Vector2i pos, ItemStack stack) { - return AdapterLogic.insertSequential(this.inventoryAdapter$getFabric(), this.getSlotLens(pos), stack); + public InventoryTransactionResult set(Vector2i pos, ItemStackLike stack) { + return AdapterLogic.insertSequential(this.inventoryAdapter$getFabric(), this.getSlotLens(pos), stack.asMutable()); } } diff --git a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java index 7c303f793e0..c37c4dd9a56 100644 --- a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java +++ b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java @@ -58,7 +58,7 @@ import org.spongepowered.api.item.inventory.ContainerType; import org.spongepowered.api.item.inventory.ContainerTypes; import org.spongepowered.api.item.inventory.Inventory; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.type.ViewableInventory; import org.spongepowered.api.registry.DefaultedRegistryReference; @@ -214,8 +214,8 @@ public BuildingStep grid(List source, Vector2i size, int offset) { } // dummy @Override - public BuildingStep item(ItemStackSnapshot item) { - this.lastSlot.set(item.asMutable()); + public BuildingStep item(ItemStackLike item) { + this.lastSlot.set(item); return this; } From 3fbcd80fe24e5553b8349dc3e6073eabd3789ca0 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 02:32:38 +0300 Subject: [PATCH 195/226] finalize migrating item package --- SpongeAPI | 2 +- .../common/event/tracking/phase/packet/PacketPhaseUtil.java | 2 +- .../common/inventory/InventoryTransactionResultImpl.java | 1 - .../common/inventory/adapter/impl/AdapterLogic.java | 2 +- .../inventory/adapter/impl/slots/FilteringSlotAdapter.java | 1 - .../common/inventory/adapter/impl/slots/HeldSlotAdapter.java | 2 -- .../common/inventory/lens/impl/slot/EquipmentSlotLens.java | 2 +- .../common/inventory/lens/impl/slot/FilteringSlotLens.java | 1 - .../minecraft/world/item/enchantment/EnchantmentMixin_API.java | 1 - .../inventory/api/world/inventory/SlotMixin_Inventory_API.java | 1 - 10 files changed, 4 insertions(+), 11 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 26492d4356d..e2d8085fa82 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 26492d4356d264efa4d8c95ca84854f95606fbf2 +Subproject commit e2d8085fa823b19c8de7e58d46e1a1efae2799c7 diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java index aea3d5d144c..db98191c158 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhaseUtil.java @@ -92,7 +92,7 @@ public static void handleSlotRestore(@Nullable final Player player, final @Nulla final org.spongepowered.api.item.inventory.Slot slot = slotTransaction.slot(); final ItemStackSnapshot snapshot = eventCancelled || !slotTransaction.isValid() ? slotTransaction.original() : slotTransaction.custom().get(); if (containerMenu == null || slot.viewedSlot() instanceof Slot) { - slot.set(snapshot.asMutable()); + slot.set(snapshot); } else if (player instanceof ServerPlayer serverPlayer && containerMenu != player.inventoryMenu && serverPlayer.inventory().containsInventory(slot)) { final org.spongepowered.api.item.inventory.ItemStack stack = snapshot.asMutable(); diff --git a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java index 1cf39ad0bb4..38317b9c96f 100644 --- a/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java +++ b/src/main/java/org/spongepowered/common/inventory/InventoryTransactionResultImpl.java @@ -28,7 +28,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java index 6ab2d5548f4..dedae4cc143 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/AdapterLogic.java @@ -109,7 +109,7 @@ public static InventoryTransactionResult.Poll pollSequential(Fabric fabric, @Nul removedType.setQuantity(totalPolled); } - return result.poll(removedType.asImmutable()).build(); + return result.poll(removedType).build(); } public static Optional peekSequential(Fabric fabric, @Nullable Lens lens) { diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java index 4bb84163a6d..55bc5c8e004 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/FilteringSlotAdapter.java @@ -32,7 +32,6 @@ import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.common.inventory.fabric.Fabric; import org.spongepowered.common.inventory.lens.impl.slot.FilteringSlotLens; -import org.spongepowered.common.item.util.ItemStackUtil; public class FilteringSlotAdapter extends SlotAdapter implements FilteringSlot { diff --git a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java index fdbcf3632bd..03cb0814e44 100644 --- a/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java +++ b/src/main/java/org/spongepowered/common/inventory/adapter/impl/slots/HeldSlotAdapter.java @@ -26,14 +26,12 @@ import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.api.item.inventory.slot.EquipmentSlot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.common.inventory.fabric.Fabric; import org.spongepowered.common.inventory.lens.impl.slot.HeldHandSlotLens; -import org.spongepowered.common.item.util.ItemStackUtil; import java.util.function.Predicate; diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java index 0af32460cec..e63fe04826a 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/EquipmentSlotLens.java @@ -52,7 +52,7 @@ private static FilteringSlotLens.ItemStackFilter equipmentTypeFilter(EquipmentTy if (item.isEmpty()) { return true; } - final var equipable = Equipable.get(ItemStackUtil.toNative(item)); + final var equipable = Equipable.get(ItemStackUtil.fromLikeToNative(item)); final var itemSlotType = equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND; return itemSlotType == (Object) type; }; diff --git a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java index 54c9a27e42d..cb1e0731a35 100644 --- a/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java +++ b/src/main/java/org/spongepowered/common/inventory/lens/impl/slot/FilteringSlotLens.java @@ -26,7 +26,6 @@ import net.minecraft.world.Container; import org.spongepowered.api.item.inventory.Inventory; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.common.bridge.world.inventory.InventoryBridge; diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java index 8ed9fe87cf3..3b20df6735d 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/enchantment/EnchantmentMixin_API.java @@ -28,7 +28,6 @@ import net.minecraft.core.Holder; import net.minecraft.world.item.enchantment.Enchantment; import org.spongepowered.api.item.enchantment.EnchantmentType; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java index 1b9a0ef5ae4..16790079ee4 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/inventory/SlotMixin_Inventory_API.java @@ -27,7 +27,6 @@ import net.minecraft.world.Container; import net.minecraft.world.inventory.Slot; import org.spongepowered.api.item.inventory.Inventory; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; From 56369c271e14145bb151d84a0483cc21f6036990 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 16 Sep 2024 03:11:27 +0300 Subject: [PATCH 196/226] Migrate different stuff --- SpongeAPI | 2 +- .../common/advancement/SpongeDisplayInfoBuilder.java | 7 ++++--- .../level/block/entity/JukeboxBlockEntityMixin_API.java | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index e2d8085fa82..47299e1628f 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit e2d8085fa823b19c8de7e58d46e1a1efae2799c7 +Subproject commit 47299e1628fb02b1a980435aaf6043845337c7d7 diff --git a/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java b/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java index c65e7071f48..0f38a02050e 100644 --- a/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java +++ b/src/main/java/org/spongepowered/common/advancement/SpongeDisplayInfoBuilder.java @@ -30,6 +30,7 @@ import org.spongepowered.api.advancement.AdvancementType; import org.spongepowered.api.advancement.AdvancementTypes; import org.spongepowered.api.advancement.DisplayInfo; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.util.Preconditions; @@ -72,9 +73,9 @@ public DisplayInfo.Builder title(final Component title) { } @Override - public DisplayInfo.Builder icon(final ItemStackSnapshot itemStackSnapshot) { - Objects.requireNonNull(itemStackSnapshot, "itemStackSnapshot"); - this.icon = itemStackSnapshot; + public DisplayInfo.Builder icon(final ItemStackLike itemStack) { + Objects.requireNonNull(itemStack, "itemStackSnapshot"); + this.icon = itemStack.asImmutable(); return this; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java index 8c298d407be..885e62a88de 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/JukeboxBlockEntityMixin_API.java @@ -31,7 +31,7 @@ import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.api.block.entity.Jukebox; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.item.util.ItemStackUtil; @@ -74,8 +74,8 @@ public void eject() { } @Override - public void insert(final ItemStack record) { - final net.minecraft.world.item.ItemStack itemStack = ItemStackUtil.toNative(record); + public void insert(final ItemStackLike record) { + final net.minecraft.world.item.ItemStack itemStack = ItemStackUtil.fromLikeToNative(record); final BlockState block = this.level.getBlockState(this.shadow$getBlockPos()); if (block.getBlock() == Blocks.JUKEBOX) { this.shadow$setTheItem(itemStack); From 935ef9b7484f7fc17561109950f1c5dedffb9437 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 13 Jun 2024 21:41:32 +0200 Subject: [PATCH 197/226] WIP Update ModLauncher on SpongeVanilla --- build.gradle.kts | 153 ++++---- forge/build.gradle.kts | 58 +-- .../applaunch/plugin/ForgePluginPlatform.java | 5 - gradle/libs.versions.toml | 9 +- modlauncher-patcher/build.gradle | 22 -- .../mlpatcher/AsmFixerAgent.java | 149 -------- modlauncher-transformers/build.gradle.kts | 5 - .../AccessWidenerTransformationService.java | 4 - .../modlauncher/SuperclassChanger.java | 4 - settings.gradle.kts | 1 - vanilla/build.gradle.kts | 330 +++++++++--------- .../vanilla/applaunch/AppCommandLine.java | 102 ------ .../vanilla/applaunch/Constants.java | 34 ++ .../spongepowered/vanilla/applaunch/Main.java | 95 ----- .../handler/AbstractVanillaLaunchHandler.java | 306 +--------------- .../handler/dev/ClientDevLaunchHandler.java | 10 +- .../handler/dev/ServerDevLaunchHandler.java | 10 +- .../handler/prod/ServerProdLaunchHandler.java | 10 +- .../handler/test/ClientTestLaunchHandler.java | 9 +- .../handler/test/ServerTestLaunchHandler.java | 9 +- .../plugin/VanillaPlatformService.java | 118 ++++--- .../plugin/VanillaPluginPlatform.java | 3 - .../applaunch/util/MixinLoggerInjector.java | 3 +- .../vanilla/installer/Constants.java | 9 - .../vanilla/installer/Agent.java | 3 - 25 files changed, 400 insertions(+), 1061 deletions(-) delete mode 100644 modlauncher-patcher/build.gradle delete mode 100644 modlauncher-patcher/src/main/java/org/spongepowered/mlpatcher/AsmFixerAgent.java delete mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppCommandLine.java create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java delete mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Main.java diff --git a/build.gradle.kts b/build.gradle.kts index 8dfab8d5a90..0ab8e33a941 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,8 @@ val apiVersion: String by project val apiJavaTarget: String by project val minecraftVersion: String by project val recommendedVersion: String by project +val organization: String by project +val projectUrl: String by project val commonManifest = java.manifest { attributes( @@ -34,48 +36,9 @@ val commonManifest = java.manifest { System.getenv()["GIT_BRANCH"]?.apply { attributes("Git-Branch" to this) } } -tasks { - jar { - manifest.from(commonManifest) - } - val mixinsJar by registering(Jar::class) { - archiveClassifier.set("mixins") - manifest.from(commonManifest) - from(mixins.map { it.output }) - } - val accessorsJar by registering(Jar::class) { - archiveClassifier.set("accessors") - manifest.from(commonManifest) - from(accessors.map { it.output }) - } - val launchJar by registering(Jar::class) { - archiveClassifier.set("launch") - manifest.from(commonManifest) - from(launch.map { it.output }) - } - val applaunchJar by registering(Jar::class) { - archiveClassifier.set("applaunch") - manifest.from(commonManifest) - from(applaunch.map { it.output }) - } - - test { - useJUnitPlatform() - } - - check { - dependsOn(gradle.includedBuild("SpongeAPI").task(":check")) - } - - prepareWorkspace { - dependsOn(gradle.includedBuild("SpongeAPI").task(":genEventImpl")) - } - -} - version = spongeImpl.generateImplementationVersionString(apiVersion, minecraftVersion, recommendedVersion) -// Configurations +// SpongeCommon configurations val applaunchConfig by configurations.register("applaunch") val launchConfig by configurations.register("launch") { @@ -90,35 +53,28 @@ val mixinsConfig by configurations.register("mixins") { extendsFrom(launchConfig) } -// create the sourcesets +// SpongeCommon source sets val main by sourceSets val applaunch by sourceSets.registering { spongeImpl.applyNamedDependencyOnOutput(project, this, main, project, main.implementationConfigurationName) - project.dependencies { - mixinsConfig(this@registering.output) - } + configurations.named(implementationConfigurationName) { extendsFrom(applaunchConfig) } } val launch by sourceSets.registering { spongeImpl.applyNamedDependencyOnOutput(project, applaunch.get(), this, project, this.implementationConfigurationName) - project.dependencies { - mixinsConfig(this@registering.output) - } - project.dependencies { - implementation(this@registering.output) - } + spongeImpl.applyNamedDependencyOnOutput(project, this, main, project, main.implementationConfigurationName) configurations.named(implementationConfigurationName) { extendsFrom(launchConfig) } } - val accessors by sourceSets.registering { spongeImpl.applyNamedDependencyOnOutput(project, launch.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, this, main, project, main.implementationConfigurationName) + configurations.named(implementationConfigurationName) { extendsFrom(accessorsConfig) } @@ -128,6 +84,7 @@ val mixins by sourceSets.registering { spongeImpl.applyNamedDependencyOnOutput(project, applaunch.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, accessors.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, main, this, project, this.implementationConfigurationName) + configurations.named(implementationConfigurationName) { extendsFrom(mixinsConfig) } @@ -199,7 +156,6 @@ dependencies { applaunchConfig(libs.log4j.core) applaunchConfig(libs.log4j.jpl) - mixinsConfig(sourceSets.main.map { it.output }) add(mixins.get().implementationConfigurationName, "org.spongepowered:spongeapi:$apiVersion") // Tests @@ -215,8 +171,6 @@ dependencies { } } -val organization: String by project -val projectUrl: String by project indraSpotlessLicenser { licenseHeaderFile(rootProject.file("HEADER.txt")) @@ -229,7 +183,6 @@ idea { if (project != null) { (project as ExtensionAware).extensions["settings"].run { (this as ExtensionAware).extensions.getByType(org.jetbrains.gradle.ext.TaskTriggersConfig::class).run { - afterSync(":modlauncher-patcher:build") afterSync(":modlauncher-transformers:build") } } @@ -365,6 +318,38 @@ allprojects { } } + tasks.register("printConfigsHierarchy") { + group = "debug" + doLast { + configurations.forEach { conf: Configuration -> + val seen = mutableSetOf() + println("Parents of ${conf.name}:") + printParents(conf, "", seen) + } + } + } + + tasks.register("printConfigsResolution") { + group = "debug" + doLast { + configurations.forEach { conf: Configuration -> + println() + println("Artifacts of ${conf.name}:") + if (conf.isCanBeResolved) { + try { + conf.forEach { + println(it) + } + } catch (e: Exception) { + println("error") + } + } else { + println("not resolved") + } + } + } + } + afterEvaluate { publishing { repositories { @@ -395,34 +380,80 @@ allprojects { } } +fun printParents(conf: Configuration, indent: String, seen: MutableSet) { + for (parent in conf.extendsFrom) { + if (parent in seen) { + continue + } + seen.add(parent) + println("$indent - ${parent.name}") + printParents(parent, indent + " ", seen) + } +} + tasks { + jar { + manifest.from(commonManifest) + } + val mixinsJar by registering(Jar::class) { + archiveClassifier.set("mixins") + manifest.from(commonManifest) + from(mixins.map { it.output }) + } + val accessorsJar by registering(Jar::class) { + archiveClassifier.set("accessors") + manifest.from(commonManifest) + from(accessors.map { it.output }) + } + val launchJar by registering(Jar::class) { + archiveClassifier.set("launch") + manifest.from(commonManifest) + from(launch.map { it.output }) + } + val applaunchJar by registering(Jar::class) { + archiveClassifier.set("applaunch") + manifest.from(commonManifest) + from(applaunch.map { it.output }) + } + val jar by existing val sourcesJar by existing - val mixinsJar by existing - val accessorsJar by existing - val launchJar by existing - val applaunchJar by existing shadowJar { mergeServiceFiles() archiveClassifier.set("dev") + manifest { attributes(mapOf( - "Access-Widener" to "common.accesswidener", - "Multi-Release" to true + "Access-Widener" to "common.accesswidener", + "Multi-Release" to true )) from(commonManifest) } + from(jar) from(sourcesJar) from(mixinsJar) from(accessorsJar) from(launchJar) from(applaunchJar) + dependencies { include(project(":")) } } + + test { + useJUnitPlatform() + } + + check { + dependsOn(gradle.includedBuild("SpongeAPI").task(":check")) + } + + prepareWorkspace { + dependsOn(gradle.includedBuild("SpongeAPI").task(":genEventImpl")) + } } publishing { diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index 6b1b816b98c..f513ad15071 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -19,6 +19,8 @@ plugins { val commonProject = parent!! val transformersProject = parent!!.project(":modlauncher-transformers") +val testPluginsProject: Project? = rootProject.subprojects.find { "testplugins" == it.name } + val apiVersion: String by project val minecraftVersion: String by project val forgeVersion: String by project @@ -26,8 +28,6 @@ val recommendedVersion: String by project val organization: String by project val projectUrl: String by project -val testPluginsProject: Project? = rootProject.subprojects.find { "testplugins" == it.name } - description = "The SpongeAPI implementation for MinecraftForge" version = spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVersion, recommendedVersion, forgeVersion) @@ -70,7 +70,7 @@ val gameLayerConfig: NamedDomainObjectProvider = configurations.r } } -// Common source sets and configurations +// SpongeCommon source sets val launchConfig: NamedDomainObjectProvider = commonProject.configurations.named("launch") val accessors: NamedDomainObjectProvider = commonProject.sourceSets.named("accessors") val launch: NamedDomainObjectProvider = commonProject.sourceSets.named("launch") @@ -78,7 +78,7 @@ val applaunch: NamedDomainObjectProvider = commonProject.sourceSets.n val mixins: NamedDomainObjectProvider = commonProject.sourceSets.named("mixins") val main: NamedDomainObjectProvider = commonProject.sourceSets.named("main") -// Forge source sets +// SpongeForge source sets val forgeMain by sourceSets.named("main") { // implementation (compile) dependencies spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName) @@ -102,6 +102,7 @@ val forgeLaunch by sourceSets.register("launch") { } val forgeAccessors by sourceSets.register("accessors") { spongeImpl.applyNamedDependencyOnOutput(commonProject, mixins.get(), this, project, this.implementationConfigurationName) + spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, this, forgeLaunch, project, forgeLaunch.implementationConfigurationName) configurations.named(implementationConfigurationName) { @@ -326,7 +327,7 @@ tasks { .toList() } - // jvmArguments.add("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath + jvmArguments.add("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath sourceSets.forEach { dependsOn(it.classesTaskName) @@ -491,45 +492,20 @@ publishing { } } -tasks.register("printConfigsHierarchy") { - group = "debug" - doLast { - configurations.forEach { conf: Configuration -> - val seen = mutableSetOf() - println("Parents of ${conf.name}:") - printParents(conf, "", seen) - } - } -} - -fun printParents(conf: Configuration, indent: String, seen: MutableSet) { - for (parent in conf.extendsFrom) { - if (parent in seen) { - continue - } - seen.add(parent) - println("$indent - ${parent.name}") - printParents(parent, indent + " ", seen) - } -} - -tasks.register("printConfigsResolution") { +tasks.register("printRunTasks") { group = "debug" doLast { - configurations.forEach { conf: Configuration -> + tasks.withType(net.fabricmc.loom.task.AbstractRunTask::class) { println() - println("Artifacts of ${conf.name}:") - if (conf.isCanBeResolved) { - try { - conf.forEach { - println(it) - } - } catch (e: Exception) { - println("error") - } - } else { - println("not resolved") - } + println("Task ${this.name}:") + println("mainClass: " + this.mainClass.orNull) + println("mainModule: " + this.mainModule.orNull) + println("allJvmArgs: " + this.allJvmArgs) + println("jvmArgs: " + this.jvmArgs) + println("args: " + this.args) + println("commandLine: " + this.commandLine) + println("environment: " + this.environment) + println("classpath: " + this.classpath.files) } } } diff --git a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/plugin/ForgePluginPlatform.java b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/plugin/ForgePluginPlatform.java index f054ca99da1..e72dc791b8e 100644 --- a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/plugin/ForgePluginPlatform.java +++ b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/plugin/ForgePluginPlatform.java @@ -49,11 +49,6 @@ public final class ForgePluginPlatform implements PluginPlatform { private final Logger logger; private final List pluginDirectories; - /** - * Bootstrap - * @param environment - * @return - */ public static synchronized boolean bootstrap(final Environment environment) { if (ForgePluginPlatform.bootstrapped) { return false; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 805458ce703..599cabe41e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,9 @@ asm = "9.7" log4j = "2.22.1" forgeAutoRenamingTool = "1.0.6" mixin = "0.8.7" -modlauncher = "8.1.3" +bootstrap = "2.1.1" +modlauncher = "10.2.1" +securemodules = "2.2.20" guava = "32.1.2-jre" mockito = "5.11.0" jline = "3.25.1" @@ -22,13 +24,14 @@ asm-analysis = { module = "org.ow2.asm:asm-analysis", version.ref = "asm" } asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } asm-util = { module = "org.ow2.asm:asm-util", version.ref = "asm" } asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } -grossJava9Hacks = { module = "cpw.mods:grossjava9hacks", version = "1.3.3" } joptSimple = { module = "net.sf.jopt-simple:jopt-simple", version = "5.0.4" } log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-jpl = { module = "org.apache.logging.log4j:log4j-jpl", version.ref = "log4j" } log4j-slf4j2 = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version.ref = "log4j" } -modlauncher = { module = "cpw.mods:modlauncher", version.ref = "modlauncher" } +bootstrap = { module = "net.minecraftforge:bootstrap", version.ref = "bootstrap" } +modlauncher = { module = "net.minecraftforge:modlauncher", version.ref = "modlauncher" } +securemodules = { module = "net.minecraftforge:securemodules", version.ref = "securemodules" } tinylog-api = { module = "org.tinylog:tinylog-api", version.ref = "tinylog" } tinylog-impl = { module = "org.tinylog:tinylog-impl", version.ref = "tinylog" } tinylog-slf4j = { module = "org.tinylog:slf4j-tinylog", version.ref = "tinylog" } diff --git a/modlauncher-patcher/build.gradle b/modlauncher-patcher/build.gradle deleted file mode 100644 index 03e64a2a5fe..00000000000 --- a/modlauncher-patcher/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -dependencies { - implementation libs.asm -} - -// Make sure jar is present for other projects -eclipse { - synchronizationTasks 'jar' -} - -tasks.named('jar') { - manifest.attributes "Premain-Class": "org.spongepowered.mlpatcher.AsmFixerAgent", - "Agent-Class": "org.spongepowered.mlpatcher.AsmFixerAgent" - -} - -indraSpotlessLicenser { - licenseHeaderFile rootProject.file("HEADER.txt") - - property "name", "Sponge" - property "organization", organization - property "url", projectUrl -} diff --git a/modlauncher-patcher/src/main/java/org/spongepowered/mlpatcher/AsmFixerAgent.java b/modlauncher-patcher/src/main/java/org/spongepowered/mlpatcher/AsmFixerAgent.java deleted file mode 100644 index fa9e00da844..00000000000 --- a/modlauncher-patcher/src/main/java/org/spongepowered/mlpatcher/AsmFixerAgent.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.mlpatcher; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.lang.instrument.Instrumentation; -import java.security.ProtectionDomain; -import java.util.Map; -import java.util.Set; - -public class AsmFixerAgent { - private static final int ASM_VERSION = Opcodes.ASM9; - - private static Instrumentation instrumentation; - - public static void premain(final String agentArgs, final Instrumentation instrumentation) { - AsmFixerAgent.instrumentation = instrumentation; - AsmFixerAgent.setup(); - } - - public static void agentmain(final String agentArgs, final Instrumentation instrumentation) { - AsmFixerAgent.instrumentation = instrumentation; - AsmFixerAgent.setup(); - } - - private static void setup() { - AsmFixerAgent.instrumentation.addTransformer(new MLFixer()); - } - - private AsmFixerAgent() { - } - - private static class MLFixer implements ClassFileTransformer { - - record PatchInfo(Set methodsToPatch) { - - public PatchInfo(final String... methods) { - this(Set.of(methods)); - } - } - - private final Map patch = Map.of( - "cpw/mods/modlauncher/TransformerClassWriter$SuperCollectingVisitor", new PatchInfo(""), - "cpw/mods/modlauncher/ClassTransformer", new PatchInfo("transform"), - "cpw/mods/modlauncher/PredicateVisitor", new PatchInfo("") - ); - - @Override - public byte[] transform( - final Module module, - final ClassLoader loader, - final String className, - final Class classBeingRedefined, - final ProtectionDomain protectionDomain, - final byte[] classfileBuffer - ) throws IllegalClassFormatException { - if (!this.patch.containsKey(className)) { - return classfileBuffer; - } - - final ClassReader reader = new ClassReader(classfileBuffer); - final ClassWriter writer = new ClassWriter(reader, 0); - - reader.accept(new Cls(writer, this.patch.get(className)), 0); - - return writer.toByteArray(); - } - - private static class Cls extends ClassVisitor { - private final PatchInfo data; - public Cls(final ClassVisitor parent, final PatchInfo data) { - super(AsmFixerAgent.ASM_VERSION, parent); - this.data = data; - } - - @Override - public MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions - ) { - final MethodVisitor parent = super.visitMethod( - access, - name, - descriptor, - signature, - exceptions - ); - - if (this.data.methodsToPatch.contains(name)) { - return new Method(parent); - } else { - return parent; - } - - } - - } - - private static class Method extends MethodVisitor { - public Method(final MethodVisitor parent) { - super(AsmFixerAgent.ASM_VERSION, parent); - } - - @Override - public void visitLdcInsn(final Object value) { - if (value instanceof Integer && ((Integer) value).intValue() == Opcodes.ASM7) { - super.visitLdcInsn(AsmFixerAgent.ASM_VERSION); - } else { - super.visitLdcInsn(value); - } - } - } - - } - - -} diff --git a/modlauncher-transformers/build.gradle.kts b/modlauncher-transformers/build.gradle.kts index 13753910654..238ee465cc3 100644 --- a/modlauncher-transformers/build.gradle.kts +++ b/modlauncher-transformers/build.gradle.kts @@ -7,7 +7,6 @@ eclipse { synchronizationTasks(tasks.jar) } - val organization: String by project val projectUrl: String by project @@ -31,14 +30,10 @@ dependencies { compileOnly(libs.modlauncher) { exclude(group = "org.ow2.asm") exclude(group = "org.apache.logging.log4j") - exclude(group = "net.sf.jopt-simple") // uses a newer version than MC } compileOnly(libs.joptSimple) compileOnly(libs.asm.commons) - compileOnly(libs.grossJava9Hacks) { - exclude(group="org.apache.logging.log4j") - } // Configurate dependencies, also to be provided by the platform // making use of this project compileOnly(platform(apiLibs.configurate.bom)) diff --git a/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/AccessWidenerTransformationService.java b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/AccessWidenerTransformationService.java index 2570580d24c..9dec53fc0ce 100644 --- a/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/AccessWidenerTransformationService.java +++ b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/AccessWidenerTransformationService.java @@ -106,10 +106,6 @@ public void argumentValues(final OptionResult option) { public void initialize(final IEnvironment environment) { } - @Override - public void beginScanning(final IEnvironment environment) { - } - @Override @SuppressWarnings("rawtypes") // :( public @NonNull List transformers() { diff --git a/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/SuperclassChanger.java b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/SuperclassChanger.java index e0e8aacbc74..1cce82fbbe5 100644 --- a/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/SuperclassChanger.java +++ b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/SuperclassChanger.java @@ -112,10 +112,6 @@ public void argumentValues(final OptionResult option) { public void initialize(final IEnvironment environment) { } - @Override - public void beginScanning(final IEnvironment environment) { - } - @Override @SuppressWarnings("rawtypes") // :( public @NonNull List transformers() { diff --git a/settings.gradle.kts b/settings.gradle.kts index 24cd27fbdf6..50bc2b07780 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -61,7 +61,6 @@ include(":SpongeVanilla") project(":SpongeVanilla").projectDir = file("vanilla") include("modlauncher-transformers") include("generator") -include("modlauncher-patcher") val testPlugins = file("testplugins.settings.gradle.kts") if (testPlugins.exists()) { diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index 5fd71ad4636..ddf19e96537 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -7,6 +7,9 @@ plugins { } val commonProject = parent!! +val transformersProject = parent!!.project(":modlauncher-transformers") +val testPluginsProject: Project? = rootProject.subprojects.find { "testplugins" == it.name } + val apiVersion: String by project val apiJavaTarget: String by project val minecraftVersion: String by project @@ -14,45 +17,63 @@ val recommendedVersion: String by project val organization: String by project val projectUrl: String by project -val testplugins: Project? = rootProject.subprojects.find { "testplugins".equals(it.name) } - description = "The SpongeAPI implementation for Vanilla Minecraft" version = spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVersion, recommendedVersion) -// Vanilla extra configurations -val vanillaBootstrapLibrariesConfig = configurations.register("bootstrapLibraries") -val vanillaLibrariesConfig = configurations.register("libraries") -val mlTransformersConfig = configurations.register("mlTransformers") -val vanillaAppLaunchConfig = configurations.register("applaunch") { - extendsFrom(vanillaBootstrapLibrariesConfig.get()) - extendsFrom(configurations.minecraft.get()) - extendsFrom(mlTransformersConfig.get()) +// SpongeVanilla libraries +val installerLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeInstallerLibraries") +val bootstrapLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootstrapModules") // JVM initial classpath +val launcherLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeLauncherLibraries") // ModLauncher boot +val serviceLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeServiceLibraries") +val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameLibraries") + +val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameManagedLibraries") + +val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameShadedLibraries") + +val runTaskOnlyConfig: NamedDomainObjectProvider = configurations.register("runTaskOnly") + +// ModLauncher layers +val bootLayerConfig: NamedDomainObjectProvider = configurations.register("bootLayer") { + extendsFrom(bootstrapLibrariesConfig.get()) + extendsFrom(launcherLibrariesConfig.get()) +} +val serviceLayerConfig: NamedDomainObjectProvider = configurations.register("serviceLayer") { + extendsFrom(bootLayerConfig.get()) + extendsFrom(serviceLibrariesConfig.get()) +} +val langLayerConfig: NamedDomainObjectProvider = configurations.register("langLayer") { + extendsFrom(bootLayerConfig.get()) } -val mlpatcherConfig = configurations.register("mlpatcher") -val vanillaInstallerConfig = configurations.register("installer") { - extendsFrom(mlpatcherConfig.get()) - extendsFrom(mlTransformersConfig.get()) +val gameLayerConfig: NamedDomainObjectProvider = configurations.register("gameLayer") { + extendsFrom(serviceLayerConfig.get()) + extendsFrom(langLayerConfig.get()) + extendsFrom(gameLibrariesConfig.get()) + extendsFrom(configurations.minecraft.get()) } -// Common source sets and configurations -val launchConfig = commonProject.configurations.named("launch") -val accessors = commonProject.sourceSets.named("accessors") -val launch = commonProject.sourceSets.named("launch") -val applaunch = commonProject.sourceSets.named("applaunch") -val mixins = commonProject.sourceSets.named("mixins") -val main = commonProject.sourceSets.named("main") +// SpongeCommon source sets +val accessors: NamedDomainObjectProvider = commonProject.sourceSets.named("accessors") +val launch: NamedDomainObjectProvider = commonProject.sourceSets.named("launch") +val applaunch: NamedDomainObjectProvider = commonProject.sourceSets.named("applaunch") +val mixins: NamedDomainObjectProvider = commonProject.sourceSets.named("mixins") +val main: NamedDomainObjectProvider = commonProject.sourceSets.named("main") -// Vanilla source sets -val vanillaInstaller by sourceSets.register("installer") +// SpongeVanilla source sets +val vanillaInstaller by sourceSets.register("installer") { + configurations.named(implementationConfigurationName) { + extendsFrom(installerLibrariesConfig.get()) + } +} val vanillaMain by sourceSets.named("main") { // implementation (compile) dependencies spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName) + configurations.named(implementationConfigurationName) { - extendsFrom(vanillaLibrariesConfig.get()) - extendsFrom(vanillaBootstrapLibrariesConfig.get()) + extendsFrom(gameLayerConfig.get()) } } val vanillaLaunch by sourceSets.register("launch") { @@ -63,18 +84,17 @@ val vanillaLaunch by sourceSets.register("launch") { spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaMain, project, vanillaMain.implementationConfigurationName) configurations.named(implementationConfigurationName) { - extendsFrom(vanillaLibrariesConfig.get()) - extendsFrom(vanillaAppLaunchConfig.get()) + extendsFrom(gameLayerConfig.get()) } } val vanillaAccessors by sourceSets.register("accessors") { spongeImpl.applyNamedDependencyOnOutput(commonProject, mixins.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaMain, this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.implementationConfigurationName) + spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaLaunch, project, vanillaLaunch.implementationConfigurationName) + + configurations.named(implementationConfigurationName) { + extendsFrom(gameLayerConfig.get()) + } } val vanillaMixins by sourceSets.register("mixins") { // implementation (compile) dependencies @@ -84,50 +104,31 @@ val vanillaMixins by sourceSets.register("mixins") { spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, vanillaMain, this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, vanillaAccessors, this, project, this.implementationConfigurationName) + spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.implementationConfigurationName) + + configurations.named(implementationConfigurationName) { + extendsFrom(gameLayerConfig.get()) + } +} +val vanillaLang by sourceSets.register("lang") { + configurations.named(implementationConfigurationName) { + extendsFrom(langLayerConfig.get()) + } } val vanillaAppLaunch by sourceSets.register("applaunch") { // implementation (compile) dependencies spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), vanillaLaunch, project, this.implementationConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaInstaller, this, project, this.implementationConfigurationName) spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaLaunch, project, vanillaLaunch.implementationConfigurationName) - // runtime dependencies - literally add the rest of the project, because we want to launch the game - spongeImpl.applyNamedDependencyOnOutput(project, vanillaMixins, this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, mixins.get(), this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaMain, this, project, this.runtimeOnlyConfigurationName) - spongeImpl.applyNamedDependencyOnOutput(project, vanillaAccessors, this, project, this.runtimeOnlyConfigurationName) - - configurations.named(runtimeClasspathConfigurationName) { - extendsFrom(vanillaLibrariesConfig.get()) - extendsFrom(mlpatcherConfig.get()) - extendsFrom(mlTransformersConfig.get()) - } -} - -val vanillaAccessorsImplementation by configurations.named(vanillaAccessors.implementationConfigurationName) { - extendsFrom(vanillaAppLaunchConfig.get()) -} -val vanillaMixinsImplementation by configurations.named(vanillaMixins.implementationConfigurationName) { - extendsFrom(vanillaAppLaunchConfig.get()) - extendsFrom(vanillaLibrariesConfig.get()) -} -configurations.named(vanillaInstaller.implementationConfigurationName) { - extendsFrom(vanillaInstallerConfig.get()) -} -configurations.named(vanillaAppLaunch.implementationConfigurationName) { - extendsFrom(vanillaAppLaunchConfig.get()) - extendsFrom(launchConfig.get()) + configurations.named(implementationConfigurationName) { + extendsFrom(serviceLayerConfig.get()) + } } -val vanillaAppLaunchRuntime by configurations.named(vanillaAppLaunch.runtimeOnlyConfigurationName) val superclassConfigs = spongeImpl.getNamedConfigurations("superClassChanges") val mixinConfigs = spongeImpl.mixinConfigurations + minecraft { runs { // Full development environment @@ -161,27 +162,11 @@ minecraft { "-Dmixin.debug.strict=true", "-Dmixin.debug.strict.unique=false" ) - allJvmArgumentProviders += CommandLineArgumentProvider { - // todo: Mixin agent does not currently work in 0.8.4 - /*// Resolve the Mixin artifact for use as a reload agent - val mixinJar = vanillaAppLaunchConfig.get().resolvedConfiguration - .getFiles { it.name == "mixin" && it.group == "org.spongepowered" } - .firstOrNull() - - // The mixin agent initializes logging too early, which prevents jansi from properly stripping escape codes in Eclipse. - val base = if (!org.spongepowered.gradle.vanilla.internal.util.IdeConfigurer.isEclipseImport() && mixinJar != null) { - listOf("-javaagent:$mixinJar") - } else { - emptyList() - }*/ - - // Then add necessary module cracks - listOf( - "--add-exports=java.base/sun.security.util=ALL-UNNAMED", // ModLauncher - "--add-opens=java.base/java.util.jar=ALL-UNNAMED", // ModLauncher - "-javaagent:${mlpatcherConfig.get().resolvedConfiguration.files.firstOrNull()}" - ) - } + + // ModLauncher + jvmArgs("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath + mainClass("net.minecraftforge.bootstrap.ForgeBootstrap") + allArgumentProviders += CommandLineArgumentProvider { mixinConfigs.asSequence() .flatMap { sequenceOf("--mixin.config", it) } @@ -192,37 +177,55 @@ minecraft { .flatMap { sequenceOf("--superclass_change.config", it) } .toList() } - mainClass("org.spongepowered.vanilla.applaunch.Main") - classpath.setFrom( - vanillaAppLaunch.output, - vanillaAppLaunch.runtimeClasspath, - ) - ideaRunSourceSet.set(vanillaAppLaunch) + } + + all { + tasks.named(this.name, JavaExec::class) { + // Put modules in boot layer + classpath = files( + vanillaAppLaunch.output, + vanillaAppLaunch.runtimeClasspath, + runTaskOnlyConfig + ) + + // Merge applaunch sourcesets in a single module + val applaunchOutputs = arrayOf(applaunch.get().output, vanillaAppLaunch.output) + val applaunchDirs: MutableList = mutableListOf() + applaunchOutputs.forEach { + applaunchDirs.add(it.resourcesDir!!) + applaunchDirs.addAll(it.classesDirs) + } + environment("MOD_CLASSES", applaunchDirs.joinToString(";") { "applaunch%%$it" }) + } } } - commonProject.sourceSets["main"].resources + + main.get().resources .filter { it.name.endsWith(".accesswidener") } .files - .forEach { - accessWideners(it) - } + .forEach { accessWideners(it) } - project.sourceSets["main"].resources + vanillaMain.resources .filter { it.name.endsWith(".accesswidener") } .files .forEach { accessWideners(it) } } +configurations.configureEach { + // Force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+ + resolutionStrategy { + force("net.sf.jopt-simple:jopt-simple:5.0.4") + } +} + dependencies { api(project(":", configuration = "launch")) implementation(project(":", configuration = "accessors")) implementation(project(commonProject.path)) - mlpatcherConfig.name(project(":modlauncher-patcher")) - vanillaAccessorsImplementation(project(commonProject.path)) - vanillaMixinsImplementation(project(commonProject.path)) + vanillaMixins.implementationConfigurationName(project(commonProject.path)) - val installer = vanillaInstallerConfig.name + val installer = installerLibrariesConfig.name installer(apiLibs.gson) installer(platform(apiLibs.configurate.bom)) installer(apiLibs.configurate.hocon) @@ -240,98 +243,86 @@ dependencies { exclude(group = "net.sf.jopt-simple") asmExclusions.forEach { exclude(group = it.get().group, module = it.get().name) } // Use our own ASM version } - mlTransformersConfig.name(rootProject.project(":modlauncher-transformers")) // Add the API as a runtime dependency, just so it gets shaded into the jar add(vanillaInstaller.runtimeOnlyConfigurationName, "org.spongepowered:spongeapi:$apiVersion") { isTransitive = false } - val appLaunch = vanillaAppLaunchConfig.name + val bootstrap = bootstrapLibrariesConfig.name + bootstrap(libs.bootstrap) + bootstrap(libs.securemodules) + bootstrap(libs.asm.commons) + bootstrap(libs.asm.util) - val bootstrapLibraries = vanillaBootstrapLibrariesConfig.name - val libraries = vanillaLibrariesConfig.name - - // Libraries only needed on the TCL (during main game lifecycle) - - libraries("org.spongepowered:spongeapi:$apiVersion") - libraries(platform(apiLibs.adventure.bom)) { - exclude(group = "org.jetbrains", module = "annotations") - } - libraries(libs.adventure.serializerConfigurate4) { - exclude(group = "org.checkerframework", module = "checker-qual") - } - libraries(libs.javaxInject) - libraries(libs.configurate.jackson) { - exclude(group = "org.spongepowered", module = "configurate-core") - exclude(group = "org.checkerframework", module = "checker-qual") + val launcher = launcherLibrariesConfig.name + launcher(libs.modlauncher) { + exclude(group = "org.apache.logging.log4j") } - - libraries(libs.adventure.serializerAnsi) { - exclude(group = "org.jetbrains", module = "annotations") + launcher(apiLibs.pluginSpi) { exclude(group = "org.checkerframework", module = "checker-qual") + exclude(group = "com.google.code.gson", module = "gson") + exclude(group = "org.apache.logging.log4j", module = "log4j-api") + exclude(group = "org.apache.commons", module = "commons-lang3") } + launcher(libs.lmaxDisruptor) + launcher(apiLibs.checkerQual) - // Libraries needed during applaunch phase and runtime - bootstrapLibraries(libs.terminalConsoleAppender) { + launcher(libs.terminalConsoleAppender) { exclude(group = "org.jline", module = "jline-reader") exclude(group = "org.apache.logging.log4j", module = "log4j-core") } - bootstrapLibraries(apiLibs.checkerQual) - bootstrapLibraries(libs.jline.terminal) - bootstrapLibraries(libs.jline.reader) - bootstrapLibraries(libs.jline.terminalJansi) - // Must be on the base ClassLoader since ModLauncher has a dependency on log4j - bootstrapLibraries(libs.log4j.jpl) + launcher(libs.jline.terminal) + launcher(libs.jline.reader) + launcher(libs.jline.terminalJansi) - bootstrapLibraries(platform(apiLibs.configurate.bom)) - bootstrapLibraries(apiLibs.configurate.core) { + launcher(libs.log4j.jpl) + launcher(libs.log4j.api) + launcher(libs.log4j.core) + launcher(libs.log4j.slf4j2) + + launcher(platform(apiLibs.configurate.bom)) + launcher(apiLibs.configurate.core) { exclude(group = "org.checkerframework", module = "checker-qual") } - bootstrapLibraries(apiLibs.configurate.hocon) { + launcher(apiLibs.configurate.hocon) { exclude(group = "org.spongepowered", module = "configurate-core") exclude(group = "org.checkerframework", module = "checker-qual") } - bootstrapLibraries(libs.log4j.api) - bootstrapLibraries(libs.log4j.core) - bootstrapLibraries(libs.log4j.slf4j2) { - exclude(group = "org.slf4j", module = "slf4j-api") - } - // Mixin and dependencies - bootstrapLibraries(libs.mixin) - bootstrapLibraries(libs.asm.util) - bootstrapLibraries(libs.asm.tree) - bootstrapLibraries(libs.guava) { + launcher(libs.mixin) + launcher(libs.asm.tree) + launcher(libs.guava) { exclude(group = "com.google.errorprone", module = "error_prone_annotations") exclude(group = "org.checkerframework", module = "checker-qual") } - // Launch Dependencies - Needed to bootstrap the engine(s) - // Not needing to be source-visible past the init phase - // The ModLauncher compatibility launch layer - appLaunch(libs.modlauncher) { - exclude(group = "org.ow2.asm") - exclude(group = "org.apache.logging.log4j") - exclude(group = "net.sf.jopt-simple") // uses a newer version than MC + val service = serviceLibrariesConfig.name + service(project(transformersProject.path)) + + val game = gameLibrariesConfig.name + game("org.spongepowered:spongeapi:$apiVersion") + game(platform(apiLibs.adventure.bom)) { + exclude(group = "org.jetbrains", module = "annotations") } - appLaunch(libs.asm.commons) - appLaunch(libs.grossJava9Hacks) { - exclude(group = "org.apache.logging.log4j") + game(libs.adventure.serializerConfigurate4) { + exclude(group = "org.checkerframework", module = "checker-qual") + } + game(libs.javaxInject) + game(libs.configurate.jackson) { + exclude(group = "org.spongepowered", module = "configurate-core") + exclude(group = "org.checkerframework", module = "checker-qual") } - appLaunch(apiLibs.pluginSpi) { + game(libs.adventure.serializerAnsi) { + exclude(group = "org.jetbrains", module = "annotations") exclude(group = "org.checkerframework", module = "checker-qual") - exclude(group = "com.google.code.gson", module = "gson") - exclude(group = "org.apache.logging.log4j", module = "log4j-api") - exclude(group = "org.apache.commons", module = "commons-lang3") } - appLaunch(libs.lmaxDisruptor) - testplugins?.also { - vanillaAppLaunchRuntime(project(it.path)) { - exclude(group = "org.spongepowered") - } - } + // TODO list shaded / managed libraries + + val runTaskOnly = runTaskOnlyConfig.name + // Allow boot layer manipulation such as merging applaunch sourcesets + runTaskOnly("net.minecraftforge:bootstrap-dev:2.1.1") } val vanillaManifest = java.manifest { @@ -409,18 +400,11 @@ tasks { val installerResources = project.layout.buildDirectory.dir("generated/resources/installer") vanillaInstaller.resources.srcDir(installerResources) - val downloadNotNeeded = configurations.register("downloadNotNeeded") { - extendsFrom(configurations.minecraft.get()) - extendsFrom(vanillaInstallerConfig.get()) - } - val emitDependencies by registering(org.spongepowered.gradle.impl.OutputDependenciesToJson::class) { group = "sponge" - // everything in applaunch goes -> bootstrap, everything in libraries goes -> main (MC is inserted here too) - this.dependencies("bootstrap", vanillaAppLaunchConfig) - this.dependencies("main", vanillaLibrariesConfig) - // except what we're providing through the installer - this.excludedDependencies(downloadNotNeeded) + this.dependencies("bootstrap", launcherLibrariesConfig) + this.dependencies("main", gameManagedLibrariesConfig) + this.excludedDependencies(gameShadedLibrariesConfig) outputFile.set(installerResources.map { it.file("libraries.json") }) } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppCommandLine.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppCommandLine.java deleted file mode 100644 index 22324628acc..00000000000 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppCommandLine.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.applaunch; - -import joptsimple.ArgumentAcceptingOptionSpec; -import joptsimple.OptionParser; -import joptsimple.OptionSet; -import joptsimple.util.PathConverter; -import joptsimple.util.PathProperties; -import org.spongepowered.vanilla.installer.Constants; - -import java.io.InputStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.jar.Manifest; - -public final class AppCommandLine { - - private static final OptionParser PARSER = new OptionParser(); - private static final ArgumentAcceptingOptionSpec LAUNCH_TARGET_ARG = AppCommandLine.PARSER.accepts("launchTarget", "Launch Target") - .withRequiredArg(); - private static final ArgumentAcceptingOptionSpec GAME_DIRECTORY_ARG = AppCommandLine.PARSER.accepts("gameDir", "Alternative game directory") - .withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)).defaultsTo(Paths.get(".")); - - public static String[] RAW_ARGS; - public static AppLaunchTargets launchTarget; - public static Path gameDirectory; - - public static void configure(String[] args) throws Exception { - AppCommandLine.PARSER.allowsUnrecognizedOptions(); - - final OptionSet options = AppCommandLine.PARSER.parse(args); - - String launchTarget = options.valueOf(AppCommandLine.LAUNCH_TARGET_ARG); - boolean manifestTarget = false; - if (launchTarget == null) { - final Path executionJar = Paths.get(AppCommandLine.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - try (final FileSystem system = FileSystems.newFileSystem(executionJar, (ClassLoader) null)) { - final Path manifestFile = system.getPath("META-INF", "MANIFEST.MF"); - if (Files.notExists(manifestFile)) { - throw new RuntimeException("The installer contains no manifest!"); - } - - // Try the manifest before we give up - try (final InputStream stream = Files.newInputStream(manifestFile)) { - final Manifest manifest = new Manifest(stream); - launchTarget = manifest.getMainAttributes().getValue(Constants.ManifestAttributes.LAUNCH_TARGET); - manifestTarget = true; - } - } - } - - if (launchTarget == null) { - throw new RuntimeException("No launch target has been specified! Check your run configs/manifest..."); - } - - AppCommandLine.launchTarget = AppLaunchTargets.from(launchTarget); - if (AppCommandLine.launchTarget == null) { - throw new RuntimeException("Invalid launch target specified!"); - } - - if (manifestTarget) { - String[] temp = new String[args.length + 2]; - System.arraycopy(args, 0, temp, 0, args.length); - temp[args.length] = "--launchTarget"; - temp[args.length + 1] = launchTarget; - args = temp; - } - - AppCommandLine.gameDirectory = options.valueOf(AppCommandLine.GAME_DIRECTORY_ARG); - - AppCommandLine.RAW_ARGS = args; - } - - private AppCommandLine() { - } -} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java new file mode 100644 index 00000000000..d133eccd84c --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java @@ -0,0 +1,34 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch; + +public final class Constants { + + public static final class ManifestAttributes { + public static final String ACCESS_WIDENER = "Access-Widener"; + public static final String LAUNCH_TARGET = "Launch-Target"; + public static final String SUPERCLASS_CHANGE = "Superclass-Transformer"; + } +} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Main.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Main.java deleted file mode 100644 index b3e96d20476..00000000000 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Main.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.applaunch; - -import cpw.mods.modlauncher.Launcher; -import org.fusesource.jansi.AnsiConsole; -import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants; -import org.spongepowered.plugin.builtin.StandardEnvironment; -import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; -import org.spongepowered.vanilla.applaunch.util.ArgumentList; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public final class Main { - - static { - AnsiConsole.systemInstall(); - } - - private final VanillaPluginPlatform pluginPlatform; - private final Path[] extraPaths; - - public Main(final Path[] extraPaths) { - this.pluginPlatform = AppLaunch.setPluginPlatform(new VanillaPluginPlatform(new StandardEnvironment())); - this.extraPaths = extraPaths; - } - - public static void main(final String[] args) throws Exception { - Main.main(args, new Path[0]); - } - - public static void main(final String[] args, final Path[] extraPaths) throws Exception { - AppCommandLine.configure(args); - new Main(extraPaths).run(); - } - - public void run() throws IOException { - final String implementationVersion = StandardEnvironment.class.getPackage().getImplementationVersion(); - - this.pluginPlatform.setVersion(implementationVersion == null ? "dev" : implementationVersion); - this.pluginPlatform.setBaseDirectory(AppCommandLine.gameDirectory); - - final Path modsDirectory = AppCommandLine.gameDirectory.resolve("mods"); - if (Files.notExists(modsDirectory)) { - Files.createDirectories(modsDirectory); - } - final Path pluginsDirectory = AppCommandLine.gameDirectory.resolve("plugins"); - final List pluginDirectories = new ArrayList<>(); - pluginDirectories.add(modsDirectory); - if (Files.exists(pluginsDirectory)) { - pluginDirectories.add(pluginsDirectory); - } - this.pluginPlatform.setPluginDirectories(pluginDirectories); - this.pluginPlatform.setMetadataFilePath(PluginPlatformConstants.METADATA_FILE_LOCATION); - - // Extra paths that are on the TCL but not the system loader - this.pluginPlatform.getStandardEnvironment().blackboard().getOrCreate( - VanillaPluginPlatform.EXTRA_TRANSFORMABLE_PATHS, - () -> Collections.unmodifiableList(Arrays.asList(this.extraPaths)) - ); - - AppLaunch.logger().info("Transitioning to ModLauncher, please wait..."); - final ArgumentList lst = ArgumentList.from(AppCommandLine.RAW_ARGS); - Launcher.main(lst.getArguments()); - } -} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java index 05562bdd3de..47f153881a7 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java @@ -24,327 +24,33 @@ */ package org.spongepowered.vanilla.applaunch.handler; -import cpw.mods.gross.Java9ClassLoaderUtil; -import cpw.mods.modlauncher.TransformingClassLoader; import cpw.mods.modlauncher.api.ILaunchHandlerService; -import cpw.mods.modlauncher.api.ITransformingClassLoader; -import cpw.mods.modlauncher.api.ITransformingClassLoaderBuilder; +import cpw.mods.modlauncher.api.ServiceRunner; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.plugin.PluginResource; -import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; -import org.spongepowered.plugin.builtin.jvm.locator.ResourceType; -import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.jar.JarFile; -import java.util.jar.Manifest; /** * The common Sponge {@link ILaunchHandlerService launch handler} for development * and production environments. */ public abstract class AbstractVanillaLaunchHandler implements ILaunchHandlerService { - - private static final String JAVA_HOME_PATH = System.getProperty("java.home"); protected final Logger logger = LogManager.getLogger("launch"); - /** - * Classes or packages that mark jar files that should be excluded from the transformation path - */ - protected static final String[] NON_TRANSFORMABLE_PATHS = { - "org/spongepowered/asm/", // Mixin (for obvious reasons) - // because NIO Paths use different normalization than Instrumentation.appendToSystemClassLoaderSearch() - // (NIO uses uppercase URL encoding (ex. %2D), Instrumentation does not (ex. %2d)), this cannot appear in the transformer path at all - // This suppresses a warning from LoggerFactory.findPossibleStaticLoggerBinderPathSet - "org/slf4j/impl/", // slf4j - }; - - /** - * A list of packages to exclude from the {@link TransformingClassLoader transforming class loader}, - * to be registered with {@link ITransformingClassLoader#addTargetPackageFilter(Predicate)}. - *

- * Packages should be scoped as tightly as possible - for example {@code "com.google.common."} is - * preferred over {@code "com.google."}. - *

- * Packages should always include a trailing full stop - for example if {@code "org.neptune"} was - * excluded, classes in {@code "org.neptunepowered"} would also be excluded. The correct usage would - * be to exclude {@code "org.neptune."}. - */ - private static final String[] EXCLUDED_PACKAGES = { - "org.spongepowered.plugin.", - "org.spongepowered.common.applaunch.", - "org.spongepowered.vanilla.applaunch.", - // configurate 4 - "io.leangen.geantyref.", - "org.spongepowered.configurate.", - // terminal console bits - "org.jline.", - "org.fusesource.", - "net.minecrell.terminalconsole.", - "org.slf4j.", - // Maven artifacts -- specifically for versioning - "org.apache.maven.artifact.", - // HotswapAgent - "org.hotswap.agent." - }; - - private static final String[] EXCLUSION_EXCEPTIONS = { - "org.spongepowered.configurate.objectmapping.guice.", - "org.spongepowered.configurate.yaml.", - "org.spongepowered.configurate.gson.", - "org.spongepowered.configurate.jackson.", - "org.spongepowered.configurate.xml.", - }; - - protected boolean isDev() { - return false; - } - @Override - public void configureTransformationClassLoader(final ITransformingClassLoaderBuilder builder) { - // Specifically requested to be available on the launch loader - final VanillaPluginPlatform platform = AppLaunch.pluginPlatform(); - for (final Path path : platform.getStandardEnvironment().blackboard().getOrCreate(VanillaPluginPlatform.EXTRA_TRANSFORMABLE_PATHS, () -> Collections.emptyList())) { - builder.addTransformationPath(path); - } - - // Plus everything else on the system loader - // todo: we might be able to eliminate this at some point, but that causes complications - if (this.isDev()) { - for (final URL url : Java9ClassLoaderUtil.getSystemClassPathURLs()) { - try { - final URI uri = url.toURI(); - if (!this.isTransformable(uri)) { - this.logger.debug("Non-transformable system classpath entry: {}", uri); - continue; - } - - builder.addTransformationPath(Paths.get(uri)); - this.logger.debug("Transformable system classpath entry: {}", uri); - } catch (final URISyntaxException | IOException ex) { - this.logger.error("Failed to add {} to transformation path", url, ex); - } - } - } - - builder.setResourceEnumeratorLocator(this.getResourceLocator()); - builder.setManifestLocator(this.getManifestLocator()); - } - - protected boolean isTransformable(final URI uri) throws URISyntaxException, IOException { - final Path p = Path.of(uri); - - // in Java 8 ONLY, the system classpath contains JVM internals - // let's make sure those don't get transformed - if (p.toAbsolutePath().startsWith(AbstractVanillaLaunchHandler.JAVA_HOME_PATH)) { - return false; - } - - if (!Files.exists(p)) { - return false; - } - - final BasicFileAttributes basicFileAttributes = Files.readAttributes(p, BasicFileAttributes.class); - if (basicFileAttributes.isDirectory()) { - for (final String test : AbstractVanillaLaunchHandler.NON_TRANSFORMABLE_PATHS) { - if (Files.exists(p.resolve(test))) { - return false; - } - } - } else if (basicFileAttributes.isRegularFile()) { - try (final JarFile jf = new JarFile(new File(uri))) { - for (final String test : AbstractVanillaLaunchHandler.NON_TRANSFORMABLE_PATHS) { - if (jf.getEntry(test) != null) { - return false; - } - } - } - } - return true; - } - - @Override - public Callable launchService(final String[] arguments, final ITransformingClassLoader launchClassLoader) { + public ServiceRunner launchService(final String[] arguments, final ModuleLayer gameLayer) { this.logger.info("Transitioning to Sponge launch, please wait..."); - - launchClassLoader.addTargetPackageFilter(klass -> { - outer: for (final String pkg : AbstractVanillaLaunchHandler.EXCLUDED_PACKAGES) { - if (klass.startsWith(pkg)) { - for (final String exception : AbstractVanillaLaunchHandler.EXCLUSION_EXCEPTIONS) { - if (klass.startsWith(exception)) { - break outer; - } - } - return false; - } - } - return true; - }); - AbstractVanillaLaunchHandler.fixPackageExclusions(launchClassLoader); - - return () -> { - this.launchService0(arguments, launchClassLoader); - return null; - }; - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private static void fixPackageExclusions(final ITransformingClassLoader tcl) { - try { - final Field prefixField = tcl.getClass().getDeclaredField("SKIP_PACKAGE_PREFIXES"); - prefixField.setAccessible(true); - ((List) prefixField.get(null)).set(1, "__javax__noplswhy."); - } catch (NoSuchFieldException | IllegalAccessException ex) { - throw new RuntimeException("Failed to fix strange transformer exclusions", ex); - } - } - - protected Function> getResourceLocator() { - return s -> { - // Save unnecessary searches of plugin classes for things that are definitely not plugins - // In this case: MC and fastutil - if (s.startsWith("net/minecraft") || s.startsWith("it/unimi")) { - return Collections.emptyEnumeration(); - } - - final URI asUri; - try { - asUri = new URI(null, null, s, null); - } catch (final URISyntaxException ex) { - this.logger.error("Failed to convert resource path {} to a URI", s, ex); - return Collections.emptyEnumeration(); - } - - return new Enumeration() { - final Iterator> serviceResources = ((VanillaPluginPlatform) AppLaunch.pluginPlatform()).getResources() - .values().iterator(); - Iterator resources; - URL next = this.computeNext(); - - @Override - public boolean hasMoreElements() { - return this.next != null; - } - - @Override - public URL nextElement() { - final URL next = this.next; - if (next == null) { - throw new NoSuchElementException(); - } - this.next = this.computeNext(); - return next; - } - - private URL computeNext() { - while (true) { - if (this.resources != null && !this.resources.hasNext()) { - this.resources = null; - } - if (this.resources == null) { - if (!this.serviceResources.hasNext()) { - return null; - } - this.resources = this.serviceResources.next().iterator(); - } - - if (this.resources.hasNext()) { - final PluginResource resource = this.resources.next(); - if (resource instanceof JVMPluginResource) { - if (((JVMPluginResource) resource).type() != ResourceType.JAR) { - continue; - } - } - - final Optional uri = resource.locateResource(asUri); - if (uri.isPresent()) { - try { - return uri.get().toURL(); - } catch (final MalformedURLException ex) { - throw new RuntimeException(ex); - } - } - } - } - } - }; - }; - } - - private final ConcurrentMap> manifestCache = new ConcurrentHashMap<>(); - private static final Optional UNKNOWN_MANIFEST = Optional.of(new Manifest()); - - private Function> getManifestLocator() { - return connection -> { - if (connection instanceof JarURLConnection) { - final URL jarFileUrl = ((JarURLConnection) connection).getJarFileURL(); - final Optional manifest = this.manifestCache.computeIfAbsent(jarFileUrl, key -> { - for (final Set resources : ((VanillaPluginPlatform) AppLaunch.pluginPlatform()).getResources().values()) { - for (final PluginResource resource : resources) { - if (resource instanceof JVMPluginResource) { - final JVMPluginResource jvmResource = (JVMPluginResource) resource; - try { - if (jvmResource.type() == ResourceType.JAR && ((JVMPluginResource) resource).path().toAbsolutePath().normalize().equals(Paths.get(key.toURI()).toAbsolutePath().normalize())) { - return jvmResource.manifest(); - } - } catch (final URISyntaxException ex) { - this.logger.error("Failed to load manifest from jar {}: ", key, ex); - } - } - } - } - return AbstractVanillaLaunchHandler.UNKNOWN_MANIFEST; - }); - - try { - if (manifest == AbstractVanillaLaunchHandler.UNKNOWN_MANIFEST) { - return Optional.ofNullable(((JarURLConnection) connection).getManifest()); - } else { - return manifest; - } - } catch (final IOException ex) { - this.logger.error("Failed to load manifest from jar {}: ", jarFileUrl, ex); - } - } - return Optional.empty(); - }; + return () -> this.launchService0(arguments, gameLayer); } /** * Launch the service (Minecraft). *

* Take care to ONLY load classes on the provided - * {@link ClassLoader class loader}, which can be retrieved with {@link ITransformingClassLoader#getInstance()}. + * {@link ModuleLayer layer}. * * @param arguments The arguments to launch the service with - * @param launchClassLoader The transforming class loader to load classes with + * @param gameLayer The game layer to load classes with * @throws Exception This can be any exception that occurs during the launch process */ - protected abstract void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception; + protected abstract void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception; } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java index 69ee9f6288d..56edea4930b 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java @@ -24,7 +24,6 @@ */ package org.spongepowered.vanilla.applaunch.handler.dev; -import cpw.mods.modlauncher.api.ITransformingClassLoader; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.vanilla.applaunch.AppLaunchTargets; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; @@ -32,19 +31,14 @@ public final class ClientDevLaunchHandler extends AbstractVanillaLaunchHandler { - @Override - protected boolean isDev() { - return true; - } - @Override public String name() { return AppLaunchTargets.CLIENT_DEVELOPMENT.getLaunchTarget(); } @Override - protected void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception { - Class.forName("org.spongepowered.vanilla.launch.ClientLaunch", true, launchClassLoader.getInstance()) + protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { + Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.ClientLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.TRUE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java index 1b54be0b2a0..869adee82cc 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java @@ -24,7 +24,6 @@ */ package org.spongepowered.vanilla.applaunch.handler.dev; -import cpw.mods.modlauncher.api.ITransformingClassLoader; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.vanilla.applaunch.AppLaunchTargets; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; @@ -32,19 +31,14 @@ public final class ServerDevLaunchHandler extends AbstractVanillaLaunchHandler { - @Override - protected boolean isDev() { - return true; - } - @Override public String name() { return AppLaunchTargets.SERVER_DEVELOPMENT.getLaunchTarget(); } @Override - protected void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception { - Class.forName("org.spongepowered.vanilla.launch.DedicatedServerLaunch", true, launchClassLoader.getInstance()) + protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { + Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.DedicatedServerLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.TRUE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java index 8476ce4557d..cabe378a765 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java @@ -24,7 +24,6 @@ */ package org.spongepowered.vanilla.applaunch.handler.prod; -import cpw.mods.modlauncher.api.ITransformingClassLoader; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.vanilla.applaunch.AppLaunchTargets; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; @@ -32,19 +31,14 @@ public final class ServerProdLaunchHandler extends AbstractVanillaLaunchHandler { - @Override - protected boolean isDev() { - return false; - } - @Override public String name() { return AppLaunchTargets.SERVER_PRODUCTION.getLaunchTarget(); } @Override - protected void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception { - Class.forName("org.spongepowered.vanilla.launch.DedicatedServerLaunch", true, launchClassLoader.getInstance()) + protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { + Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.DedicatedServerLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.FALSE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java index fd4b9957d7b..f4f08797482 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java @@ -24,7 +24,6 @@ */ package org.spongepowered.vanilla.applaunch.handler.test; -import cpw.mods.modlauncher.api.ITransformingClassLoader; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.vanilla.applaunch.AppLaunchTargets; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; @@ -38,9 +37,9 @@ public String name() { } @Override - protected void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception { - Class.forName("org.spongepowered.vanilla.launch.IntegrationTestLaunch", true, launchClassLoader.getInstance()) - .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) - .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.FALSE, arguments); + protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { + Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.IntegrationTestLaunch") + .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) + .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.FALSE, arguments); } } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java index 0f5367bca37..b410e61daaa 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java @@ -24,7 +24,6 @@ */ package org.spongepowered.vanilla.applaunch.handler.test; -import cpw.mods.modlauncher.api.ITransformingClassLoader; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.vanilla.applaunch.AppLaunchTargets; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; @@ -38,9 +37,9 @@ public String name() { } @Override - protected void launchService0(final String[] arguments, final ITransformingClassLoader launchClassLoader) throws Exception { - Class.forName("org.spongepowered.vanilla.launch.IntegrationTestLaunch", true, launchClassLoader.getInstance()) - .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) - .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.TRUE, arguments); + protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { + Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.IntegrationTestLaunch") + .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) + .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.TRUE, arguments); } } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java index 14c233cea90..a021fe6c1a2 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java @@ -25,23 +25,29 @@ package org.spongepowered.vanilla.applaunch.plugin; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import cpw.mods.modlauncher.api.IEnvironment; -import cpw.mods.modlauncher.api.ITransformationService; -import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.jarhandling.SecureJar; +import cpw.mods.modlauncher.Launcher; +import cpw.mods.modlauncher.api.*; import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; +import org.fusesource.jansi.AnsiConsole; import org.spongepowered.asm.launch.MixinLaunchPluginLegacy; import org.spongepowered.common.applaunch.AppLaunch; +import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants; import org.spongepowered.plugin.PluginResource; +import org.spongepowered.plugin.builtin.StandardEnvironment; import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; import org.spongepowered.transformers.modlauncher.AccessWidenerTransformationService; import org.spongepowered.transformers.modlauncher.SuperclassChanger; -import org.spongepowered.vanilla.installer.Constants; +import org.spongepowered.vanilla.applaunch.Constants; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -51,7 +57,7 @@ public final class VanillaPlatformService implements ITransformationService { private static final String NAME = "vanilla_platform"; - private static final VanillaPluginPlatform pluginPlatform = AppLaunch.pluginPlatform(); + private @MonotonicNonNull VanillaPluginPlatform pluginPlatform; @Override public @NonNull String name() { @@ -60,25 +66,20 @@ public final class VanillaPlatformService implements ITransformationService { @Override public void initialize(final IEnvironment environment) { - VanillaPlatformService.pluginPlatform.initialize(); + this.pluginPlatform.initialize(); } @Override - public void beginScanning(final IEnvironment environment) { - //NOOP - } - - @Override - public List> runScan(final IEnvironment environment) { - VanillaPlatformService.pluginPlatform.locatePluginResources(); - VanillaPlatformService.pluginPlatform.createPluginCandidates(); + public List beginScanning(final IEnvironment environment) { + this.pluginPlatform.locatePluginResources(); + this.pluginPlatform.createPluginCandidates(); final AccessWidenerTransformationService accessWidener = environment.getProperty(AccessWidenerTransformationService.INSTANCE.get()).orElse(null); final SuperclassChanger superclassChanger = environment.getProperty(SuperclassChanger.INSTANCE.get()).orElse(null); final ILaunchPluginService mixin = environment.findLaunchPlugin(MixinLaunchPluginLegacy.NAME).orElse(null); - final List> launchResources = new ArrayList<>(); + final List gameResources = new ArrayList<>(); - for (final Map.Entry> resourcesEntry : VanillaPlatformService.pluginPlatform.getResources().entrySet()) { + for (final Map.Entry> resourcesEntry : this.pluginPlatform.getResources().entrySet()) { final Set resources = resourcesEntry.getValue(); for (final PluginResource resource : resources) { @@ -86,7 +87,7 @@ public List> runScan(final IEnvironment environment) { if ((accessWidener != null || mixin != null || superclassChanger != null) && resource instanceof JVMPluginResource) { if (mixin != null) { // Offer jar to the Mixin service - mixin.offerResource(((JVMPluginResource) resource).path(), ((JVMPluginResource) resource).path().getFileName().toString()); + mixin.offerResource(resource.path(), resource.path().getFileName().toString()); } // Offer jar to the AW service @@ -100,14 +101,14 @@ public List> runScan(final IEnvironment environment) { } try { accessWidener.offerResource( - ((JVMPluginResource) resource).fileSystem().getPath(atFile).toUri().toURL(), - atFile + ((JVMPluginResource) resource).fileSystem().getPath(atFile).toUri().toURL(), + atFile ); } catch (final MalformedURLException ex) { - VanillaPlatformService.pluginPlatform.logger().warn( - "Failed to read declared access widener {}, from {}:", - atFile, - resource.locator() + this.pluginPlatform.logger().warn( + "Failed to read declared access widener {}, from {}:", + atFile, + resource.locator() ); } } @@ -115,9 +116,9 @@ public List> runScan(final IEnvironment environment) { } if (mixin != null && manifest.getMainAttributes().getValue(org.spongepowered.asm.util.Constants.ManifestAttributes.MIXINCONFIGS) != null) { if (!VanillaPlatformService.isSponge((JVMPluginResource) resource)) { - VanillaPlatformService.pluginPlatform.logger().warn( - "Plugin from {} uses Mixins to modify the Minecraft Server. If something breaks, remove it before reporting the " - + "problem to Sponge!", ((JVMPluginResource) resource).path() + this.pluginPlatform.logger().warn( + "Plugin from {} uses Mixins to modify the Minecraft Server. If something breaks, remove it before reporting the " + + "problem to Sponge!", resource.path() ); } } @@ -130,14 +131,14 @@ public List> runScan(final IEnvironment environment) { } try { superclassChanger.offerResource( - ((JVMPluginResource) resource).fileSystem().getPath(superclassChangeFile).toUri().toURL(), - superclassChangeFile + ((JVMPluginResource) resource).fileSystem().getPath(superclassChangeFile).toUri().toURL(), + superclassChangeFile ); } catch (final MalformedURLException ex) { - VanillaPlatformService.pluginPlatform.logger().warn( - "Failed to read declared superclass changer {}, from {}:", - superclassChangeFile, - resource.locator() + this.pluginPlatform.logger().warn( + "Failed to read declared superclass changer {}, from {}:", + superclassChangeFile, + resource.locator() ); } } @@ -145,14 +146,13 @@ public List> runScan(final IEnvironment environment) { } }); - final Map.Entry entry = Maps.immutableEntry(((JVMPluginResource) resource).path().getFileName().toString(), - ((JVMPluginResource) resource).path()); - launchResources.add(entry); + // TODO custom jar metadata ? + gameResources.add(SecureJar.from(resource.path())); } } } - return launchResources; + return List.of(new Resource(IModuleLayerManager.Layer.GAME, gameResources)); } private static boolean isSponge(final JVMPluginResource resource) { @@ -165,17 +165,45 @@ private static boolean isSponge(final JVMPluginResource resource) { @Override public void onLoad(final IEnvironment env, final Set otherServices) { - final VanillaPluginPlatform pluginPlatform = VanillaPlatformService.pluginPlatform; - pluginPlatform.logger().info("SpongePowered PLUGIN Subsystem Version={} Source={}", - pluginPlatform.version(), this.getCodeSource()); - - pluginPlatform.discoverLocatorServices(); - pluginPlatform.getLocatorServices().forEach((k, v) -> pluginPlatform.logger().info("Plugin resource locator '{}' found.", k)); - pluginPlatform.discoverLanguageServices(); - pluginPlatform.getLanguageServices().forEach((k, v) -> pluginPlatform.logger().info("Plugin language loader '{}' found.", k)); + AnsiConsole.systemInstall(); + + this.pluginPlatform = new VanillaPluginPlatform(new StandardEnvironment()); + AppLaunch.setPluginPlatform(this.pluginPlatform); + + final String implementationVersion = StandardEnvironment.class.getPackage().getImplementationVersion(); + final Path baseDirectory = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".")); + + this.pluginPlatform.setVersion(implementationVersion == null ? "dev" : implementationVersion); + this.pluginPlatform.setBaseDirectory(baseDirectory); + + this.pluginPlatform.logger().info("SpongePowered PLUGIN Subsystem Version={} Source={}", + this.pluginPlatform.version(), this.getCodeSource()); + + final Path modsDirectory = baseDirectory.resolve("mods"); + if (Files.notExists(modsDirectory)) { + try { + Files.createDirectories(modsDirectory); + } catch (IOException ignored) {} + } + + final Path pluginsDirectory = baseDirectory.resolve("plugins"); + final List pluginDirectories = new ArrayList<>(); + pluginDirectories.add(modsDirectory); + if (Files.exists(pluginsDirectory)) { + pluginDirectories.add(pluginsDirectory); + } + + this.pluginPlatform.setPluginDirectories(pluginDirectories); + this.pluginPlatform.setMetadataFilePath(PluginPlatformConstants.METADATA_FILE_LOCATION); + + this.pluginPlatform.discoverLocatorServices(); + this.pluginPlatform.getLocatorServices().forEach((k, v) -> this.pluginPlatform.logger().info("Plugin resource locator '{}' found.", k)); + this.pluginPlatform.discoverLanguageServices(); + this.pluginPlatform.getLanguageServices().forEach((k, v) -> this.pluginPlatform.logger().info("Plugin language loader '{}' found.", k)); } @Override + @SuppressWarnings("rawtypes") public @NonNull List transformers() { return ImmutableList.of(); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index d35fa3778ab..5cb21f752f4 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -30,7 +30,6 @@ import org.spongepowered.plugin.PluginLanguageService; import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.PluginResourceLocatorService; -import org.spongepowered.plugin.blackboard.Key; import org.spongepowered.plugin.blackboard.Keys; import org.spongepowered.plugin.builtin.StandardEnvironment; import org.spongepowered.plugin.builtin.jvm.JVMKeys; @@ -49,8 +48,6 @@ public final class VanillaPluginPlatform implements PluginPlatform { - public static final Key> EXTRA_TRANSFORMABLE_PATHS = Key.of("spongevanilla:transformable_paths", List.class); - private final StandardEnvironment standardEnvironment; private final Map> locatorServices; private final Map> languageServices; diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/util/MixinLoggerInjector.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/util/MixinLoggerInjector.java index 9ce261dbf17..fcaa7c28c71 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/util/MixinLoggerInjector.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/util/MixinLoggerInjector.java @@ -30,7 +30,6 @@ import org.apache.logging.log4j.core.filter.CompositeFilter; import org.apache.logging.log4j.core.filter.DenyAllFilter; import org.apache.logging.log4j.core.filter.RegexFilter; -import org.intellij.lang.annotations.Language; import org.spongepowered.asm.mixin.MixinEnvironment; import java.util.Queue; @@ -45,7 +44,7 @@ public final class MixinLoggerInjector { private MixinLoggerInjector() { } - private static RegexFilter pattern(@Language("RegExp") final String pattern) { + private static RegexFilter pattern(final String pattern) { try { return RegexFilter.createFilter(pattern, new String[0], false, Filter.Result.ACCEPT, Filter.Result.NEUTRAL); } catch (final IllegalAccessException ex) { diff --git a/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java b/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java index 2da830df3cd..0cba3447553 100644 --- a/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java +++ b/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java @@ -28,8 +28,6 @@ public final class Constants { - public static final int ASM_VERSION = Opcodes.ASM9; - public static final class Libraries { public static final String MINECRAFT_VERSION_TARGET = "{{ minecraftVersion }}"; @@ -42,11 +40,4 @@ public static final class Libraries { public static final String SPONGE_NEXUS_DOWNLOAD_URL = "https://repo.spongepowered.org/service/rest/v1/search/assets?md5=%s&maven" + ".groupId=%s&maven.artifactId=%s&maven.baseVersion=%s&maven.extension=jar"; } - - public static final class ManifestAttributes { - - public static final String ACCESS_WIDENER = "Access-Widener"; - public static final String LAUNCH_TARGET = "Launch-Target"; - public static final String SUPERCLASS_CHANGE = "Superclass-Transformer"; - } } diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java index 7fe229109e1..59b62592420 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java @@ -25,7 +25,6 @@ package org.spongepowered.vanilla.installer; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.mlpatcher.AsmFixerAgent; import org.tinylog.Logger; import java.io.File; @@ -57,12 +56,10 @@ public class Agent { public static void premain(final String agentArgs, final Instrumentation instrumentation) { Agent.instrumentation = instrumentation; - AsmFixerAgent.premain("", instrumentation); } public static void agentmain(final String agentArgs, final Instrumentation instrumentation) { Agent.instrumentation = instrumentation; - AsmFixerAgent.agentmain("", instrumentation); } static void addJarToClasspath(final Path jar) { From b151dfc3dfc9206d7d93c5519e85e4d270b59d0f Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Mon, 26 Aug 2024 23:44:48 +0200 Subject: [PATCH 198/226] Boot vanilla dev environment on modern ModLauncher --- SpongeAPI | 2 +- .../locator/EnvironmentPluginLocator.java | 2 +- .../launch/plugin/ForgePluginContainer.java | 4 +- vanilla/build.gradle.kts | 128 ++++++----- ...aunchTargets.java => AppLaunchTarget.java} | 32 +-- .../handler/AbstractVanillaLaunchHandler.java | 16 +- .../handler/dev/ClientDevLaunchHandler.java | 10 +- .../handler/dev/ServerDevLaunchHandler.java | 10 +- .../handler/prod/ServerProdLaunchHandler.java | 10 +- .../handler/test/ClientTestLaunchHandler.java | 10 +- .../handler/test/ServerTestLaunchHandler.java | 10 +- .../plugin/JavaPluginLanguageService.java | 70 ++++++ .../applaunch/plugin/ResourceType.java} | 37 ++- .../plugin/VanillaPlatformService.java | 214 +++++++++--------- .../plugin/VanillaPluginPlatform.java | 35 +-- ...vironmentPluginResourceLocatorService.java | 66 ++++++ .../plugin/locator/PluginJarMetadata.java | 102 +++++++++ .../locator/SecureJarPluginResource.java | 118 ++++++++++ .../META-INF/minecraft_sponge_plugins.json | 24 ++ ...odlauncher.serviceapi.ILaunchPluginService | 0 ...spongepowered.plugin.PluginLanguageService | 2 +- ...owered.plugin.PluginResourceLocatorService | 3 +- .../vanilla/launch/VanillaLaunch.java | 73 +----- .../launch/event/VanillaEventManager.java | 4 - .../launch/plugin/JavaPluginLoader.java | 9 +- .../plugin/VanillaDummyPluginContainer.java | 79 +------ .../plugin/VanillaJavaPluginContainer.java | 29 +-- .../launch/plugin/VanillaPluginManager.java | 10 - .../META-INF/sponge_plugins.json | 48 ++-- .../server/packs/PluginPackResources.java | 17 +- .../server/packs/PluginRepositorySource.java | 18 +- 31 files changed, 700 insertions(+), 492 deletions(-) rename vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/{AppLaunchTargets.java => AppLaunchTarget.java} (68%) create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java rename vanilla/src/{launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLanguageService.java => applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ResourceType.java} (53%) create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java create mode 100644 vanilla/src/applaunch/resource-templates/META-INF/minecraft_sponge_plugins.json delete mode 100644 vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService diff --git a/SpongeAPI b/SpongeAPI index 42dc372340a..9c29c74cc4b 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 42dc372340aa68a7ea28a5ffa90b68c25af09661 +Subproject commit 9c29c74cc4bf767cf253c287969620185604a7ce diff --git a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/locator/EnvironmentPluginLocator.java b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/locator/EnvironmentPluginLocator.java index 4aa59a6cd64..a0c3b100247 100644 --- a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/locator/EnvironmentPluginLocator.java +++ b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/locator/EnvironmentPluginLocator.java @@ -40,7 +40,7 @@ public final class EnvironmentPluginLocator extends AbstractModProvider implemen @Override public List scanMods() { final List modFiles = new ArrayList<>(); - for (final Path[] paths : getPluginsPaths()) { + for (final Path[] paths : EnvironmentPluginLocator.getPluginsPaths()) { modFiles.add(new ModFileOrException(ModFileParsers.newPluginInstance(this, paths), null)); } return modFiles; diff --git a/forge/src/launch/java/org/spongepowered/forge/launch/plugin/ForgePluginContainer.java b/forge/src/launch/java/org/spongepowered/forge/launch/plugin/ForgePluginContainer.java index 6fceac8462a..c71ed3745b5 100644 --- a/forge/src/launch/java/org/spongepowered/forge/launch/plugin/ForgePluginContainer.java +++ b/forge/src/launch/java/org/spongepowered/forge/launch/plugin/ForgePluginContainer.java @@ -72,11 +72,11 @@ public Logger logger() { } @Override - public Optional locateResource(URI relative) { + public Optional locateResource(String relative) { Objects.requireNonNull(relative, "relative"); final ClassLoader classLoader = this.modContainer.getMod().getClass().getClassLoader(); - final URL resolved = classLoader.getResource(relative.getPath()); + final URL resolved = classLoader.getResource(relative); try { if (resolved == null) { return Optional.empty(); diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index ddf19e96537..bb7f19df922 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -22,10 +22,11 @@ version = spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVer // SpongeVanilla libraries val installerLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeInstallerLibraries") -val bootstrapLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootstrapModules") // JVM initial classpath -val launcherLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeLauncherLibraries") // ModLauncher boot -val serviceLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeServiceLibraries") -val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameLibraries") +val initLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeInitLibraries") // JVM initial classpath +val bootLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootLibraries") +val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameLibraries") { + extendsFrom(configurations.minecraft.get()) +} val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameManagedLibraries") @@ -35,21 +36,12 @@ val runTaskOnlyConfig: NamedDomainObjectProvider = configurations // ModLauncher layers val bootLayerConfig: NamedDomainObjectProvider = configurations.register("bootLayer") { - extendsFrom(bootstrapLibrariesConfig.get()) - extendsFrom(launcherLibrariesConfig.get()) -} -val serviceLayerConfig: NamedDomainObjectProvider = configurations.register("serviceLayer") { - extendsFrom(bootLayerConfig.get()) - extendsFrom(serviceLibrariesConfig.get()) -} -val langLayerConfig: NamedDomainObjectProvider = configurations.register("langLayer") { - extendsFrom(bootLayerConfig.get()) + extendsFrom(initLibrariesConfig.get()) + extendsFrom(bootLibrariesConfig.get()) } val gameLayerConfig: NamedDomainObjectProvider = configurations.register("gameLayer") { - extendsFrom(serviceLayerConfig.get()) - extendsFrom(langLayerConfig.get()) + extendsFrom(bootLayerConfig.get()) extendsFrom(gameLibrariesConfig.get()) - extendsFrom(configurations.minecraft.get()) } // SpongeCommon source sets @@ -113,7 +105,7 @@ val vanillaMixins by sourceSets.register("mixins") { } val vanillaLang by sourceSets.register("lang") { configurations.named(implementationConfigurationName) { - extendsFrom(langLayerConfig.get()) + extendsFrom(bootLayerConfig.get()) } } val vanillaAppLaunch by sourceSets.register("applaunch") { @@ -122,7 +114,7 @@ val vanillaAppLaunch by sourceSets.register("applaunch") { spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaLaunch, project, vanillaLaunch.implementationConfigurationName) configurations.named(implementationConfigurationName) { - extendsFrom(serviceLayerConfig.get()) + extendsFrom(bootLayerConfig.get()) } } @@ -189,13 +181,28 @@ minecraft { ) // Merge applaunch sourcesets in a single module - val applaunchOutputs = arrayOf(applaunch.get().output, vanillaAppLaunch.output) - val applaunchDirs: MutableList = mutableListOf() - applaunchOutputs.forEach { - applaunchDirs.add(it.resourcesDir!!) - applaunchDirs.addAll(it.classesDirs) + val applaunchOutputs = files(applaunch.get().output, vanillaAppLaunch.output) + dependsOn(applaunchOutputs) + environment("MOD_CLASSES", applaunchOutputs.joinToString(";") { "applaunch%%$it" }) + + // Configure GAME and LANG resources + val resources = mutableListOf() + resources.addAll(gameManagedLibrariesConfig.get().files.map { files(it) }) + + resources.add(files( + main.get().output, vanillaMain.output, + mixins.get().output, vanillaMixins.output, + accessors.get().output, vanillaAccessors.output, + launch.get().output, vanillaLaunch.output, + gameShadedLibrariesConfig.get() + )) + + testPluginsProject?.also { + //resources.add(it.sourceSets.getByName("main").output) } - environment("MOD_CLASSES", applaunchDirs.joinToString(";") { "applaunch%%$it" }) + + dependsOn(resources) + environment("SPONGE_PLUGINS", resources.joinToString(";") { it.joinToString("&") }) } } } @@ -249,56 +256,59 @@ dependencies { isTransitive = false } - val bootstrap = bootstrapLibrariesConfig.name - bootstrap(libs.bootstrap) - bootstrap(libs.securemodules) - bootstrap(libs.asm.commons) - bootstrap(libs.asm.util) + val init = initLibrariesConfig.name + init(libs.bootstrap) + init(libs.securemodules) + init(libs.asm.commons) + init(libs.asm.util) - val launcher = launcherLibrariesConfig.name - launcher(libs.modlauncher) { + val boot = bootLibrariesConfig.name + boot(libs.modlauncher) { exclude(group = "org.apache.logging.log4j") } - launcher(apiLibs.pluginSpi) { + boot(apiLibs.pluginSpi) { exclude(group = "org.checkerframework", module = "checker-qual") - exclude(group = "com.google.code.gson", module = "gson") + // exclude(group = "com.google.code.gson", module = "gson") exclude(group = "org.apache.logging.log4j", module = "log4j-api") - exclude(group = "org.apache.commons", module = "commons-lang3") + // exclude(group = "org.apache.commons", module = "commons-lang3") } - launcher(libs.lmaxDisruptor) - launcher(apiLibs.checkerQual) + boot(libs.lmaxDisruptor) + boot(apiLibs.checkerQual) - launcher(libs.terminalConsoleAppender) { + boot(libs.terminalConsoleAppender) { exclude(group = "org.jline", module = "jline-reader") exclude(group = "org.apache.logging.log4j", module = "log4j-core") } - launcher(libs.jline.terminal) - launcher(libs.jline.reader) - launcher(libs.jline.terminalJansi) + boot(libs.jline.terminal) + boot(libs.jline.reader) + boot(libs.jline.terminalJansi) - launcher(libs.log4j.jpl) - launcher(libs.log4j.api) - launcher(libs.log4j.core) - launcher(libs.log4j.slf4j2) + boot(libs.log4j.jpl) + boot(libs.log4j.api) + boot(libs.log4j.core) + boot(libs.log4j.slf4j2) - launcher(platform(apiLibs.configurate.bom)) - launcher(apiLibs.configurate.core) { + boot(platform(apiLibs.configurate.bom)) + boot(apiLibs.configurate.core) { exclude(group = "org.checkerframework", module = "checker-qual") } - launcher(apiLibs.configurate.hocon) { + boot(apiLibs.configurate.hocon) { exclude(group = "org.spongepowered", module = "configurate-core") exclude(group = "org.checkerframework", module = "checker-qual") } - launcher(libs.mixin) - launcher(libs.asm.tree) - launcher(libs.guava) { + boot(libs.mixin) + boot(libs.asm.tree) + boot(libs.guava) { exclude(group = "com.google.errorprone", module = "error_prone_annotations") exclude(group = "org.checkerframework", module = "checker-qual") } - val service = serviceLibrariesConfig.name - service(project(transformersProject.path)) + boot("com.mojang:authlib:6.0.54") { + exclude(group = "com.google.guava", module = "guava") + } + + boot(project(transformersProject.path)) val game = gameLibrariesConfig.name game("org.spongepowered:spongeapi:$apiVersion") @@ -318,7 +328,12 @@ dependencies { exclude(group = "org.checkerframework", module = "checker-qual") } - // TODO list shaded / managed libraries + val gameShadedLibraries = gameShadedLibrariesConfig.name + gameShadedLibraries("org.spongepowered:spongeapi:$apiVersion") { isTransitive = false } + + afterEvaluate { + spongeImpl.copyModulesExcludingProvided(gameLibrariesConfig.get(), bootLayerConfig.get(), gameManagedLibrariesConfig.get()) + } val runTaskOnly = runTaskOnlyConfig.name // Allow boot layer manipulation such as merging applaunch sourcesets @@ -339,6 +354,11 @@ val vanillaManifest = java.manifest { System.getenv()["GIT_BRANCH"]?.apply { attributes("Git-Branch" to this) } } +vanillaAppLaunch.apply { + blossom.resources { + property("minecraftVersion", minecraftVersion) + } +} vanillaLaunch.apply { blossom.resources { property("apiVersion", apiVersion) @@ -402,7 +422,7 @@ tasks { val emitDependencies by registering(org.spongepowered.gradle.impl.OutputDependenciesToJson::class) { group = "sponge" - this.dependencies("bootstrap", launcherLibrariesConfig) + this.dependencies("bootstrap", bootLibrariesConfig) this.dependencies("main", gameManagedLibrariesConfig) this.excludedDependencies(gameShadedLibrariesConfig) diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTargets.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTarget.java similarity index 68% rename from vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTargets.java rename to vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTarget.java index 8cf0b25ee40..22f22fd4f0d 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTargets.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/AppLaunchTarget.java @@ -24,7 +24,7 @@ */ package org.spongepowered.vanilla.applaunch; -public enum AppLaunchTargets { +public enum AppLaunchTarget { CLIENT_DEVELOPMENT("sponge_client_dev"), CLIENT_PRODUCTION("sponge_client_prod"), SERVER_DEVELOPMENT("sponge_server_dev"), @@ -34,7 +34,7 @@ public enum AppLaunchTargets { private final String launchTarget; - AppLaunchTargets(final String launchTarget) { + AppLaunchTarget(final String launchTarget) { this.launchTarget = launchTarget; } @@ -42,23 +42,15 @@ public String getLaunchTarget() { return this.launchTarget; } - public static AppLaunchTargets from(final String launchTarget) { - - switch (launchTarget) { - case "sponge_client_dev": - return AppLaunchTargets.CLIENT_DEVELOPMENT; - case "sponge_client_prod": - return AppLaunchTargets.CLIENT_PRODUCTION; - case "sponge_server_dev": - return AppLaunchTargets.SERVER_DEVELOPMENT; - case "sponge_server_prod": - return AppLaunchTargets.SERVER_PRODUCTION; - case "sponge_client_it": - return AppLaunchTargets.CLIENT_INTEGRATION_TEST; - case "sponge_server_it": - return AppLaunchTargets.SERVER_INTEGRATION_TEST; - } - - return null; + public static AppLaunchTarget from(final String launchTarget) { + return switch (launchTarget) { + case "sponge_client_dev" -> AppLaunchTarget.CLIENT_DEVELOPMENT; + case "sponge_client_prod" -> AppLaunchTarget.CLIENT_PRODUCTION; + case "sponge_server_dev" -> AppLaunchTarget.SERVER_DEVELOPMENT; + case "sponge_server_prod" -> AppLaunchTarget.SERVER_PRODUCTION; + case "sponge_client_it" -> AppLaunchTarget.CLIENT_INTEGRATION_TEST; + case "sponge_server_it" -> AppLaunchTarget.SERVER_INTEGRATION_TEST; + default -> null; + }; } } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java index 47f153881a7..e830a6ddf6e 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java @@ -28,6 +28,7 @@ import cpw.mods.modlauncher.api.ServiceRunner; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; /** * The common Sponge {@link ILaunchHandlerService launch handler} for development @@ -36,21 +37,28 @@ public abstract class AbstractVanillaLaunchHandler implements ILaunchHandlerService { protected final Logger logger = LogManager.getLogger("launch"); + @Override + public String name() { + return this.target().getLaunchTarget(); + } + @Override public ServiceRunner launchService(final String[] arguments, final ModuleLayer gameLayer) { this.logger.info("Transitioning to Sponge launch, please wait..."); - return () -> this.launchService0(arguments, gameLayer); + return () -> this.launchSponge(gameLayer.findModule("spongevanilla").orElseThrow(), arguments); } + public abstract AppLaunchTarget target(); + /** * Launch the service (Minecraft). *

* Take care to ONLY load classes on the provided - * {@link ModuleLayer layer}. + * {@link Module module}. * + * @param module The sponge module to load classes with * @param arguments The arguments to launch the service with - * @param gameLayer The game layer to load classes with * @throws Exception This can be any exception that occurs during the launch process */ - protected abstract void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception; + protected abstract void launchSponge(final Module module, final String[] arguments) throws Exception; } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java index 56edea4930b..d8a8ceecd91 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ClientDevLaunchHandler.java @@ -25,20 +25,20 @@ package org.spongepowered.vanilla.applaunch.handler.dev; import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.vanilla.applaunch.AppLaunchTargets; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; public final class ClientDevLaunchHandler extends AbstractVanillaLaunchHandler { @Override - public String name() { - return AppLaunchTargets.CLIENT_DEVELOPMENT.getLaunchTarget(); + public AppLaunchTarget target() { + return AppLaunchTarget.CLIENT_DEVELOPMENT; } @Override - protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { - Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.ClientLaunch") + protected void launchSponge(final Module module, final String[] arguments) throws Exception { + Class.forName(module, "org.spongepowered.vanilla.launch.ClientLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.TRUE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java index 869adee82cc..c2b5e72cd3b 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/dev/ServerDevLaunchHandler.java @@ -25,20 +25,20 @@ package org.spongepowered.vanilla.applaunch.handler.dev; import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.vanilla.applaunch.AppLaunchTargets; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; public final class ServerDevLaunchHandler extends AbstractVanillaLaunchHandler { @Override - public String name() { - return AppLaunchTargets.SERVER_DEVELOPMENT.getLaunchTarget(); + public AppLaunchTarget target() { + return AppLaunchTarget.SERVER_DEVELOPMENT; } @Override - protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { - Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.DedicatedServerLaunch") + protected void launchSponge(final Module module, final String[] arguments) throws Exception { + Class.forName(module, "org.spongepowered.vanilla.launch.DedicatedServerLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.TRUE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java index cabe378a765..f326f93b4d6 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/prod/ServerProdLaunchHandler.java @@ -25,20 +25,20 @@ package org.spongepowered.vanilla.applaunch.handler.prod; import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.vanilla.applaunch.AppLaunchTargets; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; public final class ServerProdLaunchHandler extends AbstractVanillaLaunchHandler { @Override - public String name() { - return AppLaunchTargets.SERVER_PRODUCTION.getLaunchTarget(); + public AppLaunchTarget target() { + return AppLaunchTarget.SERVER_PRODUCTION; } @Override - protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { - Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.DedicatedServerLaunch") + protected void launchSponge(final Module module, final String[] arguments) throws Exception { + Class.forName(module, "org.spongepowered.vanilla.launch.DedicatedServerLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), Boolean.FALSE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java index f4f08797482..c06d849bf3d 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ClientTestLaunchHandler.java @@ -25,20 +25,20 @@ package org.spongepowered.vanilla.applaunch.handler.test; import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.vanilla.applaunch.AppLaunchTargets; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; public class ClientTestLaunchHandler extends AbstractVanillaLaunchHandler { @Override - public String name() { - return AppLaunchTargets.CLIENT_INTEGRATION_TEST.getLaunchTarget(); + public AppLaunchTarget target() { + return AppLaunchTarget.CLIENT_INTEGRATION_TEST; } @Override - protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { - Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.IntegrationTestLaunch") + protected void launchSponge(final Module module, final String[] arguments) throws Exception { + Class.forName(module, "org.spongepowered.vanilla.launch.IntegrationTestLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.FALSE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java index b410e61daaa..3a1d4b9a4ef 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/test/ServerTestLaunchHandler.java @@ -25,20 +25,20 @@ package org.spongepowered.vanilla.applaunch.handler.test; import org.spongepowered.common.applaunch.AppLaunch; -import org.spongepowered.vanilla.applaunch.AppLaunchTargets; +import org.spongepowered.vanilla.applaunch.AppLaunchTarget; import org.spongepowered.vanilla.applaunch.handler.AbstractVanillaLaunchHandler; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; public class ServerTestLaunchHandler extends AbstractVanillaLaunchHandler { @Override - public String name() { - return AppLaunchTargets.SERVER_INTEGRATION_TEST.getLaunchTarget(); + public AppLaunchTarget target() { + return AppLaunchTarget.SERVER_INTEGRATION_TEST; } @Override - protected void launchService0(final String[] arguments, final ModuleLayer gameLayer) throws Exception { - Class.forName(gameLayer.findModule("sponge").orElseThrow(), "org.spongepowered.vanilla.launch.IntegrationTestLaunch") + protected void launchSponge(final Module module, final String[] arguments) throws Exception { + Class.forName(module, "org.spongepowered.vanilla.launch.IntegrationTestLaunch") .getMethod("launch", VanillaPluginPlatform.class, Boolean.class, String[].class) .invoke(null, AppLaunch.pluginPlatform(), /* isServer = */ Boolean.TRUE, arguments); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java new file mode 100644 index 00000000000..6b04efffe4f --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java @@ -0,0 +1,70 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin; + +import org.spongepowered.plugin.Environment; +import org.spongepowered.plugin.PluginCandidate; +import org.spongepowered.plugin.PluginResource; +import org.spongepowered.plugin.builtin.StandardPluginCandidate; +import org.spongepowered.plugin.builtin.StandardPluginLanguageService; +import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; +import org.spongepowered.plugin.metadata.PluginMetadata; + +import java.io.InputStream; +import java.nio.file.Files; +import java.util.LinkedList; +import java.util.List; + +public final class JavaPluginLanguageService extends StandardPluginLanguageService { + private final static String NAME = "java_plain"; + + @Override + public String name() { + return JavaPluginLanguageService.NAME; + } + + @Override + public String pluginLoader() { + return "org.spongepowered.vanilla.launch.plugin.JavaPluginLoader"; + } + + @Override + public List> createPluginCandidates(final Environment environment, final PluginResource resource) throws Exception { + if (resource instanceof JVMPluginResource jvmResource && Files.exists(jvmResource.resourcesRoot().resolve("net/minecraft/server/MinecraftServer.class"))) { + this.logger.debug("Container in path '{}' has been detected as Minecraft.", resource.path()); + + final List> candidates = new LinkedList<>(); + try (final InputStream stream = JavaPluginLanguageService.class.getClassLoader().getResourceAsStream("META-INF/minecraft_sponge_plugins.json")) { + for (final PluginMetadata metadata : loadMetadataContainer(environment, stream).metadata()) { + candidates.add(new StandardPluginCandidate<>(metadata, resource)); + } + } + + return candidates; + } + + return super.createPluginCandidates(environment, resource); + } +} diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLanguageService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ResourceType.java similarity index 53% rename from vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLanguageService.java rename to vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ResourceType.java index 04a58be0df4..adeece5a25d 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLanguageService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ResourceType.java @@ -22,36 +22,29 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.vanilla.launch.plugin; +package org.spongepowered.vanilla.applaunch.plugin; -import org.spongepowered.plugin.Environment; -import org.spongepowered.plugin.builtin.jvm.JVMPluginLanguageService; -import org.spongepowered.plugin.metadata.Container; -import org.spongepowered.plugin.metadata.builtin.MetadataParser; +import cpw.mods.jarhandling.SecureJar; +import org.spongepowered.plugin.PluginResource; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; +import java.util.Locale; -public final class JavaPluginLanguageService extends JVMPluginLanguageService { +public enum ResourceType { + SERVICE, // service layer + LANGUAGE, // plugin layer + PLUGIN; // game layer - private final static String NAME = "java_plain"; + public static final String PROPERTY_NAME = "Resource-Type"; - @Override - public String name() { - return JavaPluginLanguageService.NAME; + public static ResourceType of(final PluginResource resource) { + return ResourceType.fromName(resource.property(PROPERTY_NAME).orElse(null)); } - @Override - public String pluginLoader() { - return "org.spongepowered.vanilla.launch.plugin.JavaPluginLoader"; + public static ResourceType of(final SecureJar jar) { + return ResourceType.fromName(jar.moduleDataProvider().getManifest().getMainAttributes().getValue(PROPERTY_NAME)); } - @Override - public Container loadMetadataContainer(final Environment environment, final InputStream stream) throws Exception { - final BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)); - return MetadataParser.read(reader, MetadataParser.gsonBuilder().create()); + public static ResourceType fromName(final String name) { + return name == null ? ResourceType.PLUGIN : ResourceType.valueOf(name.toUpperCase(Locale.ROOT)); } - } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java index a021fe6c1a2..4919af6a534 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java @@ -32,25 +32,23 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.fusesource.jansi.AnsiConsole; -import org.spongepowered.asm.launch.MixinLaunchPluginLegacy; +import org.spongepowered.asm.launch.MixinLaunchPlugin; import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants; import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.builtin.StandardEnvironment; -import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; import org.spongepowered.transformers.modlauncher.AccessWidenerTransformationService; import org.spongepowered.transformers.modlauncher.SuperclassChanger; import org.spongepowered.vanilla.applaunch.Constants; +import org.spongepowered.vanilla.applaunch.plugin.locator.SecureJarPluginResource; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.Set; public final class VanillaPlatformService implements ITransformationService { @@ -64,105 +62,6 @@ public final class VanillaPlatformService implements ITransformationService { return VanillaPlatformService.NAME; } - @Override - public void initialize(final IEnvironment environment) { - this.pluginPlatform.initialize(); - } - - @Override - public List beginScanning(final IEnvironment environment) { - this.pluginPlatform.locatePluginResources(); - this.pluginPlatform.createPluginCandidates(); - final AccessWidenerTransformationService accessWidener = environment.getProperty(AccessWidenerTransformationService.INSTANCE.get()).orElse(null); - final SuperclassChanger superclassChanger = environment.getProperty(SuperclassChanger.INSTANCE.get()).orElse(null); - final ILaunchPluginService mixin = environment.findLaunchPlugin(MixinLaunchPluginLegacy.NAME).orElse(null); - - final List gameResources = new ArrayList<>(); - - for (final Map.Entry> resourcesEntry : this.pluginPlatform.getResources().entrySet()) { - final Set resources = resourcesEntry.getValue(); - for (final PluginResource resource : resources) { - - // Handle Access Transformers - if ((accessWidener != null || mixin != null || superclassChanger != null) && resource instanceof JVMPluginResource) { - if (mixin != null) { - // Offer jar to the Mixin service - mixin.offerResource(resource.path(), resource.path().getFileName().toString()); - } - - // Offer jar to the AW service - ((JVMPluginResource) resource).manifest().ifPresent(manifest -> { - if (accessWidener != null) { - final String atFiles = manifest.getMainAttributes().getValue(Constants.ManifestAttributes.ACCESS_WIDENER); - if (atFiles != null) { - for (final String atFile : atFiles.split(",")) { - if (!atFile.endsWith(AccessWidenerTransformationService.ACCESS_WIDENER_EXTENSION)) { - continue; - } - try { - accessWidener.offerResource( - ((JVMPluginResource) resource).fileSystem().getPath(atFile).toUri().toURL(), - atFile - ); - } catch (final MalformedURLException ex) { - this.pluginPlatform.logger().warn( - "Failed to read declared access widener {}, from {}:", - atFile, - resource.locator() - ); - } - } - } - } - if (mixin != null && manifest.getMainAttributes().getValue(org.spongepowered.asm.util.Constants.ManifestAttributes.MIXINCONFIGS) != null) { - if (!VanillaPlatformService.isSponge((JVMPluginResource) resource)) { - this.pluginPlatform.logger().warn( - "Plugin from {} uses Mixins to modify the Minecraft Server. If something breaks, remove it before reporting the " - + "problem to Sponge!", resource.path() - ); - } - } - if (superclassChanger != null) { - final String superclassChangeFiles = manifest.getMainAttributes().getValue(Constants.ManifestAttributes.SUPERCLASS_CHANGE); - if (superclassChangeFiles != null) { - for (final String superclassChangeFile : superclassChangeFiles.split(",")) { - if (!superclassChangeFile.endsWith(SuperclassChanger.SUPER_CLASS_EXTENSION)) { - continue; - } - try { - superclassChanger.offerResource( - ((JVMPluginResource) resource).fileSystem().getPath(superclassChangeFile).toUri().toURL(), - superclassChangeFile - ); - } catch (final MalformedURLException ex) { - this.pluginPlatform.logger().warn( - "Failed to read declared superclass changer {}, from {}:", - superclassChangeFile, - resource.locator() - ); - } - } - } - } - }); - - // TODO custom jar metadata ? - gameResources.add(SecureJar.from(resource.path())); - } - } - } - - return List.of(new Resource(IModuleLayerManager.Layer.GAME, gameResources)); - } - - private static boolean isSponge(final JVMPluginResource resource) { - try { - return resource.path().toUri().equals(VanillaPlatformService.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (final URISyntaxException ex) { - return false; - } - } - @Override public void onLoad(final IEnvironment env, final Set otherServices) { AnsiConsole.systemInstall(); @@ -171,13 +70,12 @@ public void onLoad(final IEnvironment env, final Set otherServices) { AppLaunch.setPluginPlatform(this.pluginPlatform); final String implementationVersion = StandardEnvironment.class.getPackage().getImplementationVersion(); - final Path baseDirectory = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".")); + final Path baseDirectory = env.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".")); this.pluginPlatform.setVersion(implementationVersion == null ? "dev" : implementationVersion); this.pluginPlatform.setBaseDirectory(baseDirectory); - this.pluginPlatform.logger().info("SpongePowered PLUGIN Subsystem Version={} Source={}", - this.pluginPlatform.version(), this.getCodeSource()); + this.pluginPlatform.logger().info("SpongePowered PLUGIN Subsystem Version={} Source={}", this.pluginPlatform.version(), this.getCodeSource()); final Path modsDirectory = baseDirectory.resolve("mods"); if (Files.notExists(modsDirectory)) { @@ -195,11 +93,113 @@ public void onLoad(final IEnvironment env, final Set otherServices) { this.pluginPlatform.setPluginDirectories(pluginDirectories); this.pluginPlatform.setMetadataFilePath(PluginPlatformConstants.METADATA_FILE_LOCATION); + } + + @Override + public void initialize(final IEnvironment environment) { + this.pluginPlatform.initializeLanguageServices(); + } + @Override + public List beginScanning(final IEnvironment environment) { this.pluginPlatform.discoverLocatorServices(); this.pluginPlatform.getLocatorServices().forEach((k, v) -> this.pluginPlatform.logger().info("Plugin resource locator '{}' found.", k)); + + this.pluginPlatform.locatePluginResources(); + + final List languageResources = new ArrayList<>(); + + for (final Set resources : this.pluginPlatform.getResources().values()) { + for (final PluginResource resource : resources) { + if (resource instanceof SecureJarPluginResource secureJarResource) { + if (ResourceType.of(resource) == ResourceType.LANGUAGE) { + languageResources.add(secureJarResource.jar()); + } + } + } + } + + return List.of(new Resource(IModuleLayerManager.Layer.PLUGIN, languageResources)); + } + + @Override + public List completeScan(IModuleLayerManager layerManager) { this.pluginPlatform.discoverLanguageServices(); this.pluginPlatform.getLanguageServices().forEach((k, v) -> this.pluginPlatform.logger().info("Plugin language loader '{}' found.", k)); + + this.pluginPlatform.createPluginCandidates(); + + IEnvironment env = Launcher.INSTANCE.environment(); + final AccessWidenerTransformationService accessWidener = env.getProperty(AccessWidenerTransformationService.INSTANCE.get()).orElse(null); + final SuperclassChanger superclassChanger = env.getProperty(SuperclassChanger.INSTANCE.get()).orElse(null); + final ILaunchPluginService mixin = env.findLaunchPlugin(MixinLaunchPlugin.NAME).orElse(null); + + final List gameResources = new ArrayList<>(); + + for (final Set resources : this.pluginPlatform.getResources().values()) { + for (final PluginResource resource : resources) { + if (resource instanceof SecureJarPluginResource secureJarResource) { + // Build jar metadata from first candidate, or fallback to standard + secureJarResource.init(); + + if (ResourceType.of(resource) == ResourceType.PLUGIN) { + gameResources.add(secureJarResource.jar()); + } + } + + // Offer jar to the Mixin service + if (mixin != null) { + mixin.offerResource(resource.path(), resource.path().getFileName().toString()); + } + + // Offer jar to the AW service + if (accessWidener != null) { + final Optional awFiles = resource.property(Constants.ManifestAttributes.ACCESS_WIDENER); + if (awFiles.isPresent()) { + for (final String awFile : awFiles.get().split(",")) { + if (!awFile.endsWith(AccessWidenerTransformationService.ACCESS_WIDENER_EXTENSION)) { + continue; + } + try { + accessWidener.offerResource(resource.locateResource(awFile).get().toURL(), awFile); + } catch (final Exception ex) { + this.pluginPlatform.logger().warn("Failed to read declared access widener {}, from {}:", awFile, resource.locator()); + } + } + } + } + + // Offer jar to the SuperclassChanger service + if (superclassChanger != null) { + final Optional superclassChangeFiles = resource.property(Constants.ManifestAttributes.SUPERCLASS_CHANGE); + if (superclassChangeFiles.isPresent()) { + for (final String superclassChangeFile : superclassChangeFiles.get().split(",")) { + if (!superclassChangeFile.endsWith(SuperclassChanger.SUPER_CLASS_EXTENSION)) { + continue; + } + try { + superclassChanger.offerResource(resource.locateResource(superclassChangeFile).get().toURL(), superclassChangeFile); + } catch (final Exception ex) { + this.pluginPlatform.logger().warn("Failed to read declared superclass changer {}, from {}:", superclassChangeFile, resource.locator()); + } + } + } + } + + // Log warning about plugin using Mixin + if (mixin != null && resource.property(org.spongepowered.asm.util.Constants.ManifestAttributes.MIXINCONFIGS).isPresent()) { + if (!VanillaPlatformService.isSponge(resource)) { + this.pluginPlatform.logger().warn("Plugin from {} uses Mixins to modify the Minecraft Server. If something breaks, remove it before reporting the problem to Sponge!", resource.path()); + } + } + } + } + + return List.of(new Resource(IModuleLayerManager.Layer.GAME, gameResources)); + } + + private static boolean isSponge(final PluginResource resource) { + return resource instanceof SecureJarPluginResource secureJarResource && secureJarResource.jar().name().equals("spongevanilla"); } @Override diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index 5cb21f752f4..dc353e2298e 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -24,6 +24,8 @@ */ package org.spongepowered.vanilla.applaunch.plugin; +import cpw.mods.modlauncher.Launcher; +import cpw.mods.modlauncher.api.IModuleLayerManager; import org.apache.logging.log4j.Logger; import org.spongepowered.common.applaunch.plugin.PluginPlatform; import org.spongepowered.plugin.PluginCandidate; @@ -32,7 +34,7 @@ import org.spongepowered.plugin.PluginResourceLocatorService; import org.spongepowered.plugin.blackboard.Keys; import org.spongepowered.plugin.builtin.StandardEnvironment; -import org.spongepowered.plugin.builtin.jvm.JVMKeys; +import org.spongepowered.vanilla.applaunch.plugin.locator.SecureJarPluginResource; import java.nio.file.Path; import java.util.Collections; @@ -100,12 +102,12 @@ public void setPluginDirectories(final List pluginDirectories) { @Override public String metadataFilePath() { - return this.standardEnvironment.blackboard().get(JVMKeys.METADATA_FILE_PATH); + return this.standardEnvironment.blackboard().get(Keys.METADATA_FILE_PATH); } @Override public void setMetadataFilePath(final String metadataFilePath) { - this.standardEnvironment.blackboard().getOrCreate(JVMKeys.METADATA_FILE_PATH, () -> metadataFilePath); + this.standardEnvironment.blackboard().getOrCreate(Keys.METADATA_FILE_PATH, () -> metadataFilePath); } public StandardEnvironment getStandardEnvironment() { @@ -128,15 +130,15 @@ public Map, List> entry : this.languageServices.entrySet()) { entry.getValue().initialize(this.standardEnvironment); } } public void discoverLocatorServices() { - final ServiceLoader> serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load( - PluginResourceLocatorService.class, null); + final ModuleLayer serviceLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.SERVICE)).orElseThrow(); + final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(serviceLayer, PluginResourceLocatorService.class); for (final Iterator> iter = serviceLoader.iterator(); iter.hasNext(); ) { final PluginResourceLocatorService next; @@ -153,8 +155,8 @@ public void discoverLocatorServices() { } public void discoverLanguageServices() { - final ServiceLoader> serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load( - PluginLanguageService.class, VanillaPluginPlatform.class.getClassLoader()); + final ModuleLayer pluginLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.PLUGIN)).orElseThrow(); + final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(pluginLayer, PluginLanguageService.class); for (final Iterator> iter = serviceLoader.iterator(); iter.hasNext(); ) { final PluginLanguageService next; @@ -181,18 +183,23 @@ public void locatePluginResources() { } public void createPluginCandidates() { - for (final Map.Entry> languageEntry : this.languageServices.entrySet()) { - final PluginLanguageService languageService = languageEntry.getValue(); - for (final Map.Entry> resourcesEntry : this.locatorResources.entrySet()) { + for (final PluginLanguageService languageService : this.languageServices.values()) { + for (final Set resources : this.locatorResources.values()) { + for (final PluginResource pluginResource : resources) { + if (ResourceType.of(pluginResource) != ResourceType.PLUGIN) { + continue; + } - for (final PluginResource pluginResource : resourcesEntry.getValue()) { try { - final List> candidates = languageService.createPluginCandidates(this.standardEnvironment, - pluginResource); + final List> candidates = languageService.createPluginCandidates(this.standardEnvironment, pluginResource); if (candidates.isEmpty()) { continue; } this.pluginCandidates.computeIfAbsent(languageService, k -> new LinkedList<>()).addAll(candidates); + + if (pluginResource instanceof SecureJarPluginResource jarResource) { + jarResource.addCandidates((List) candidates); + } } catch (final Exception ex) { this.standardEnvironment.logger().error("Failed to create plugin candidates", ex); } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java new file mode 100644 index 00000000000..f9f90b76476 --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java @@ -0,0 +1,66 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin.locator; + +import org.spongepowered.plugin.Environment; +import org.spongepowered.plugin.PluginResourceLocatorService; + +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Stream; + +public final class EnvironmentPluginResourceLocatorService implements PluginResourceLocatorService { + + @Override + public String name() { + return "environment_plugin"; + } + + @Override + public Set locatePluginResources(Environment environment) { + final Set resources = new HashSet<>(); + for (final Path[] paths : EnvironmentPluginResourceLocatorService.getPluginsPaths()) { + resources.add(new SecureJarPluginResource(this.name(), paths)); + } + return resources; + } + + private static List getPluginsPaths() { + final String env = System.getenv("SPONGE_PLUGINS"); + if (env == null) { + return Collections.emptyList(); + } + + List plugins = new ArrayList<>(); + for (final String entry : env.split(";")) { + if (entry.isBlank()) { + continue; + } + plugins.add(Stream.of(entry.split("&")).map(Path::of).toArray(Path[]::new)); + } + + return plugins; + } +} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java new file mode 100644 index 00000000000..ff80fbb80f5 --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java @@ -0,0 +1,102 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin.locator; + +import cpw.mods.jarhandling.JarMetadata; +import cpw.mods.jarhandling.SecureJar; +import org.spongepowered.plugin.metadata.PluginMetadata; + +import java.lang.module.ModuleDescriptor; +import java.nio.file.Path; + +public class PluginJarMetadata implements JarMetadata { + private final SecureJar jar; + private final Path[] paths; + + private boolean initialized = false; + private PluginMetadata plugin; + private JarMetadata fallback; + + private ModuleDescriptor descriptor; + + public PluginJarMetadata(final SecureJar jar, final Path[] paths) { + this.jar = jar; + this.paths = paths; + } + + public void init(final PluginMetadata plugin) { + if (this.initialized) { + throw new IllegalStateException("Metadata already initialized"); + } + this.initialized = true; + if (plugin == null) { + this.fallback = JarMetadata.from(this.jar, this.paths); + } else { + this.plugin = plugin; + } + } + + private void checkInitialized() { + if (!this.initialized) { + throw new IllegalStateException("Metadata not initialized"); + } + } + + @Override + public String name() { + checkInitialized(); + if (this.plugin == null) { + return this.fallback.name(); + } + return this.plugin.id(); + } + + @Override + public String version() { + checkInitialized(); + if (this.plugin == null) { + return this.fallback.version(); + } + return this.plugin.version().toString(); + } + + @Override + public ModuleDescriptor descriptor() { + checkInitialized(); + if (this.plugin == null) { + return this.fallback.descriptor(); + } + if (this.descriptor == null) { + ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(name()) + .version(version()) + .packages(this.jar.getPackages()); + this.jar.getProviders().stream() + .filter(p -> !p.providers().isEmpty()) + .forEach(p -> builder.provides(p.serviceName(), p.providers())); + this.descriptor = builder.build(); + } + return this.descriptor; + } +} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java new file mode 100644 index 00000000000..d5aa68ed8a2 --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java @@ -0,0 +1,118 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin.locator; + +import cpw.mods.jarhandling.JarMetadata; +import cpw.mods.jarhandling.SecureJar; +import org.spongepowered.plugin.PluginCandidate; +import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; +import org.spongepowered.vanilla.applaunch.plugin.ResourceType; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.jar.Manifest; + +public final class SecureJarPluginResource implements JVMPluginResource { + private final String locator; + private final SecureJar jar; + + private PluginJarMetadata pluginJarMetadata; + private List> candidates; + + public SecureJarPluginResource(final String locator, final Path... paths) { + this.locator = locator; + this.jar = SecureJar.from(jar -> { + if (ResourceType.of(jar) == ResourceType.PLUGIN) { + this.pluginJarMetadata = new PluginJarMetadata(jar, paths); + this.candidates = new ArrayList<>(); + return this.pluginJarMetadata; + } + return JarMetadata.from(jar, paths); + }, paths); + } + + @Override + public String locator() { + return this.locator; + } + + public SecureJar jar() { + return this.jar; + } + + @Override + public Path path() { + return this.jar.getPrimaryPath(); + } + + @Override + public Manifest manifest() { + return this.jar.moduleDataProvider().getManifest(); + } + + @Override + public Path resourcesRoot() { + return this.jar.getRootPath(); + } + + public void addCandidates(Collection> candidates) { + if (this.candidates != null) { + this.candidates.addAll(candidates); + } + } + + public void init() { + if (this.pluginJarMetadata != null) { + this.pluginJarMetadata.init(this.candidates.isEmpty() ? null : this.candidates.get(0).metadata()); + } + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof SecureJarPluginResource that)) { + return false; + } + return this.locator.equals(that.locator) && this.jar.equals(that.jar); + } + + @Override + public int hashCode() { + return Objects.hash(this.locator, this.jar); + } + + @Override + public String toString() { + return "SecureJarPluginResource[" + + "locator=" + this.locator + ", " + + "jar=" + this.jar + ']'; + } + +} diff --git a/vanilla/src/applaunch/resource-templates/META-INF/minecraft_sponge_plugins.json b/vanilla/src/applaunch/resource-templates/META-INF/minecraft_sponge_plugins.json new file mode 100644 index 00000000000..a4d61effc80 --- /dev/null +++ b/vanilla/src/applaunch/resource-templates/META-INF/minecraft_sponge_plugins.json @@ -0,0 +1,24 @@ +{ + "loader": { + "name": "java_plain", + "version": "1.0" + }, + "license": "Mojang Studios, All Rights Reserved", + "plugins": [ + { + "id": "minecraft", + "name": "Minecraft", + "version": "{{ minecraftVersion }}", + "entrypoint": "org.spongepowered.common.launcher.Launcher", + "links": { + "homepage": "https://www.minecraft.net" + }, + "contributors": [ + { + "name": "Mojang Studios", + "description": "Lead Developer" + } + ] + } + ] +} \ No newline at end of file diff --git a/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService b/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginLanguageService b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginLanguageService index e12ee48b985..3e6983f38f8 100644 --- a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginLanguageService +++ b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginLanguageService @@ -1 +1 @@ -org.spongepowered.vanilla.launch.plugin.JavaPluginLanguageService \ No newline at end of file +org.spongepowered.vanilla.applaunch.plugin.JavaPluginLanguageService \ No newline at end of file diff --git a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService index 93928337b63..7af1564b674 100644 --- a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService +++ b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService @@ -1,2 +1 @@ -org.spongepowered.plugin.builtin.jvm.locator.DirectoryPluginResourceLocatorService -org.spongepowered.plugin.builtin.jvm.locator.ClasspathPluginResourceLocatorService \ No newline at end of file +org.spongepowered.vanilla.applaunch.plugin.locator.EnvironmentPluginResourceLocatorService \ No newline at end of file diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/VanillaLaunch.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/VanillaLaunch.java index 7203b0a7328..174351373f5 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/VanillaLaunch.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/VanillaLaunch.java @@ -34,28 +34,18 @@ import org.spongepowered.common.launch.Launch; import org.spongepowered.common.launch.mapping.SpongeMappingManager; import org.spongepowered.plugin.PluginContainer; -import org.spongepowered.plugin.metadata.PluginMetadata; -import org.spongepowered.plugin.metadata.builtin.MetadataContainer; -import org.spongepowered.plugin.metadata.builtin.MetadataParser; import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform; import org.spongepowered.vanilla.launch.inject.SpongeVanillaModule; import org.spongepowered.vanilla.launch.mapping.VanillaMappingManager; import org.spongepowered.vanilla.launch.plugin.VanillaDummyPluginContainer; import org.spongepowered.vanilla.launch.plugin.VanillaPluginManager; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Enumeration; +import java.util.Collection; import java.util.List; +import java.util.Set; public abstract class VanillaLaunch extends Launch { + private static final Set PLATFORM_IDS = Set.of("spongevanilla", "sponge", "spongeapi", "minecraft"); private final Stage injectionStage; private final VanillaPluginManager pluginManager; @@ -121,58 +111,9 @@ protected final void launchPlatform(final String[] args) { protected abstract void performBootstrap(final String[] args); protected final void createPlatformPlugins() { - final String metadataFileLocation = this.pluginPlatform.metadataFilePath(); - try { - // This is a bit nasty, but allows Sponge to detect builtin platform plugins when it's not the first entry on the classpath. - final URL classUrl = VanillaLaunch.class.getResource("/" + VanillaLaunch.class.getName().replace('.', '/') + ".class"); - - MetadataContainer read = null; - - // In production, let's try to ensure we can find our descriptor even if we're not first on the classpath - if (classUrl.getProtocol().equals("jar")) { - // Extract the path of the underlying jar file, and parse it as a path to normalize it - final String[] classUrlSplit = classUrl.getPath().split("!"); - final Path expectedFile = Paths.get(new URL(classUrlSplit[0]).toURI()); - - // Then go through every possible resource - final Enumeration manifests = - VanillaLaunch.class.getClassLoader().getResources("/" + metadataFileLocation); - while (manifests.hasMoreElements()) { - final URL next = manifests.nextElement(); - if (!next.getProtocol().equals("jar")) { - continue; - } - - // And stop when the normalized jar in that resource matches the URL of the jar that loaded VanillaLaunch? - final String[] pathSplit = next.getPath().split("!"); - if (pathSplit.length == 2) { - final Path vanillaPath = Paths.get(new URL(pathSplit[0]).toURI()); - if (vanillaPath.equals(expectedFile)) { - try (final Reader reader = new InputStreamReader(next.openStream(), StandardCharsets.UTF_8)) { - read = MetadataParser.read(reader); - } - break; - } - } - } - } - - if (read == null) { // other measures failed, fall back to directly querying the classpath - final Path vanillaPath = - Paths.get(VanillaLaunch.class.getResource("/" + metadataFileLocation).toURI()); - try (final Reader reader = Files.newBufferedReader(vanillaPath, StandardCharsets.UTF_8)) { - read = MetadataParser.read(reader); - } - } - if (read == null) { - throw new RuntimeException("Could not determine location for implementation metadata!"); - } - - for (final PluginMetadata metadata : read.metadata()) { - this.pluginManager().addPlugin(new VanillaDummyPluginContainer(metadata, this.logger(), this)); - } - } catch (final IOException | URISyntaxException e) { - throw new RuntimeException("Could not load metadata information for the implementation! This should be impossible!"); - } + this.pluginPlatform().getCandidates().values().stream().flatMap(Collection::stream) + .filter(plugin -> PLATFORM_IDS.contains(plugin.metadata().id())) + .map(plugin -> new VanillaDummyPluginContainer(plugin, this.logger(), this)) + .forEach(this.pluginManager()::addPlugin); } } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java index 1333eac8ece..6a730ff319b 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.manager.SpongeEventManager; import org.spongepowered.plugin.PluginContainer; -import org.spongepowered.vanilla.launch.plugin.VanillaJavaPluginContainer; import java.lang.invoke.MethodHandles; @@ -37,9 +36,6 @@ public final class VanillaEventManager extends SpongeEventManager { @Override protected MethodHandles.@Nullable Lookup getLookup(final PluginContainer plugin, final Class handle) { - if (plugin instanceof VanillaJavaPluginContainer vanilla) { - return vanilla.lookup(); - } return null; } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java index a672c47da58..7b52a8aadc4 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java @@ -33,16 +33,12 @@ import org.spongepowered.plugin.InvalidPluginException; import org.spongepowered.plugin.PluginCandidate; import org.spongepowered.plugin.builtin.jvm.JVMPluginLoader; -import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; +import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; -import java.lang.invoke.MethodHandles; - -public final class JavaPluginLoader extends JVMPluginLoader { +public final class JavaPluginLoader implements JVMPluginLoader { private final ArtifactVersion version = new DefaultArtifactVersion("1.0"); - private static final MethodHandles.Lookup SPONGE_LOOKUP = MethodHandles.lookup(); - @Override public ArtifactVersion version() { return this.version; @@ -55,7 +51,6 @@ public VanillaJavaPluginContainer loadPlugin(final Environment environment, fina try { final String mainClass = container.metadata().entrypoint(); final Class pluginClass = Class.forName(mainClass, true, targetClassLoader); - container.initializeLookup(MethodHandles.privateLookupIn(pluginClass, JavaPluginLoader.SPONGE_LOOKUP)); final Injector parentInjector = Launch.instance().lifecycle().platformInjector(); final Object plugin; diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java index de1c07ccd66..66689339990 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java @@ -26,79 +26,14 @@ import org.apache.logging.log4j.Logger; import org.spongepowered.common.applaunch.plugin.DummyPluginContainer; -import org.spongepowered.plugin.PluginContainer; -import org.spongepowered.plugin.metadata.PluginMetadata; +import org.spongepowered.plugin.PluginCandidate; +import org.spongepowered.plugin.PluginResource; +import org.spongepowered.plugin.builtin.StandardPluginContainer; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Objects; -import java.util.Optional; -import java.util.StringJoiner; +public final class VanillaDummyPluginContainer extends StandardPluginContainer implements DummyPluginContainer { -public final class VanillaDummyPluginContainer implements PluginContainer, DummyPluginContainer { - - private final PluginMetadata metadata; - private final Logger logger; - private final Object instance; - - public VanillaDummyPluginContainer(final PluginMetadata metadata, final Logger logger, final Object instance) { - this.metadata = metadata; - this.logger = logger; - this.instance = instance; - } - - @Override - public PluginMetadata metadata() { - return this.metadata; - } - - @Override - public Logger logger() { - return this.logger; - } - - @Override - public Object instance() { - return this.instance; - } - - @Override - public Optional locateResource(final URI relative) { - final ClassLoader classLoader = this.getClass().getClassLoader(); - final URL resolved = classLoader.getResource(relative.getPath()); - try { - if (resolved == null) { - return Optional.empty(); - } - return Optional.of(resolved.toURI()); - } catch (final URISyntaxException ignored) { - return Optional.empty(); - } - } - - @Override - public int hashCode() { - return Objects.hash(this.metadata().id()); - } - - @Override - public boolean equals(final Object that) { - if (that == this) { - return true; - } - - if (!(that instanceof PluginContainer)) { - return false; - } - - return this.metadata().id().equals(((PluginContainer) that).metadata().id()); - } - - @Override - public String toString() { - return new StringJoiner(", ", VanillaDummyPluginContainer.class.getSimpleName() + "[", "]") - .add("metadata= " + this.metadata) - .toString(); + public VanillaDummyPluginContainer(final PluginCandidate candidate, final Logger logger, final Object instance) { + super(candidate, logger); + this.initializeInstance(instance); } } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java index eda180bfa20..24001fabf6f 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java @@ -26,39 +26,18 @@ import org.spongepowered.api.Sponge; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.builtin.jvm.JVMPluginContainer; -import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; +import org.spongepowered.plugin.PluginResource; +import org.spongepowered.plugin.builtin.StandardPluginContainer; -import java.lang.invoke.MethodHandles; -import java.util.Objects; +public final class VanillaJavaPluginContainer extends StandardPluginContainer { -public final class VanillaJavaPluginContainer extends JVMPluginContainer { - - private MethodHandles.Lookup lookup; - - public VanillaJavaPluginContainer(final PluginCandidate candidate) { + public VanillaJavaPluginContainer(final PluginCandidate candidate) { super(candidate); } @Override protected void initializeInstance(final Object instance) { super.initializeInstance(instance); - Sponge.eventManager().registerListeners(this, instance); } - - /** - * {@return A lookup with access to internals of the module containing this plugin} - */ - public MethodHandles.Lookup lookup() { - return this.lookup; - } - - public void initializeLookup(final MethodHandles.Lookup lookup) { - if (this.lookup != null) { - throw new RuntimeException(String.format("Attempt made to set the lookup for plugin container '%s' twice!", - this.metadata().id())); - } - this.lookup = Objects.requireNonNull(lookup); - } } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java index f2251dffbf4..c27758532cb 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java @@ -58,18 +58,15 @@ @Singleton public final class VanillaPluginManager implements SpongePluginManager { - private final Map plugins; private final Map instancesToPlugins; private final List sortedPlugins; - private final Map> locatedResources; private final Map containerToResource; public VanillaPluginManager() { this.plugins = new Object2ObjectOpenHashMap<>(); this.instancesToPlugins = new IdentityHashMap<>(); this.sortedPlugins = new ArrayList<>(); - this.locatedResources = new Object2ObjectOpenHashMap<>(); this.containerToResource = new Object2ObjectOpenHashMap<>(); } @@ -88,10 +85,7 @@ public Collection plugins() { return Collections.unmodifiableCollection(this.sortedPlugins); } - @SuppressWarnings("unchecked") public void loadPlugins(final VanillaPluginPlatform platform) { - this.locatedResources.putAll(platform.getResources()); - final Map, PluginLanguageService> pluginLanguageLookup = new HashMap<>(); final Map, PluginLoader> pluginLoaders = new HashMap<>(); @@ -176,10 +170,6 @@ public void addPlugin(final PluginContainer plugin) { } } - public Map> locatedResources() { - return Collections.unmodifiableMap(this.locatedResources); - } - @Nullable public PluginResource resource(final PluginContainer container) { return this.containerToResource.get(container); diff --git a/vanilla/src/launch/resource-templates/META-INF/sponge_plugins.json b/vanilla/src/launch/resource-templates/META-INF/sponge_plugins.json index de066322672..5a9c035285f 100644 --- a/vanilla/src/launch/resource-templates/META-INF/sponge_plugins.json +++ b/vanilla/src/launch/resource-templates/META-INF/sponge_plugins.json @@ -6,27 +6,11 @@ "license": "MIT", "plugins": [ { - "id": "minecraft", - "name": "Minecraft", - "version": "{{ minecraftVersion }}", - "entrypoint": "org.spongepowered.common.launcher.Launcher", - "links": { - "homepage": "https://www.minecraft.net" - }, - "contributors": [ - { - "name": "Mojang AB", - "description": "Lead Developer" - } - ] - }, - { - "loader": "java_plain", - "id": "spongeapi", - "name": "SpongeAPI", - "version": "{{ apiVersion }}", - "entrypoint": "org.spongepowered.api.Sponge", - "description": "The Minecraft API specification", + "id": "spongevanilla", + "name": "SpongeVanilla", + "version": "{{ version }}", + "entrypoint": "org.spongepowered.vanilla.SpongeVanilla", + "description": "Vanilla Minecraft with Sponge", "links": { "homepage": "https://www.spongepowered.org", "source": "https://www.spongepowered.org/source", @@ -37,6 +21,12 @@ "name": "SpongePowered", "description": "Lead Developer" } + ], + "dependencies": [ + { + "id": "sponge", + "version": "{{ minecraftVersion }}-{{ apiVersion }}" + } ] }, { @@ -68,11 +58,11 @@ ] }, { - "id": "spongevanilla", - "name": "SpongeVanilla", - "version": "{{ version }}", - "entrypoint": "org.spongepowered.vanilla.SpongeVanilla", - "description": "Vanilla Minecraft with Sponge", + "id": "spongeapi", + "name": "SpongeAPI", + "version": "{{ apiVersion }}", + "entrypoint": "org.spongepowered.api.Sponge", + "description": "The Minecraft API specification", "links": { "homepage": "https://www.spongepowered.org", "source": "https://www.spongepowered.org/source", @@ -83,12 +73,6 @@ "name": "SpongePowered", "description": "Lead Developer" } - ], - "dependencies": [ - { - "id": "sponge", - "version": "{{ minecraftVersion }}-{{ apiVersion }}" - } ] } ] diff --git a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java index 8558de7459b..067a29faa37 100644 --- a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java +++ b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginPackResources.java @@ -38,15 +38,12 @@ import org.spongepowered.common.SpongeCommon; import org.spongepowered.plugin.PluginContainer; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; -import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; -import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -55,15 +52,13 @@ public final class PluginPackResources extends AbstractPackResources { private final PluginContainer container; private final PackMetadataSection metadata; - private final @Nullable Supplier fileSystem; - private final File file; + private final @Nullable Path pluginRoot; - public PluginPackResources(final PackLocationInfo info, final PluginContainer container, final @Nullable Supplier fileSystem) { + public PluginPackResources(final PackLocationInfo info, final PluginContainer container, final @Nullable Path pluginRoot) { super(info); - this.file = new File("sponge_plugin_pack"); this.container = container; this.metadata = new PackMetadataSection(Component.literal("Plugin Resources"), 6, Optional.empty()); - this.fileSystem = fileSystem; + this.pluginRoot = pluginRoot; } @Override @@ -73,7 +68,7 @@ public IoSupplier getRootResource(final String... var1) { } private IoSupplier getResource(final String rawPath) { - final Optional uri = this.container.locateResource(URI.create(rawPath)); + final Optional uri = this.container.locateResource(rawPath); if (uri.isEmpty()) { return null; } @@ -153,10 +148,10 @@ public void close() { } private @Nullable Path typeRoot(final PackType type) throws IOException { - if (this.fileSystem == null) { + if (this.pluginRoot == null) { return null; } - return this.fileSystem.get().getPath(type.getDirectory()); + return this.pluginRoot.resolve(type.getDirectory()); } } diff --git a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginRepositorySource.java b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginRepositorySource.java index 84011e55e49..7d2b6972662 100644 --- a/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginRepositorySource.java +++ b/vanilla/src/main/java/org/spongepowered/vanilla/server/packs/PluginRepositorySource.java @@ -33,19 +33,17 @@ import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.packs.repository.PackSource; import net.minecraft.server.packs.repository.RepositorySource; -import org.apache.commons.io.FilenameUtils; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.launch.Launch; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.PluginResource; -import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResource; +import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; import org.spongepowered.vanilla.bridge.server.packs.repository.PackRepositoryBridge_Vanilla; import org.spongepowered.vanilla.launch.plugin.VanillaPluginManager; -import java.nio.file.FileSystem; +import java.nio.file.Path; import java.util.Optional; import java.util.function.Consumer; -import java.util.function.Supplier; public final class PluginRepositorySource implements RepositorySource { @@ -67,17 +65,13 @@ public void loadPacks(final Consumer callback) { final String id = "plugin-" + pluginContainer.metadata().id(); final PluginResource resource = pluginManager.resource(pluginContainer); // TODO: provide hook in the resource to return the file system for all resource types? - // Also -- can we fake a FileSystem for a non-Jar (needs thinking about).... - @Nullable Supplier fileSystemSupplier = null; - if (resource instanceof JVMPluginResource) { - final String extension = FilenameUtils.getExtension(resource.path().getFileName().toString()); - if ("jar".equals(extension)) { - fileSystemSupplier = ((JVMPluginResource) resource)::fileSystem; - } + @Nullable Path pluginRoot = null; + if (resource instanceof JVMPluginResource jvmResource) { + pluginRoot = jvmResource.resourcesRoot(); } final PackLocationInfo info = new PackLocationInfo(id, Component.literal(id), PackSource.DEFAULT, Optional.empty()); - final PluginPackResources packResources = new PluginPackResources(info, pluginContainer, fileSystemSupplier); + final PluginPackResources packResources = new PluginPackResources(info, pluginContainer, pluginRoot); final Pack.ResourcesSupplier packSupplier = new Pack.ResourcesSupplier() { @Override From 3ad082e66356cbb2ab5c39723550f0842981d6f0 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Tue, 27 Aug 2024 23:01:15 +0200 Subject: [PATCH 199/226] Transform listener classes in vanilla --- .../transformation/ListenerTransformer.java | 35 +------- .../forge/launch/event/ForgeEventManager.java | 7 -- .../ListenerTransformerHelper.java | 79 +++++++++++++++++++ .../common}/event/ListenerLookups.java | 2 +- .../event/manager/SpongeEventManager.java | 10 +-- vanilla/build.gradle.kts | 2 +- .../plugin/ListenerPluginService.java | 56 +++++++++++++ ...java => VanillaTransformationService.java} | 14 ++-- ...ods.modlauncher.api.ITransformationService | 2 +- ...odlauncher.serviceapi.ILaunchPluginService | 1 + .../launch/event/VanillaEventManager.java | 9 --- 11 files changed, 153 insertions(+), 64 deletions(-) create mode 100644 modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/ListenerTransformerHelper.java rename {forge/src/launch/java/org/spongepowered/forge/launch => src/main/java/org/spongepowered/common}/event/ListenerLookups.java (97%) create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ListenerPluginService.java rename vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/{VanillaPlatformService.java => VanillaTransformationService.java} (96%) create mode 100644 vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService diff --git a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/transformation/ListenerTransformer.java b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/transformation/ListenerTransformer.java index 62daa6ab20e..4bbaab1e6f4 100644 --- a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/transformation/ListenerTransformer.java +++ b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/transformation/ListenerTransformer.java @@ -24,10 +24,6 @@ */ package org.spongepowered.forge.applaunch.transformation; -import static org.objectweb.asm.Opcodes.ACC_STATIC; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.RETURN; - import cpw.mods.modlauncher.api.ITransformer; import cpw.mods.modlauncher.api.ITransformerActivity; import cpw.mods.modlauncher.api.ITransformerVotingContext; @@ -38,11 +34,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; +import org.spongepowered.transformers.modlauncher.ListenerTransformerHelper; import java.util.HashSet; import java.util.Set; @@ -52,28 +44,7 @@ public class ListenerTransformer implements ITransformer { @NonNull @Override public ClassNode transform(final ClassNode input, final ITransformerVotingContext context) { - MethodNode clinit = null; - for (final MethodNode method : input.methods) { - if (method.name.equals("") && method.desc.equals("()V")) { - clinit = method; - break; - } - } - - if (clinit == null) { - clinit = new MethodNode(ACC_STATIC, "", "()V", null, null); - clinit.instructions.add(new InsnNode(RETURN)); - input.methods.add(clinit); - } - - - final InsnList list = new InsnList(); - list.add(new LdcInsnNode(Type.getObjectType(input.name))); - list.add(new MethodInsnNode(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)); - list.add(new MethodInsnNode(INVOKESTATIC, "org/spongepowered/forge/launch/event/ListenerLookups", "set", "(Ljava/lang/Class;Ljava/lang/invoke/MethodHandles$Lookup;)V")); - - clinit.instructions.insert(list); - + ListenerTransformerHelper.transform(input); return input; } @@ -86,7 +57,7 @@ public TransformerVoteResult castVote(final ITransformerVotingContext context) { @NonNull @Override public Set targets() { - final Type listenerType = Type.getType("Lorg/spongepowered/api/event/Listener;"); + final Type listenerType = Type.getType(ListenerTransformerHelper.LISTENER_DESC); final Set listenerClasses = new HashSet<>(); for (ModFileInfo fileInfo : LoadingModList.get().getModFiles()) { diff --git a/forge/src/launch/java/org/spongepowered/forge/launch/event/ForgeEventManager.java b/forge/src/launch/java/org/spongepowered/forge/launch/event/ForgeEventManager.java index 936129a0765..1a4fd2dd074 100644 --- a/forge/src/launch/java/org/spongepowered/forge/launch/event/ForgeEventManager.java +++ b/forge/src/launch/java/org/spongepowered/forge/launch/event/ForgeEventManager.java @@ -36,9 +36,7 @@ import org.spongepowered.common.event.manager.SpongeEventManager; import org.spongepowered.forge.launch.bridge.event.ForgeEventBridge_Forge; import org.spongepowered.forge.launch.bridge.event.SpongeEventBridge_Forge; -import org.spongepowered.plugin.PluginContainer; -import java.lang.invoke.MethodHandles; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -139,11 +137,6 @@ public void start() { // EventManager - @Override - protected MethodHandles.@Nullable Lookup getLookup(final PluginContainer plugin, final Class handle) { - return ListenerLookups.get(handle); - } - @Override public boolean post(final org.spongepowered.api.event.Event event) { final SpongeEventBridge_Forge eventBridge = ((SpongeEventBridge_Forge) event); diff --git a/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/ListenerTransformerHelper.java b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/ListenerTransformerHelper.java new file mode 100644 index 00000000000..7b65503bfa1 --- /dev/null +++ b/modlauncher-transformers/src/main/java/org/spongepowered/transformers/modlauncher/ListenerTransformerHelper.java @@ -0,0 +1,79 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.transformers.modlauncher; + +import static org.objectweb.asm.Opcodes.ACC_STATIC; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; +import static org.objectweb.asm.Opcodes.RETURN; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class ListenerTransformerHelper { + public static final String LISTENER_DESC = "Lorg/spongepowered/api/event/Listener;"; + + public static boolean shouldTransform(ClassNode classNode) { + for (final MethodNode method : classNode.methods) { + if (method.visibleAnnotations != null) { + for (final AnnotationNode annotation : method.visibleAnnotations) { + if (annotation.desc.equals(LISTENER_DESC)) { + return true; + } + } + } + } + return false; + } + + public static void transform(ClassNode classNode) { + MethodNode clinit = null; + for (final MethodNode method : classNode.methods) { + if (method.name.equals("") && method.desc.equals("()V")) { + clinit = method; + break; + } + } + + if (clinit == null) { + clinit = new MethodNode(ACC_STATIC, "", "()V", null, null); + clinit.instructions.add(new InsnNode(RETURN)); + classNode.methods.add(clinit); + } + + + final InsnList list = new InsnList(); + list.add(new LdcInsnNode(Type.getObjectType(classNode.name))); + list.add(new MethodInsnNode(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)); + list.add(new MethodInsnNode(INVOKESTATIC, "org/spongepowered/common/event/ListenerLookups", "set", "(Ljava/lang/Class;Ljava/lang/invoke/MethodHandles$Lookup;)V")); + + clinit.instructions.insert(list); + } +} diff --git a/forge/src/launch/java/org/spongepowered/forge/launch/event/ListenerLookups.java b/src/main/java/org/spongepowered/common/event/ListenerLookups.java similarity index 97% rename from forge/src/launch/java/org/spongepowered/forge/launch/event/ListenerLookups.java rename to src/main/java/org/spongepowered/common/event/ListenerLookups.java index 0ab48d288c8..eff452c0281 100644 --- a/forge/src/launch/java/org/spongepowered/forge/launch/event/ListenerLookups.java +++ b/src/main/java/org/spongepowered/common/event/ListenerLookups.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.forge.launch.event; +package org.spongepowered.common.event; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/src/main/java/org/spongepowered/common/event/manager/SpongeEventManager.java b/src/main/java/org/spongepowered/common/event/manager/SpongeEventManager.java index a8c6cf83398..10607676dfe 100644 --- a/src/main/java/org/spongepowered/common/event/manager/SpongeEventManager.java +++ b/src/main/java/org/spongepowered/common/event/manager/SpongeEventManager.java @@ -45,6 +45,7 @@ import org.spongepowered.api.event.item.inventory.container.InteractContainerEvent; import org.spongepowered.common.SpongeCommon; import org.spongepowered.common.bridge.world.inventory.container.ContainerBridge; +import org.spongepowered.common.event.ListenerLookups; import org.spongepowered.common.event.ShouldFire; import org.spongepowered.common.event.filter.FilterGenerator; import org.spongepowered.common.event.tracking.PhaseContext; @@ -77,7 +78,6 @@ public abstract class SpongeEventManager implements EventManager { private static final NoExceptionClosable NULL_CLOSABLE = new NoExceptionClosable(); - private static final MethodHandles.Lookup OWN_LOOKUP = MethodHandles.lookup(); public final ListenerChecker checker; private final Object lock; @@ -223,8 +223,6 @@ private void register(final RegisteredListener handler) { } } - protected abstract MethodHandles.@Nullable Lookup getLookup(final PluginContainer plugin, final Class handle); - private void registerListener(final PluginContainer plugin, final Object listenerObject, final MethodHandles.@Nullable Lookup customLookup) { Objects.requireNonNull(plugin, "plugin"); @@ -244,10 +242,10 @@ private void registerListener(final PluginContainer plugin, final Object listene MethodHandles.@Nullable Lookup lookup = customLookup; if (lookup == null) { - lookup = this.getLookup(plugin, handle); + lookup = ListenerLookups.get(handle); if (lookup == null) { - SpongeCommon.logger().warn("No lookup found for listener {}. Using Sponge's lookup as fallback.", handle.getName()); - lookup = SpongeEventManager.OWN_LOOKUP; + SpongeCommon.logger().warn("No lookup found for listener {}.", handle.getName()); + return; } } diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index bb7f19df922..66db7fdd3c5 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -198,7 +198,7 @@ minecraft { )) testPluginsProject?.also { - //resources.add(it.sourceSets.getByName("main").output) + resources.add(it.sourceSets.getByName("main").output) } dependsOn(resources) diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ListenerPluginService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ListenerPluginService.java new file mode 100644 index 00000000000..6953b18551c --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/ListenerPluginService.java @@ -0,0 +1,56 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin; + +import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.transformers.modlauncher.ListenerTransformerHelper; + +import java.util.EnumSet; + +public class ListenerPluginService implements ILaunchPluginService { + private static final EnumSet YAY = EnumSet.of(Phase.AFTER); + private static final EnumSet NAY = EnumSet.noneOf(Phase.class); + + @Override + public String name() { + return "listener"; + } + + @Override + public EnumSet handlesClass(Type classType, boolean isEmpty) { + return isEmpty ? NAY : YAY; + } + + @Override + public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason) { + if (ListenerTransformerHelper.shouldTransform(classNode)) { + ListenerTransformerHelper.transform(classNode); + return ComputeFlags.COMPUTE_FRAMES; + } + return ComputeFlags.NO_REWRITE; + } +} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java similarity index 96% rename from vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java rename to vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java index 4919af6a534..6c9aa0135dc 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPlatformService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java @@ -27,7 +27,10 @@ import com.google.common.collect.ImmutableList; import cpw.mods.jarhandling.SecureJar; import cpw.mods.modlauncher.Launcher; -import cpw.mods.modlauncher.api.*; +import cpw.mods.modlauncher.api.IEnvironment; +import cpw.mods.modlauncher.api.IModuleLayerManager; +import cpw.mods.modlauncher.api.ITransformationService; +import cpw.mods.modlauncher.api.ITransformer; import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; @@ -51,15 +54,12 @@ import java.util.Optional; import java.util.Set; -public final class VanillaPlatformService implements ITransformationService { - - private static final String NAME = "vanilla_platform"; - +public final class VanillaTransformationService implements ITransformationService { private @MonotonicNonNull VanillaPluginPlatform pluginPlatform; @Override public @NonNull String name() { - return VanillaPlatformService.NAME; + return "spongevanilla"; } @Override @@ -188,7 +188,7 @@ public List completeScan(IModuleLayerManager layerManager) { // Log warning about plugin using Mixin if (mixin != null && resource.property(org.spongepowered.asm.util.Constants.ManifestAttributes.MIXINCONFIGS).isPresent()) { - if (!VanillaPlatformService.isSponge(resource)) { + if (!VanillaTransformationService.isSponge(resource)) { this.pluginPlatform.logger().warn("Plugin from {} uses Mixins to modify the Minecraft Server. If something breaks, remove it before reporting the problem to Sponge!", resource.path()); } } diff --git a/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService b/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService index 5760567b8c2..fcea6e880a6 100644 --- a/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService +++ b/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService @@ -1 +1 @@ -org.spongepowered.vanilla.applaunch.plugin.VanillaPlatformService \ No newline at end of file +org.spongepowered.vanilla.applaunch.plugin.VanillaTransformationService \ No newline at end of file diff --git a/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService b/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService new file mode 100644 index 00000000000..819258d57e1 --- /dev/null +++ b/vanilla/src/applaunch/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService @@ -0,0 +1 @@ +org.spongepowered.vanilla.applaunch.plugin.ListenerPluginService \ No newline at end of file diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java index 6a730ff319b..7746158359d 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/event/VanillaEventManager.java @@ -25,18 +25,9 @@ package org.spongepowered.vanilla.launch.event; import com.google.inject.Singleton; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.manager.SpongeEventManager; -import org.spongepowered.plugin.PluginContainer; - -import java.lang.invoke.MethodHandles; @Singleton public final class VanillaEventManager extends SpongeEventManager { - @Override - protected MethodHandles.@Nullable Lookup getLookup(final PluginContainer plugin, final Class handle) { - return null; - } - } From ab66bf1d4807cada24bd1442d1ae0153310e4078 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Wed, 28 Aug 2024 22:27:32 +0200 Subject: [PATCH 200/226] Move environment resource locator to plugin-spi --- .../plugin/VanillaPluginPlatform.java | 6 ++ ...vironmentPluginResourceLocatorService.java | 66 ------------------- .../locator/SecureJarPluginResource.java | 9 ++- ...owered.plugin.PluginResourceLocatorService | 1 - 4 files changed, 14 insertions(+), 68 deletions(-) delete mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java delete mode 100644 vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index dc353e2298e..3e5d5be4e6d 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -32,8 +32,10 @@ import org.spongepowered.plugin.PluginLanguageService; import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.PluginResourceLocatorService; +import org.spongepowered.plugin.blackboard.Blackboard; import org.spongepowered.plugin.blackboard.Keys; import org.spongepowered.plugin.builtin.StandardEnvironment; +import org.spongepowered.plugin.builtin.jvm.JVMKeys; import org.spongepowered.vanilla.applaunch.plugin.locator.SecureJarPluginResource; import java.nio.file.Path; @@ -137,6 +139,10 @@ public void initializeLanguageServices() { } public void discoverLocatorServices() { + final Blackboard blackboard = this.standardEnvironment.blackboard(); + blackboard.getOrCreate(JVMKeys.ENVIRONMENT_LOCATOR_VARIABLE_NAME, () -> "SPONGE_PLUGINS"); + blackboard.getOrCreate(JVMKeys.JVM_PLUGIN_RESOURCE_FACTORY, () -> SecureJarPluginResource::new); + final ModuleLayer serviceLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.SERVICE)).orElseThrow(); final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(serviceLayer, PluginResourceLocatorService.class); diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java deleted file mode 100644 index f9f90b76476..00000000000 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/EnvironmentPluginResourceLocatorService.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.applaunch.plugin.locator; - -import org.spongepowered.plugin.Environment; -import org.spongepowered.plugin.PluginResourceLocatorService; - -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Stream; - -public final class EnvironmentPluginResourceLocatorService implements PluginResourceLocatorService { - - @Override - public String name() { - return "environment_plugin"; - } - - @Override - public Set locatePluginResources(Environment environment) { - final Set resources = new HashSet<>(); - for (final Path[] paths : EnvironmentPluginResourceLocatorService.getPluginsPaths()) { - resources.add(new SecureJarPluginResource(this.name(), paths)); - } - return resources; - } - - private static List getPluginsPaths() { - final String env = System.getenv("SPONGE_PLUGINS"); - if (env == null) { - return Collections.emptyList(); - } - - List plugins = new ArrayList<>(); - for (final String entry : env.split(";")) { - if (entry.isBlank()) { - continue; - } - plugins.add(Stream.of(entry.split("&")).map(Path::of).toArray(Path[]::new)); - } - - return plugins; - } -} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java index d5aa68ed8a2..5fb7fc43e9f 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java @@ -44,7 +44,14 @@ public final class SecureJarPluginResource implements JVMPluginResource { private PluginJarMetadata pluginJarMetadata; private List> candidates; - public SecureJarPluginResource(final String locator, final Path... paths) { + public SecureJarPluginResource(final String locator, final Path[] paths) { + Objects.requireNonNull(locator, "locator"); + Objects.requireNonNull(paths, "paths"); + + if (paths.length == 0) { + throw new IllegalArgumentException("Need at least one path"); + } + this.locator = locator; this.jar = SecureJar.from(jar -> { if (ResourceType.of(jar) == ResourceType.PLUGIN) { diff --git a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService deleted file mode 100644 index 7af1564b674..00000000000 --- a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService +++ /dev/null @@ -1 +0,0 @@ -org.spongepowered.vanilla.applaunch.plugin.locator.EnvironmentPluginResourceLocatorService \ No newline at end of file From b7d95d045263b3b1d1c7303e7d699dfc4d3540d9 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Wed, 28 Aug 2024 22:52:47 +0200 Subject: [PATCH 201/226] Make TestEventManager compile --- .../org/spongepowered/common/test/TestEventManager.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/test/java/org/spongepowered/common/test/TestEventManager.java b/src/test/java/org/spongepowered/common/test/TestEventManager.java index 2f363d4202d..94a37a48fae 100644 --- a/src/test/java/org/spongepowered/common/test/TestEventManager.java +++ b/src/test/java/org/spongepowered/common/test/TestEventManager.java @@ -27,9 +27,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.manager.SpongeEventManager; import org.spongepowered.common.util.DefinableClassLoader; -import org.spongepowered.plugin.PluginContainer; - -import java.lang.invoke.MethodHandles; public class TestEventManager extends SpongeEventManager { @@ -42,9 +39,4 @@ public TestEventManager(final DefinableClassLoader loader) { public TestEventManager() { this.loader = null; } - - @Override - protected MethodHandles.@Nullable Lookup getLookup(PluginContainer plugin, Class handle) { - return this.loader == null ? null : this.loader.lookup(); - } } From ffa8f6f942e8abd84e8c5bbd349486cffae6e917 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Wed, 28 Aug 2024 22:59:05 +0200 Subject: [PATCH 202/226] Use a proper setter to define blackboard keys --- .../applaunch/plugin/VanillaPluginPlatform.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index 3e5d5be4e6d..4384e2886dd 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -74,7 +74,7 @@ public String version() { @Override public void setVersion(final String version) { - this.standardEnvironment.blackboard().getOrCreate(Keys.VERSION, () -> version); + this.standardEnvironment.blackboard().set(Keys.VERSION, version); } @Override @@ -89,7 +89,7 @@ public Path baseDirectory() { @Override public void setBaseDirectory(final Path baseDirectory) { - this.standardEnvironment.blackboard().getOrCreate(Keys.BASE_DIRECTORY, () -> baseDirectory); + this.standardEnvironment.blackboard().set(Keys.BASE_DIRECTORY, baseDirectory); } @Override @@ -99,7 +99,7 @@ public List pluginDirectories() { @Override public void setPluginDirectories(final List pluginDirectories) { - this.standardEnvironment.blackboard().getOrCreate(Keys.PLUGIN_DIRECTORIES, () -> pluginDirectories); + this.standardEnvironment.blackboard().set(Keys.PLUGIN_DIRECTORIES, pluginDirectories); } @Override @@ -109,7 +109,7 @@ public String metadataFilePath() { @Override public void setMetadataFilePath(final String metadataFilePath) { - this.standardEnvironment.blackboard().getOrCreate(Keys.METADATA_FILE_PATH, () -> metadataFilePath); + this.standardEnvironment.blackboard().set(Keys.METADATA_FILE_PATH, metadataFilePath); } public StandardEnvironment getStandardEnvironment() { @@ -140,8 +140,8 @@ public void initializeLanguageServices() { public void discoverLocatorServices() { final Blackboard blackboard = this.standardEnvironment.blackboard(); - blackboard.getOrCreate(JVMKeys.ENVIRONMENT_LOCATOR_VARIABLE_NAME, () -> "SPONGE_PLUGINS"); - blackboard.getOrCreate(JVMKeys.JVM_PLUGIN_RESOURCE_FACTORY, () -> SecureJarPluginResource::new); + blackboard.set(JVMKeys.ENVIRONMENT_LOCATOR_VARIABLE_NAME, "SPONGE_PLUGINS"); + blackboard.set(JVMKeys.JVM_PLUGIN_RESOURCE_FACTORY, SecureJarPluginResource::new); final ModuleLayer serviceLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.SERVICE)).orElseThrow(); final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(serviceLayer, PluginResourceLocatorService.class); From a390196b086b43208ad447f09902c41b7b3cf907 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 29 Aug 2024 17:14:59 +0200 Subject: [PATCH 203/226] Update verification metadata --- SpongeAPI | 2 +- .../impl/SpongeImplementationExtension.java | 2 +- gradle/verification-metadata.xml | 93 +++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 9c29c74cc4b..7dbba481242 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 9c29c74cc4bf767cf253c287969620185604a7ce +Subproject commit 7dbba48124270b3ac08f1d3a4d0d0391ad9c3019 diff --git a/build-logic/src/main/java/org/spongepowered/gradle/impl/SpongeImplementationExtension.java b/build-logic/src/main/java/org/spongepowered/gradle/impl/SpongeImplementationExtension.java index f591b8500cf..ca43cbd7d60 100644 --- a/build-logic/src/main/java/org/spongepowered/gradle/impl/SpongeImplementationExtension.java +++ b/build-logic/src/main/java/org/spongepowered/gradle/impl/SpongeImplementationExtension.java @@ -81,7 +81,7 @@ public void copyModulesExcludingProvided(final Configuration source, final Confi final String providedVersion = providedModuleVersions.get(module); if (providedVersion == null) { - ModuleDependency dep = (ModuleDependency) deps.create(id.getDisplayName()); + ModuleDependency dep = (ModuleDependency) deps.create(module.getGroup() + ":" + module.getName() + ":" + version); dep.setTransitive(false); target.getDependencies().add(dep); } else if (!providedVersion.equals(version)) { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e3db472c750..833c009222b 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -19,6 +19,7 @@ + @@ -490,6 +491,14 @@ + + + + + + + + @@ -527,6 +536,19 @@ + + + + + + + + + + + + + @@ -547,6 +569,11 @@ + + + + + @@ -1692,6 +1719,9 @@ + + + @@ -2516,6 +2546,9 @@ + + + @@ -2528,6 +2561,14 @@ + + + + + + + + @@ -2540,6 +2581,9 @@ + + + @@ -2564,6 +2608,9 @@ + + + @@ -3051,6 +3098,9 @@ + + + @@ -3063,6 +3113,14 @@ + + + + + + + + @@ -3071,6 +3129,14 @@ + + + + + + + + @@ -3115,6 +3181,9 @@ + + + @@ -3662,6 +3731,11 @@ + + + + + @@ -3697,6 +3771,14 @@ + + + + + + + + @@ -4079,6 +4161,14 @@ + + + + + + + + @@ -5837,6 +5927,9 @@ + + + From 3dd7f98a603545868b91b1cae782cfe390d3bf1f Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sat, 31 Aug 2024 21:03:12 +0200 Subject: [PATCH 204/226] Vanilla production jar on modern ModLauncher --- gradle/libs.versions.toml | 2 + gradle/verification-metadata.xml | 3 + vanilla/build.gradle.kts | 179 ++++++++++------- .../vanilla/applaunch/Constants.java | 1 - .../handler/AbstractVanillaLaunchHandler.java | 7 +- .../plugin/VanillaPluginPlatform.java | 2 +- .../plugin/VanillaTransformationService.java | 2 +- .../locator/GameResourceLocatorService.java | 90 +++++++++ .../PluginJarMetadata.java | 2 +- .../SecureJarPluginResource.java | 2 +- ...owered.plugin.PluginResourceLocatorService | 1 + .../vanilla/installer/Constants.java | 6 +- .../vanilla/installer/Agent.java | 172 ----------------- .../vanilla/installer/InstallerMain.java | 180 +++++++++++------- .../installer/LauncherCommandLine.java | 14 +- .../vanilla/installer/LibraryManager.java | 21 +- 16 files changed, 350 insertions(+), 334 deletions(-) create mode 100644 vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/GameResourceLocatorService.java rename vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/{locator => resource}/PluginJarMetadata.java (98%) rename vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/{locator => resource}/SecureJarPluginResource.java (98%) create mode 100644 vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService delete mode 100644 vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 599cabe41e9..04cb5d08c52 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ mixin = "0.8.7" bootstrap = "2.1.1" modlauncher = "10.2.1" securemodules = "2.2.20" +jarjar = "0.3.26" guava = "32.1.2-jre" mockito = "5.11.0" jline = "3.25.1" @@ -55,6 +56,7 @@ mockito-junitJupiter = { module = "org.mockito:mockito-junit-jupiter", version.r # vanilla forgeAutoRenamingTool = { module = "net.minecraftforge:ForgeAutoRenamingTool", version.ref = "forgeAutoRenamingTool" } +jarjar-fs = { module = "net.minecraftforge:JarJarFileSystems", version.ref = "jarjar" } jline-reader = { module = "org.jline:jline-reader", version.ref = "jline" } jline-terminal = { module = "org.jline:jline-terminal", version.ref = "jline" } jline-terminalJansi = { module = "org.jline:jline-terminal-jansi", version.ref = "jline" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 833c009222b..19e94e67917 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2482,6 +2482,9 @@ + + + diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index 66db7fdd3c5..ad08086299e 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -1,3 +1,5 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + plugins { id("org.spongepowered.gradle.vanilla") alias(libs.plugins.shadow) @@ -30,6 +32,7 @@ val gameLibrariesConfig: NamedDomainObjectProvider = configuratio val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameManagedLibraries") +val bootShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootShadedLibraries") val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameShadedLibraries") val runTaskOnlyConfig: NamedDomainObjectProvider = configurations.register("runTaskOnly") @@ -185,11 +188,11 @@ minecraft { dependsOn(applaunchOutputs) environment("MOD_CLASSES", applaunchOutputs.joinToString(";") { "applaunch%%$it" }) - // Configure GAME and LANG resources - val resources = mutableListOf() - resources.addAll(gameManagedLibrariesConfig.get().files.map { files(it) }) + // Configure resources + val gameResources = mutableListOf() + gameResources.addAll(gameManagedLibrariesConfig.get().files.map { files(it) }) - resources.add(files( + gameResources.add(files( main.get().output, vanillaMain.output, mixins.get().output, vanillaMixins.output, accessors.get().output, vanillaAccessors.output, @@ -197,12 +200,14 @@ minecraft { gameShadedLibrariesConfig.get() )) + dependsOn(gameResources) + jvmArgs("-Dsponge.gameResources=" + gameResources.joinToString(";") { it.joinToString("&") }) + testPluginsProject?.also { - resources.add(it.sourceSets.getByName("main").output) + val plugins: FileCollection = it.sourceSets.getByName("main").output + dependsOn(plugins) + environment("SPONGE_PLUGINS", plugins.joinToString("&")) } - - dependsOn(resources) - environment("SPONGE_PLUGINS", resources.joinToString(";") { it.joinToString("&") }) } } } @@ -237,32 +242,29 @@ dependencies { installer(platform(apiLibs.configurate.bom)) installer(apiLibs.configurate.hocon) installer(apiLibs.configurate.core) - installer(libs.configurate.jackson) installer(libs.joptSimple) installer(libs.tinylog.api) installer(libs.tinylog.impl) - // Override ASM versions, and explicitly declare dependencies so ASM is excluded from the manifest. - val asmExclusions = sequenceOf(libs.asm.asProvider(), libs.asm.commons, libs.asm.tree, libs.asm.analysis) - .onEach { - installer(it) - }.toSet() + + installer(libs.asm.commons) + installer(libs.asm.tree) installer(libs.forgeAutoRenamingTool) { exclude(group = "net.sf.jopt-simple") - asmExclusions.forEach { exclude(group = it.get().group, module = it.get().name) } // Use our own ASM version - } - - // Add the API as a runtime dependency, just so it gets shaded into the jar - add(vanillaInstaller.runtimeOnlyConfigurationName, "org.spongepowered:spongeapi:$apiVersion") { - isTransitive = false + exclude(group = "org.ow2.asm") } val init = initLibrariesConfig.name - init(libs.bootstrap) init(libs.securemodules) init(libs.asm.commons) init(libs.asm.util) + init(libs.jarjar.fs) val boot = bootLibrariesConfig.name + boot(libs.securemodules) + boot(libs.asm.commons) + boot(libs.asm.util) + boot(libs.bootstrap) + boot(libs.modlauncher) { exclude(group = "org.apache.logging.log4j") } @@ -270,7 +272,6 @@ dependencies { exclude(group = "org.checkerframework", module = "checker-qual") // exclude(group = "com.google.code.gson", module = "gson") exclude(group = "org.apache.logging.log4j", module = "log4j-api") - // exclude(group = "org.apache.commons", module = "commons-lang3") } boot(libs.lmaxDisruptor) boot(apiLibs.checkerQual) @@ -296,6 +297,10 @@ dependencies { exclude(group = "org.spongepowered", module = "configurate-core") exclude(group = "org.checkerframework", module = "checker-qual") } + boot(libs.configurate.jackson) { + exclude(group = "org.spongepowered", module = "configurate-core") + exclude(group = "org.checkerframework", module = "checker-qual") + } boot(libs.mixin) boot(libs.asm.tree) @@ -304,9 +309,11 @@ dependencies { exclude(group = "org.checkerframework", module = "checker-qual") } - boot("com.mojang:authlib:6.0.54") { - exclude(group = "com.google.guava", module = "guava") - } + // All minecraft deps except itself + configurations.minecraft.get().resolvedConfiguration.resolvedArtifacts + .map { it.id.componentIdentifier.toString() } + .filter { !it.startsWith("net.minecraft:joined") } + .forEach { boot(it) { isTransitive = false } } boot(project(transformersProject.path)) @@ -319,15 +326,14 @@ dependencies { exclude(group = "org.checkerframework", module = "checker-qual") } game(libs.javaxInject) - game(libs.configurate.jackson) { - exclude(group = "org.spongepowered", module = "configurate-core") - exclude(group = "org.checkerframework", module = "checker-qual") - } game(libs.adventure.serializerAnsi) { exclude(group = "org.jetbrains", module = "annotations") exclude(group = "org.checkerframework", module = "checker-qual") } + val bootShadedLibraries = bootShadedLibrariesConfig.name + bootShadedLibraries(project(transformersProject.path)) { isTransitive = false } + val gameShadedLibraries = gameShadedLibrariesConfig.name gameShadedLibraries("org.spongepowered:spongeapi:$apiVersion") { isTransitive = false } @@ -382,15 +388,12 @@ tasks { manifest{ from(vanillaManifest) attributes( - "Premain-Class" to "org.spongepowered.vanilla.installer.Agent", - "Agent-Class" to "org.spongepowered.vanilla.installer.Agent", - "Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent", - "Multi-Release" to true + "Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain", + "Multi-Release" to true ) } from(vanillaInstaller.output) } - val vanillaAppLaunchJar by registering(Jar::class) { archiveClassifier.set("applaunch") manifest.from(vanillaManifest) @@ -420,11 +423,16 @@ tasks { val installerResources = project.layout.buildDirectory.dir("generated/resources/installer") vanillaInstaller.resources.srcDir(installerResources) + val downloadNotNeeded = configurations.register("downloadNotNeeded") { + extendsFrom(configurations.minecraft.get()) + extendsFrom(gameShadedLibrariesConfig.get()) + } + val emitDependencies by registering(org.spongepowered.gradle.impl.OutputDependenciesToJson::class) { group = "sponge" this.dependencies("bootstrap", bootLibrariesConfig) this.dependencies("main", gameManagedLibrariesConfig) - this.excludedDependencies(gameShadedLibrariesConfig) + this.excludedDependencies(downloadNotNeeded) outputFile.set(installerResources.map { it.file("libraries.json") }) } @@ -432,54 +440,91 @@ tasks { dependsOn(emitDependencies) } - shadowJar { + val vanillaBootShadowJar by register("bootShadowJar", ShadowJar::class) { + group = "shadow" + archiveClassifier.set("boot") + mergeServiceFiles() + configurations = listOf(bootShadedLibrariesConfig.get()) + + manifest { + from(vanillaManifest) + attributes("Automatic-Module-Name" to "spongevanilla.boot") + } - configurations = listOf(project.configurations.getByName(vanillaInstaller.runtimeClasspathConfigurationName)) + from(commonProject.sourceSets.named("applaunch").map { it.output }) + from(vanillaAppLaunch.output) + } + + val installerShadowJar by register("installerShadowJar", ShadowJar::class) { + group = "shadow" + archiveClassifier.set("installer-shadow") + + mergeServiceFiles() + configurations = listOf(installerLibrariesConfig.get(), initLibrariesConfig.get()) + exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") - archiveClassifier.set("universal") manifest { - attributes(mapOf( - "Superclass-Transformer" to "common.superclasschange,vanilla.superclasschange", - "Access-Widener" to "common.accesswidener", - "MixinConfigs" to mixinConfigs.joinToString(","), - "Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain", - "Launch-Target" to "sponge_server_prod", - "Multi-Release" to true, - "Premain-Class" to "org.spongepowered.vanilla.installer.Agent", - "Agent-Class" to "org.spongepowered.vanilla.installer.Agent", - "Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent" - )) + from(vanillaManifest) attributes( - mapOf("Implementation-Version" to libs.versions.asm.get()), - "org/objectweb/asm/" + "Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain", + "Automatic-Module-Name" to "spongevanilla.installer", + "Launch-Target" to "sponge_server_prod", + "Multi-Release" to true ) + attributes(mapOf("Implementation-Version" to libs.versions.asm.get()), "org/objectweb/asm/") + } + + from(vanillaInstaller.output) + } + + shadowJar { + group = "shadow" + archiveClassifier.set("mod") + + mergeServiceFiles() + configurations = listOf(gameShadedLibrariesConfig.get()) + + manifest { from(vanillaManifest) + attributes( + "Superclass-Transformer" to "common.superclasschange,vanilla.superclasschange", + "Access-Widener" to "common.accesswidener", + "MixinConfigs" to mixinConfigs.joinToString(","), + "Multi-Release" to true + ) } + from(commonProject.sourceSets.main.map { it.output }) - from(commonProject.sourceSets.named("mixins").map {it.output }) - from(commonProject.sourceSets.named("accessors").map {it.output }) - from(commonProject.sourceSets.named("launch").map {it.output }) - from(commonProject.sourceSets.named("applaunch").map {it.output }) - from(sourceSets.main.map {it.output }) - from(vanillaInstaller.output) - from(vanillaAppLaunch.output) + from(commonProject.sourceSets.named("mixins").map { it.output }) + from(commonProject.sourceSets.named("accessors").map { it.output }) + from(commonProject.sourceSets.named("launch").map { it.output }) + from(vanillaLaunch.output) from(vanillaAccessors.output) from(vanillaMixins.output) - /*dependencies { - // include(project(":")) - include("org.spongepowered:spongeapi:$apiVersion") - } */ + } + + val universalJar = register("universalJar", Jar::class) { + group = "build" + archiveClassifier.set("universal") + + manifest.from(installerShadowJar.manifest) + + from(installerShadowJar.archiveFile.map { zipTree(it) }) + + into("jars") { + from(shadowJar) + rename("spongevanilla-(.*)-mod.jar", "spongevanilla-mod.jar") - // We cannot have modules in a shaded jar - exclude("META-INF/versions/*/module-info.class") - exclude("module-info.class") + from(vanillaBootShadowJar) + rename("spongevanilla-(.*)-boot.jar", "spongevanilla-boot.jar") + } } + assemble { - dependsOn(shadowJar) + dependsOn(universalJar) } - } indraSpotlessLicenser { diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java index d133eccd84c..969dea1eb7c 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/Constants.java @@ -28,7 +28,6 @@ public final class Constants { public static final class ManifestAttributes { public static final String ACCESS_WIDENER = "Access-Widener"; - public static final String LAUNCH_TARGET = "Launch-Target"; public static final String SUPERCLASS_CHANGE = "Superclass-Transformer"; } } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java index e830a6ddf6e..269bf6c5ea9 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/handler/AbstractVanillaLaunchHandler.java @@ -30,6 +30,8 @@ import org.apache.logging.log4j.Logger; import org.spongepowered.vanilla.applaunch.AppLaunchTarget; +import java.util.NoSuchElementException; + /** * The common Sponge {@link ILaunchHandlerService launch handler} for development * and production environments. @@ -45,7 +47,10 @@ public String name() { @Override public ServiceRunner launchService(final String[] arguments, final ModuleLayer gameLayer) { this.logger.info("Transitioning to Sponge launch, please wait..."); - return () -> this.launchSponge(gameLayer.findModule("spongevanilla").orElseThrow(), arguments); + return () -> { + final Module module = gameLayer.findModule("spongevanilla").orElseThrow(() -> new NoSuchElementException("Module spongevanilla")); + this.launchSponge(module, arguments); + }; } public abstract AppLaunchTarget target(); diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index 4384e2886dd..834760ddb9e 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -36,7 +36,7 @@ import org.spongepowered.plugin.blackboard.Keys; import org.spongepowered.plugin.builtin.StandardEnvironment; import org.spongepowered.plugin.builtin.jvm.JVMKeys; -import org.spongepowered.vanilla.applaunch.plugin.locator.SecureJarPluginResource; +import org.spongepowered.vanilla.applaunch.plugin.resource.SecureJarPluginResource; import java.nio.file.Path; import java.util.Collections; diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java index 6c9aa0135dc..c2d44a79c6f 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java @@ -43,7 +43,7 @@ import org.spongepowered.transformers.modlauncher.AccessWidenerTransformationService; import org.spongepowered.transformers.modlauncher.SuperclassChanger; import org.spongepowered.vanilla.applaunch.Constants; -import org.spongepowered.vanilla.applaunch.plugin.locator.SecureJarPluginResource; +import org.spongepowered.vanilla.applaunch.plugin.resource.SecureJarPluginResource; import java.io.IOException; import java.nio.file.Files; diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/GameResourceLocatorService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/GameResourceLocatorService.java new file mode 100644 index 00000000000..0a1791fb459 --- /dev/null +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/GameResourceLocatorService.java @@ -0,0 +1,90 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.applaunch.plugin.locator; + +import org.spongepowered.plugin.Environment; +import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; +import org.spongepowered.plugin.builtin.jvm.locator.JVMPluginResourceLocatorService; + +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public final class GameResourceLocatorService implements JVMPluginResourceLocatorService { + + @Override + public String name() { + return "game"; + } + + @Override + public Set locatePluginResources(final Environment environment) { + environment.logger().info("Locating '{}' resources...", this.name()); + + final Set resources = new HashSet<>(); + final String resourcesProp = System.getProperty("sponge.gameResources"); + if (resourcesProp != null) { + for (final String entry : resourcesProp.split(";")) { + if (entry.isBlank()) { + continue; + } + + final Path[] paths = Stream.of(entry.split("&")).map(Path::of).toArray(Path[]::new); + resources.add(JVMPluginResource.create(environment, this.name(), paths)); + } + } + + final String fsProp = System.getProperty("sponge.rootJarFS"); + if (fsProp != null) { + try { + final FileSystem fs = FileSystems.getFileSystem(new URI(fsProp)); + final Path spongeMod = newJarInJar(fs.getPath("jars", "spongevanilla-mod.jar")); + resources.add(JVMPluginResource.create(environment, this.name(), spongeMod)); + } catch (final Exception e) { + environment.logger().error("Failed to locate spongevanilla-mod jar."); + } + } + + environment.logger().info("Located [{}] resource(s) for '{}'...", resources.size(), this.name()); + + return resources; + } + + private static Path newJarInJar(final Path jar) { + try { + URI jij = new URI("jij:" + jar.toAbsolutePath().toUri().getRawSchemeSpecificPart()).normalize(); + final Map env = Map.of("packagePath", jar); + FileSystem jijFS = FileSystems.newFileSystem(jij, env); + return jijFS.getPath("/"); // root of the archive to load + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java similarity index 98% rename from vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java rename to vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java index ff80fbb80f5..6c19e2e2daf 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/PluginJarMetadata.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.vanilla.applaunch.plugin.locator; +package org.spongepowered.vanilla.applaunch.plugin.resource; import cpw.mods.jarhandling.JarMetadata; import cpw.mods.jarhandling.SecureJar; diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java similarity index 98% rename from vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java rename to vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java index 5fb7fc43e9f..d06c90af96a 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/locator/SecureJarPluginResource.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.vanilla.applaunch.plugin.locator; +package org.spongepowered.vanilla.applaunch.plugin.resource; import cpw.mods.jarhandling.JarMetadata; import cpw.mods.jarhandling.SecureJar; diff --git a/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService new file mode 100644 index 00000000000..330fcb92be8 --- /dev/null +++ b/vanilla/src/applaunch/resources/META-INF/services/org.spongepowered.plugin.PluginResourceLocatorService @@ -0,0 +1 @@ +org.spongepowered.vanilla.applaunch.plugin.locator.GameResourceLocatorService \ No newline at end of file diff --git a/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java b/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java index 0cba3447553..c7a1027467f 100644 --- a/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java +++ b/vanilla/src/installer/java-templates/org/spongepowered/vanilla/installer/Constants.java @@ -24,8 +24,6 @@ */ package org.spongepowered.vanilla.installer; -import org.objectweb.asm.Opcodes; - public final class Constants { public static final class Libraries { @@ -40,4 +38,8 @@ public static final class Libraries { public static final String SPONGE_NEXUS_DOWNLOAD_URL = "https://repo.spongepowered.org/service/rest/v1/search/assets?md5=%s&maven" + ".groupId=%s&maven.artifactId=%s&maven.baseVersion=%s&maven.extension=jar"; } + + public static final class ManifestAttributes { + public static final String LAUNCH_TARGET = "Launch-Target"; + } } diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java deleted file mode 100644 index 59b62592420..00000000000 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.vanilla.installer; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.tinylog.Logger; - -import java.io.File; -import java.io.IOException; -import java.lang.instrument.Instrumentation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarFile; -import java.util.jar.Manifest; - -/** - * Agent, used to add downloaded jars to the system classpath and open modules - * for deep reflection. - * - *

This needs to be compiled for exactly java 9, since it runs before we have - * an opportunity to provide a friendly warning message.

- */ -public class Agent { - - private static Instrumentation instrumentation; - private static boolean usingFallback; - - public static void premain(final String agentArgs, final Instrumentation instrumentation) { - Agent.instrumentation = instrumentation; - } - - public static void agentmain(final String agentArgs, final Instrumentation instrumentation) { - Agent.instrumentation = instrumentation; - } - - static void addJarToClasspath(final Path jar) { - if (Agent.instrumentation == null) { - throw new IllegalStateException("The SpongeVanilla jar must be run as a java agent in order to add downloaded libraries to the classpath!"); - } - try { - final Path normalized = Paths.get(jar.toRealPath().toUri().toURL().toURI()); - - if (Agent.usingFallback) { - Fallback.addToSystemClasspath(jar); - return; - } - - try { - // x.X The URL escaping done by appendToSystemClassLoaderSearch differs from the - try (final JarFile jf = new JarFile(new File(normalized.toUri()))) { - Agent.instrumentation.appendToSystemClassLoaderSearch(jf); - } - } catch (final IllegalArgumentException ex) { - // For some reason, the Agent method on Windows can't handle some non-ASCII characters - // This is fairly awful, but it makes things work (and hopefully won't be reached often) - Logger.debug(ex, "Failed to add library {} to classpath, transitioning to fallback (more unsafe!) method", jar); - Agent.usingFallback = true; - Fallback.addToSystemClasspath(jar); - } - } catch (final IOException | URISyntaxException ex) { - Logger.error(ex, "Failed to create jar file for archive '{}'!", jar); - } - } - - static void crackModules() { - final Set systemUnnamed = Set.of(ClassLoader.getSystemClassLoader().getUnnamedModule()); - Agent.instrumentation.redefineModule( - Manifest.class.getModule(), - Set.of(), - Map.of("sun.security.util", systemUnnamed), // ModLauncher - Map.of( - // ModLauncher -- needs Manifest.jv, and various JarVerifier methods - "java.util.jar", systemUnnamed - ), - Set.of(), - Map.of() - ); - } - - static final class Fallback { - - private static final Object SYSTEM_CLASS_PATH; /* a URLClassPath */ - private static final Method ADD_URL; /* URLClassPath.addURL(java.net.URL) */ - - static { - Logger.debug("Initializing fallback classpath modification. This is only expected when using non-ASCII characters in file paths on Windows"); - // Crack the java.base module to allow us to use reflection - final Set systemUnnamed = Set.of(ClassLoader.getSystemClassLoader().getUnnamedModule()); - Agent.instrumentation.redefineModule( - ClassLoader.class.getModule(), /* java.base */ - Set.of(), - Map.of("jdk.internal.loader", systemUnnamed), - Map.of("jdk.internal.loader", systemUnnamed), - Set.of(), - Map.of() - ); - - final ClassLoader loader = ClassLoader.getSystemClassLoader(); - - Field ucp = Fallback.fieldOrNull(loader.getClass(), "ucp"); - if (ucp == null) { - ucp = Fallback.fieldOrNull(loader.getClass().getSuperclass(), "ucp"); - } - - if (ucp == null) { - // Did they change something? - throw new ExceptionInInitializerError("Unable to initialize fallback classpath handling on your system. Perhaps try a different Java version?"); - } - - try { - SYSTEM_CLASS_PATH = ucp.get(loader); - ADD_URL = Fallback.SYSTEM_CLASS_PATH.getClass().getDeclaredMethod("addURL", URL.class); - } catch (final NoSuchMethodException | IllegalAccessException ex) { - throw new ExceptionInInitializerError(ex); - } - } - - private static @Nullable Field fieldOrNull(final @Nullable Class clazz, final String name) { - if (clazz == null) { - return null; - } - - try { - final Field f = clazz.getDeclaredField(name); - f.setAccessible(true); - return f; - } catch (final NoSuchFieldException ex) { - return null; - } - } - - static void addToSystemClasspath(final Path file) { - try { - Fallback.ADD_URL.invoke(Fallback.SYSTEM_CLASS_PATH, file.toUri().toURL()); - } catch (final IllegalAccessException | InvocationTargetException | IOException ex) { - Logger.error(ex, "Failed to add file {} to the system classpath", file); - throw new RuntimeException(ex); - } - } - - } - -} diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java index 3e6f96caa00..992785c98d9 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java @@ -43,9 +43,14 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; import java.net.URL; +import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.file.AccessDeniedException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -63,12 +68,13 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; public final class InstallerMain { - private static final String COLLECTION_BOOTSTRAP = "bootstrap"; // goes on app - private static final String COLLECTION_MAIN = "main"; // goes on TCL + private static final String COLLECTION_BOOTSTRAP = "bootstrap"; // boot layer + private static final String COLLECTION_MAIN = "main"; // game layer private static final int MAX_TRIES = 2; private final Installer installer; @@ -126,41 +132,72 @@ public void downloadAndRun() throws Exception { } assert remappedMinecraftJar != null; // always assigned or thrown - // MC itself and mojang dependencies are on the main layer, other libs are only on the bootstrap layer + // Minecraft itself is on the main layer libraryManager.addLibrary(InstallerMain.COLLECTION_MAIN, new LibraryManager.Library("minecraft", remappedMinecraftJar.server())); - for (final Map.Entry library : remappedMinecraftJar.libraries().entrySet()) { - if (library.getKey().group().equals("com.mojang") || library.getKey().group().equals("net.minecraft")) { - libraryManager.addLibrary(InstallerMain.COLLECTION_MAIN, new LibraryManager.Library(library.getKey().toString(), library.getValue())); - } else { - libraryManager.addLibrary(InstallerMain.COLLECTION_BOOTSTRAP, new LibraryManager.Library(library.getKey().toString(), library.getValue())); - } + + // Other libs are on the bootstrap layer + for (final Map.Entry entry : remappedMinecraftJar.libraries().entrySet()) { + final GroupArtifactVersion artifact = entry.getKey(); + final Path path = entry.getValue(); + + libraryManager.addLibrary(InstallerMain.COLLECTION_BOOTSTRAP, new LibraryManager.Library(artifact.toString(), path)); } + this.installer.getLibraryManager().finishedProcessing(); Logger.info("Environment has been verified."); final Set seenLibs = new HashSet<>(); - this.installer.getLibraryManager().getAll(InstallerMain.COLLECTION_BOOTSTRAP).stream() - .peek(lib -> seenLibs.add(lib.getName())) - .map(LibraryManager.Library::getFile) - .forEach(path -> { - Logger.debug("Adding jar {} to bootstrap classpath", path); - Agent.addJarToClasspath(path); - }); - - final Path[] transformableLibs = this.installer.getLibraryManager().getAll(InstallerMain.COLLECTION_MAIN).stream() - .filter(lib -> !seenLibs.contains(lib.getName())) - .map(LibraryManager.Library::getFile) + final Path[] bootLibs = this.installer.getLibraryManager().getAll(InstallerMain.COLLECTION_BOOTSTRAP).stream() + .peek(lib -> seenLibs.add(lib.name())) + .map(LibraryManager.Library::file) .toArray(Path[]::new); + final Path[] gameLibs = this.installer.getLibraryManager().getAll(InstallerMain.COLLECTION_MAIN).stream() + .filter(lib -> !seenLibs.contains(lib.name())) + .map(LibraryManager.Library::file) + .toArray(Path[]::new); + + final URL rootJar = InstallerMain.class.getProtectionDomain().getCodeSource().getLocation(); + final URI fsURI = new URI("jar", rootJar.toString(), null); + System.setProperty("sponge.rootJarFS", fsURI.toString()); + + final FileSystem fs = FileSystems.newFileSystem(fsURI, Map.of()); + final Path spongeBoot = newJarInJar(fs.getPath("jars", "spongevanilla-boot.jar")); + + String launchTarget = LauncherCommandLine.launchTarget; + if (launchTarget == null) { + final Path manifestFile = fs.getPath("META-INF", "MANIFEST.MF"); + try (final InputStream stream = Files.newInputStream(manifestFile)) { + final Manifest manifest = new Manifest(stream); + launchTarget = manifest.getMainAttributes().getValue(Constants.ManifestAttributes.LAUNCH_TARGET); + } + } + + final StringBuilder gameLibsEnv = new StringBuilder(); + for (final Path lib : gameLibs) { + gameLibsEnv.append(lib.toAbsolutePath()).append(';'); + } + gameLibsEnv.setLength(gameLibsEnv.length() - 1); + System.setProperty("sponge.gameResources", gameLibsEnv.toString()); + final List gameArgs = new ArrayList<>(LauncherCommandLine.remainingArgs); + gameArgs.add("--launchTarget"); + gameArgs.add(launchTarget); Collections.addAll(gameArgs, this.installer.getLauncherConfig().args.split(" ")); - // Suppress illegal reflection warnings on newer java - Agent.crackModules(); + InstallerMain.bootstrap(bootLibs, spongeBoot, gameArgs.toArray(new String[0])); + } - final String className = "org.spongepowered.vanilla.applaunch.Main"; - InstallerMain.invokeMain(className, gameArgs.toArray(new String[0]), transformableLibs); + private static Path newJarInJar(final Path jar) { + try { + URI jij = new URI("jij:" + jar.toAbsolutePath().toUri().getRawSchemeSpecificPart()).normalize(); + final Map env = Map.of("packagePath", jar); + FileSystem jijFS = FileSystems.newFileSystem(jij, env); + return jijFS.getPath("/"); // root of the archive to load + } catch (Exception e) { + throw new RuntimeException(e); + } } private ServerAndLibraries recoverFromMinecraftDownloadError(final T ex) throws T { @@ -175,17 +212,33 @@ private ServerAndLibraries recoverFromMinecraftDownloadErr } } - private static void invokeMain(final String className, final String[] args, final Path[] extraCpEntries) { + private static void bootstrap(final Path[] bootLibs, final Path spongeBoot, final String[] args) throws Exception { + final URL[] urls = new URL[bootLibs.length]; + for (int i = 0; i < bootLibs.length; i++) { + urls[i] = bootLibs[i].toAbsolutePath().toUri().toURL(); + } + + final List classpath = new ArrayList<>(); + for (final Path lib : bootLibs) { + classpath.add(new Path[] { lib }); + } + classpath.add(new Path[] { spongeBoot }); + + URLClassLoader loader = new URLClassLoader(urls, ClassLoader.getPlatformClassLoader()); + ClassLoader previousLoader = Thread.currentThread().getContextClassLoader(); try { - Class.forName(className) - .getMethod("main", String[].class, Path[].class) - .invoke(null, args, extraCpEntries); - } catch (final InvocationTargetException ex) { - Logger.error(ex.getCause(), "Failed to invoke main class {} due to an error", className); - System.exit(1); - } catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException ex) { - Logger.error(ex, "Failed to invoke main class {} due to an error", className); + Thread.currentThread().setContextClassLoader(loader); + final Class cl = Class.forName("net.minecraftforge.bootstrap.Bootstrap", false, loader); + final Object instance = cl.getDeclaredConstructor().newInstance(); + final Method m = cl.getDeclaredMethod("bootstrapMain", String[].class, List.class); + m.setAccessible(true); + m.invoke(instance, args, classpath); + } catch (final Exception ex) { + final Throwable cause = ex instanceof InvocationTargetException ? ex.getCause() : ex; + Logger.error(cause, "Failed to invoke bootstrap main due to an error"); System.exit(1); + } finally { + Thread.currentThread().setContextClassLoader(previousLoader); } } @@ -391,47 +444,46 @@ private ServerAndLibraries remapMinecraft(final ServerAndLibraries minecraft, fi final Renamer.Builder renamerBuilder = Renamer.builder() .add(Transformer.parameterAnnotationFixerFactory()) .add(ctx -> { - final Transformer backing = Transformer.renamerFactory(mappings, false).create(ctx); - return new Transformer() { - - @Override - public ClassEntry process(final ClassEntry entry) { - final String name = entry.getName(); - if (name.startsWith("it/unimi") - || name.startsWith("com/google") - || name.startsWith("com/mojang/datafixers") - || name.startsWith("com/mojang/brigadier") - || name.startsWith("org/apache")) { - return entry; + final Transformer backing = Transformer.renamerFactory(mappings, false).create(ctx); + return new Transformer() { + @Override + public ClassEntry process(final ClassEntry entry) { + final String name = entry.getName(); + if (name.startsWith("it/unimi") + || name.startsWith("com/google") + || name.startsWith("com/mojang/datafixers") + || name.startsWith("com/mojang/brigadier") + || name.startsWith("org/apache")) { + return entry; + } + return backing.process(entry); } - return backing.process(entry); - } - - @Override - public ManifestEntry process(final ManifestEntry entry) { - return backing.process(entry); - } - @Override - public ResourceEntry process(final ResourceEntry entry) { - return backing.process(entry); - } + @Override + public ManifestEntry process(final ManifestEntry entry) { + return backing.process(entry); + } - @Override - public Collection getExtras() { - return backing.getExtras(); - } + @Override + public ResourceEntry process(final ResourceEntry entry) { + return backing.process(entry); + } - }; + @Override + public Collection getExtras() { + return backing.getExtras(); + } + }; }) .add(Transformer.recordFixerFactory()) .add(Transformer.parameterAnnotationFixerFactory()) .add(Transformer.sourceFixerFactory(SourceFixerConfig.JAVA)) .add(Transformer.signatureStripperFactory(SignatureStripperConfig.ALL)) .logger(Logger::debug); // quiet - try (final Renamer ren = renamerBuilder.build()) { - ren.run(minecraft.server.toFile(), tempOutput.toFile()); - } + + try (final Renamer ren = renamerBuilder.build()) { + ren.run(minecraft.server.toFile(), tempOutput.toFile()); + } // Restore file try { diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LauncherCommandLine.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LauncherCommandLine.java index f52c34a3169..89cc81e3075 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LauncherCommandLine.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LauncherCommandLine.java @@ -39,12 +39,16 @@ public final class LauncherCommandLine { private static final OptionParser PARSER = new OptionParser(); - private static final ArgumentAcceptingOptionSpec INSTALLER_DIRECTORY_ARG = LauncherCommandLine.PARSER.accepts("installerDir", - "Alternative installer directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)) + private static final ArgumentAcceptingOptionSpec INSTALLER_DIRECTORY_ARG = LauncherCommandLine.PARSER + .accepts("installerDir", "Alternative installer directory").withRequiredArg() + .withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)) .defaultsTo(Paths.get(".")); - private static final ArgumentAcceptingOptionSpec LIBRARIES_DIRECTORY_ARG = LauncherCommandLine.PARSER.accepts("librariesDir", - "Alternative libraries directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)) + private static final ArgumentAcceptingOptionSpec LIBRARIES_DIRECTORY_ARG = LauncherCommandLine.PARSER + .accepts("librariesDir", "Alternative libraries directory").withRequiredArg() + .withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)) .defaultsTo(Paths.get("libraries")); + private static final ArgumentAcceptingOptionSpec LAUNCH_TARGET_ARG = LauncherCommandLine.PARSER + .accepts("launchTarget", "Launch target").withRequiredArg(); private static final NonOptionArgumentSpec REMAINDER = LauncherCommandLine.PARSER.nonOptions().ofType(String.class); static { @@ -52,6 +56,7 @@ public final class LauncherCommandLine { } public static Path installerDirectory, librariesDirectory; + public static String launchTarget; public static List remainingArgs; private LauncherCommandLine() { @@ -61,6 +66,7 @@ public static void configure(final String[] args) { final OptionSet options = LauncherCommandLine.PARSER.parse(args); LauncherCommandLine.installerDirectory = options.valueOf(LauncherCommandLine.INSTALLER_DIRECTORY_ARG); LauncherCommandLine.librariesDirectory = options.valueOf(LauncherCommandLine.LIBRARIES_DIRECTORY_ARG); + LauncherCommandLine.launchTarget = options.valueOf(LauncherCommandLine.LAUNCH_TARGET_ARG); LauncherCommandLine.remainingArgs = UnmodifiableCollections.copyOf(options.valuesOf(LauncherCommandLine.REMAINDER)); } } diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LibraryManager.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LibraryManager.java index c7147a310fd..8c939f4c4e9 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LibraryManager.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/LibraryManager.java @@ -87,7 +87,7 @@ public Set getAll(final String collection) { return Collections.unmodifiableSet(this.libraries.getOrDefault(collection, Collections.emptySet())); } - protected void addLibrary(final String set, final Library library) { + void addLibrary(final String set, final Library library) { this.libraries.computeIfAbsent(set, $ -> Collections.synchronizedSet(new LinkedHashSet<>())).add(library); } @@ -244,24 +244,7 @@ public void finishedProcessing() { } } - public static class Library { - - private final String name; - private final Path file; - - public Library(final String name, final Path file) { - this.name = name; - this.file = file; - } - - public String getName() { - return this.name; - } - - public Path getFile() { - return this.file; - } - } + public record Library(String name, Path file) {} private static String asId(final Dependency dep) { return dep.group + ':' + dep.module + ':' + dep.version; From 7262cde637e79ec7e0dde8430037cf04e9a3dc2d Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 1 Sep 2024 16:55:03 +0200 Subject: [PATCH 205/226] Exclude versioned module-info in shadow jars --- forge/build.gradle.kts | 2 +- vanilla/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index f513ad15071..e3c75af6d4c 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -355,7 +355,7 @@ tasks { mergeServiceFiles() configurations = listOf(serviceShadedLibrariesConfig.get()) - exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") + exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "**/module-info.class") manifest { attributes("Automatic-Module-Name" to "spongeforge.services") diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index ad08086299e..a83e493c207 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -462,7 +462,7 @@ tasks { mergeServiceFiles() configurations = listOf(installerLibrariesConfig.get(), initLibrariesConfig.get()) - exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") + exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "**/module-info.class") manifest { from(vanillaManifest) From d46e1251ec63b7584f930d00da8094f87e8d7d60 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 1 Sep 2024 18:07:54 +0200 Subject: [PATCH 206/226] Workaround to support dash in plugin ids. Add a deprecation warning. --- .../loading/metadata/PluginMetadataUtils.java | 49 +++++++++++++++++-- .../loading/moddiscovery/ModFileParsers.java | 3 +- .../provider/JavaPluginLanguageProvider.java | 6 ++- .../plugin/resource/PluginJarMetadata.java | 8 +-- .../launch/plugin/VanillaPluginManager.java | 15 ++++-- 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/metadata/PluginMetadataUtils.java b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/metadata/PluginMetadataUtils.java index 1ffd3c8c854..c0372bcfae5 100644 --- a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/metadata/PluginMetadataUtils.java +++ b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/metadata/PluginMetadataUtils.java @@ -26,7 +26,10 @@ import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import net.minecraftforge.forgespi.language.IModInfo; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.plugin.metadata.PluginMetadata; +import org.spongepowered.plugin.metadata.builtin.MetadataContainer; import org.spongepowered.plugin.metadata.builtin.StandardPluginMetadata; import org.spongepowered.plugin.metadata.builtin.model.StandardPluginContributor; import org.spongepowered.plugin.metadata.builtin.model.StandardPluginDependency; @@ -34,12 +37,52 @@ import org.spongepowered.plugin.metadata.model.PluginDependency; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; -/** - * ModInfo cannot be mixed into as it is on the app class loader so this somewhat hacky util class will do... - */ public final class PluginMetadataUtils { + private static final Set invalidPluginIds = new HashSet<>(); + + public static MetadataContainer fixPluginIds(final MetadataContainer container) { + boolean modified = false; + final List metadata = new ArrayList<>(); + + for (final PluginMetadata plugin : container.metadata()) { + final String id = plugin.id(); + if (id.indexOf('-') >= 0) { + final String newId = id.replace('-', '_'); + if (PluginMetadataUtils.invalidPluginIds.add(id)) { + AppLaunch.pluginPlatform().logger().warn("The dash character (-) is no longer supported in plugin ids.\n" + + "Plugin {} will be loaded as {}. If you are the developer of this plugin, please change the id.", id, newId); + } + + final StandardPluginMetadata.Builder pluginBuilder = StandardPluginMetadata.builder() + .from((StandardPluginMetadata) plugin).id(newId).entrypoint(plugin.entrypoint()); + plugin.name().ifPresent(pluginBuilder::name); + plugin.description().ifPresent(pluginBuilder::description); + + metadata.add(pluginBuilder.build()); + modified = true; + } else { + metadata.add((StandardPluginMetadata) plugin); + } + } + + if (!modified) { + return container; + } + + final MetadataContainer.Builder builder = container.toBuilder(); + builder.metadata(metadata); + + try { + return builder.build(); + } catch (InvalidVersionSpecificationException e) { + // This should not happen since we never modify the version. + throw new RuntimeException(e); + } + } public static PluginMetadata modToPlugin(final ModInfo info) { final StandardPluginMetadata.Builder builder = StandardPluginMetadata.builder(); diff --git a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/ModFileParsers.java b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/ModFileParsers.java index de41a11126b..ad1972b3226 100644 --- a/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/ModFileParsers.java +++ b/forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/ModFileParsers.java @@ -35,6 +35,7 @@ import org.spongepowered.common.applaunch.AppLaunch; import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants; import org.spongepowered.forge.applaunch.loading.metadata.PluginFileConfigurable; +import org.spongepowered.forge.applaunch.loading.metadata.PluginMetadataUtils; import org.spongepowered.plugin.metadata.builtin.MetadataContainer; import org.spongepowered.plugin.metadata.builtin.MetadataParser; @@ -73,7 +74,7 @@ public static IModFileInfo parsePluginMetadata(final IModFile iModFile) { container = MetadataParser.read(reader); } - final PluginFileConfigurable config = new PluginFileConfigurable(container); + final PluginFileConfigurable config = new PluginFileConfigurable(PluginMetadataUtils.fixPluginIds(container)); return new ModFileInfo(modFile, config, (info) -> {}, List.of()); } catch (final Exception e) { AppLaunch.logger().warn("Could not read metadata for plugin file '{}'", modFile, e); diff --git a/forge/src/lang/java/org/spongepowered/forge/lang/provider/JavaPluginLanguageProvider.java b/forge/src/lang/java/org/spongepowered/forge/lang/provider/JavaPluginLanguageProvider.java index 5bdcef45012..5b5b7af6e68 100644 --- a/forge/src/lang/java/org/spongepowered/forge/lang/provider/JavaPluginLanguageProvider.java +++ b/forge/src/lang/java/org/spongepowered/forge/lang/provider/JavaPluginLanguageProvider.java @@ -63,12 +63,16 @@ public Consumer getFileVisitor() { final Map modTargetMap = scanResult.getAnnotations().stream() .filter(ad -> ad.annotationType().equals(JavaPluginLanguageProvider.PLUGIN_ANNOTATION)) .peek(ad -> this.logger.debug(Logging.SCAN, "Found @Plugin class {} with id {}", ad.clazz().getClassName(), ad.annotationData().get("value"))) - .map(ad -> new PluginTarget(ad.clazz().getClassName(), (String)ad.annotationData().get("value"))) + .map(ad -> new PluginTarget(ad.clazz().getClassName(), JavaPluginLanguageProvider.fixPluginId((String) ad.annotationData().get("value")))) .collect(Collectors.toMap(PluginTarget::getPlugin, Function.identity(), (a,b)->a)); scanResult.addLanguageLoader(modTargetMap); }; } + private static String fixPluginId(final String id) { + return id.replace('-', '_'); + } + private static final class PluginTarget implements IModLanguageProvider.IModLanguageLoader { private final Logger logger; diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java index 6c19e2e2daf..31a5850c88b 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/PluginJarMetadata.java @@ -39,6 +39,7 @@ public class PluginJarMetadata implements JarMetadata { private PluginMetadata plugin; private JarMetadata fallback; + private String name; private ModuleDescriptor descriptor; public PluginJarMetadata(final SecureJar jar, final Path[] paths) { @@ -53,8 +54,10 @@ public void init(final PluginMetadata plugin) { this.initialized = true; if (plugin == null) { this.fallback = JarMetadata.from(this.jar, this.paths); + this.name = this.fallback.name(); } else { this.plugin = plugin; + this.name = this.plugin.id().replace('-', '_'); } } @@ -67,10 +70,7 @@ private void checkInitialized() { @Override public String name() { checkInitialized(); - if (this.plugin == null) { - return this.fallback.name(); - } - return this.plugin.id(); + return this.name; } @Override diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java index c27758532cb..c1d8bb84820 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java @@ -114,14 +114,20 @@ public void loadPlugins(final VanillaPluginPlatform platform) { final Map, String> consequentialFailedInstances = new HashMap<>(); final ClassLoader launchClassloader = VanillaLaunch.instance().getClass().getClassLoader(); for (final PluginCandidate candidate : resolutionResult.sortedSuccesses()) { - final PluginContainer plugin = this.plugins.get(candidate.metadata().id()); + final String id = candidate.metadata().id(); + if (id.indexOf('-') >= 0) { + platform.logger().warn("The dash character (-) is no longer supported in plugin ids.\n" + + "Plugin {} is still using it. If you are the developer of this plugin, please change the id.", id); + } + + final PluginContainer plugin = this.plugins.get(id); if (plugin != null) { if (plugin instanceof VanillaDummyPluginContainer) { continue; } // If we get here, we screwed up - duplicate IDs should have been detected earlier. // Place it in the resolution result... it'll then get picked up in the big error message - resolutionResult.duplicateIds().add(candidate.metadata().id()); + resolutionResult.duplicateIds().add(id); // but this is our screw up, let's also make a big point of it final PrettyPrinter prettyPrinter = new PrettyPrinter(120) @@ -129,8 +135,7 @@ public void loadPlugins(final VanillaPluginPlatform platform) { .hr() .addWrapped("Sponge attempted to create a second plugin with ID '%s'. This is not allowed - all plugins must have a unique " + "ID. Usually, Sponge will catch this earlier -- but in this case Sponge has validated two plugins with " - + "the same ID. Please report this error to Sponge.", - candidate.metadata().id()) + + "the same ID. Please report this error to Sponge.", id) .add() .add("Technical Details:") .add("Plugins to load:", 4); @@ -152,7 +157,7 @@ public void loadPlugins(final VanillaPluginPlatform platform) { this.containerToResource.put(container, candidate.resource()); } catch (final InvalidPluginException e) { failedInstances.put(candidate, "Failed to construct: see stacktrace(s) above this message for details."); - platform.logger().error("Failed to construct plugin {}", candidate.metadata().id(), e); + platform.logger().error("Failed to construct plugin {}", id, e); } } } From ba72fb729e6da8f29257a3a91e44956a53335348 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 1 Sep 2024 20:44:51 +0200 Subject: [PATCH 207/226] Update verification metadata --- SpongeAPI | 2 +- gradle/verification-metadata.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 7dbba481242..894d82d50b7 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 7dbba48124270b3ac08f1d3a4d0d0391ad9c3019 +Subproject commit 894d82d50b7249444ce453990b4f06da68b461b3 diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 19e94e67917..8ccf8a4c3d9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -19,6 +19,7 @@ + From a2bc234c0d5e1470822e0b5f86747ece7c75d0f2 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 1 Sep 2024 22:24:08 +0200 Subject: [PATCH 208/226] Fix compatibility with SpongeGradle --- vanilla/build.gradle.kts | 7 +++- .../vanilla/installer/Agent.java | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index a83e493c207..8352b028903 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -467,6 +467,7 @@ tasks { manifest { from(vanillaManifest) attributes( + "Premain-Class" to "org.spongepowered.vanilla.installer.Agent", "Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain", "Automatic-Module-Name" to "spongevanilla.installer", "Launch-Target" to "sponge_server_prod", @@ -535,7 +536,7 @@ indraSpotlessLicenser { property("url", projectUrl) } -val shadowJar by tasks.existing +val universalJar by tasks.existing val vanillaInstallerJar by tasks.existing val vanillaAppLaunchJar by tasks.existing val vanillaLaunchJar by tasks.existing @@ -546,16 +547,18 @@ publishing { publications { register("sponge", MavenPublication::class) { - artifact(shadowJar.get()) + artifact(universalJar.get()) artifact(vanillaInstallerJar.get()) artifact(vanillaAppLaunchJar.get()) artifact(vanillaLaunchJar.get()) artifact(vanillaAccessorsJar.get()) artifact(vanillaMixinsJar.get()) + artifact(tasks["applaunchSourcesJar"]) artifact(tasks["launchSourcesJar"]) artifact(tasks["accessorsSourcesJar"]) artifact(tasks["mixinsSourcesJar"]) + pom { artifactId = project.name.lowercase() this.name.set(project.name) diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java new file mode 100644 index 00000000000..9e180133bf2 --- /dev/null +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/Agent.java @@ -0,0 +1,37 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.vanilla.installer; + +import java.lang.instrument.Instrumentation; + +/** + * We used to have an agent but we no longer need it. + * Some versions of SpongeGradle attempt to run this agent, so this class exists otherwise it fails. + */ +public class Agent { + public static void premain(final String agentArgs, final Instrumentation instrumentation) { + // ignored + } +} From 08cd0530d6ceb0f942a38140ee676e46f4d8de49 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Mon, 2 Sep 2024 21:26:31 +0200 Subject: [PATCH 209/226] Remove most generics in services and candidates They actually create more problems than they solve resulting in a bunch of unsafe casts --- .../plugin/JavaPluginLanguageService.java | 6 +- .../plugin/VanillaPluginPlatform.java | 45 ++++++------ .../plugin/VanillaTransformationService.java | 4 +- .../resource/SecureJarPluginResource.java | 4 +- .../launch/plugin/JavaPluginLoader.java | 7 +- .../plugin/VanillaDummyPluginContainer.java | 3 +- .../plugin/VanillaJavaPluginContainer.java | 3 +- .../launch/plugin/VanillaPluginManager.java | 27 ++++--- .../plugin/resolver/DependencyResolver.java | 73 +++++++++---------- .../plugin/resolver/ResolutionResult.java | 45 ++++++------ 10 files changed, 105 insertions(+), 112 deletions(-) diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java index 6b04efffe4f..07b026699e3 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/JavaPluginLanguageService.java @@ -51,14 +51,14 @@ public String pluginLoader() { } @Override - public List> createPluginCandidates(final Environment environment, final PluginResource resource) throws Exception { + public List createPluginCandidates(final Environment environment, final PluginResource resource) throws Exception { if (resource instanceof JVMPluginResource jvmResource && Files.exists(jvmResource.resourcesRoot().resolve("net/minecraft/server/MinecraftServer.class"))) { this.logger.debug("Container in path '{}' has been detected as Minecraft.", resource.path()); - final List> candidates = new LinkedList<>(); + final List candidates = new LinkedList<>(); try (final InputStream stream = JavaPluginLanguageService.class.getClassLoader().getResourceAsStream("META-INF/minecraft_sponge_plugins.json")) { for (final PluginMetadata metadata : loadMetadataContainer(environment, stream).metadata()) { - candidates.add(new StandardPluginCandidate<>(metadata, resource)); + candidates.add(new StandardPluginCandidate(metadata, resource)); } } diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java index 834760ddb9e..1bd3bc80bc8 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaPluginPlatform.java @@ -42,7 +42,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -53,11 +52,11 @@ public final class VanillaPluginPlatform implements PluginPlatform { private final StandardEnvironment standardEnvironment; - private final Map> locatorServices; - private final Map> languageServices; + private final Map> locatorServices; + private final Map languageServices; - private final Map> locatorResources; - private final Map, List>> pluginCandidates; + private final Map> locatorResources; + private final Map> pluginCandidates; public VanillaPluginPlatform(final StandardEnvironment standardEnvironment) { this.standardEnvironment = standardEnvironment; @@ -116,24 +115,24 @@ public StandardEnvironment getStandardEnvironment() { return this.standardEnvironment; } - public Map> getLocatorServices() { + public Map> getLocatorServices() { return Collections.unmodifiableMap(this.locatorServices); } - public Map> getLanguageServices() { + public Map getLanguageServices() { return Collections.unmodifiableMap(this.languageServices); } - public Map> getResources() { + public Map> getResources() { return Collections.unmodifiableMap(this.locatorResources); } - public Map, List>> getCandidates() { + public Map> getCandidates() { return Collections.unmodifiableMap(this.pluginCandidates); } public void initializeLanguageServices() { - for (final Map.Entry> entry : this.languageServices.entrySet()) { + for (final Map.Entry entry : this.languageServices.entrySet()) { entry.getValue().initialize(this.standardEnvironment); } } @@ -144,10 +143,10 @@ public void discoverLocatorServices() { blackboard.set(JVMKeys.JVM_PLUGIN_RESOURCE_FACTORY, SecureJarPluginResource::new); final ModuleLayer serviceLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.SERVICE)).orElseThrow(); - final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(serviceLayer, PluginResourceLocatorService.class); + final var serviceLoader = ServiceLoader.load(serviceLayer, PluginResourceLocatorService.class); - for (final Iterator> iter = serviceLoader.iterator(); iter.hasNext(); ) { - final PluginResourceLocatorService next; + for (final var iter = serviceLoader.iterator(); iter.hasNext(); ) { + final PluginResourceLocatorService next; try { next = iter.next(); @@ -162,10 +161,10 @@ public void discoverLocatorServices() { public void discoverLanguageServices() { final ModuleLayer pluginLayer = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm -> lm.getLayer(IModuleLayerManager.Layer.PLUGIN)).orElseThrow(); - final var serviceLoader = (ServiceLoader>) (Object) ServiceLoader.load(pluginLayer, PluginLanguageService.class); + final var serviceLoader = ServiceLoader.load(pluginLayer, PluginLanguageService.class); - for (final Iterator> iter = serviceLoader.iterator(); iter.hasNext(); ) { - final PluginLanguageService next; + for (final var iter = serviceLoader.iterator(); iter.hasNext(); ) { + final PluginLanguageService next; try { next = iter.next(); @@ -179,9 +178,9 @@ public void discoverLanguageServices() { } public void locatePluginResources() { - for (final Map.Entry> locatorEntry : this.locatorServices.entrySet()) { - final PluginResourceLocatorService locatorService = locatorEntry.getValue(); - final Set resources = locatorService.locatePluginResources(this.standardEnvironment); + for (final Map.Entry> locatorEntry : this.locatorServices.entrySet()) { + final PluginResourceLocatorService locatorService = locatorEntry.getValue(); + final Set resources = locatorService.locatePluginResources(this.standardEnvironment); if (!resources.isEmpty()) { this.locatorResources.put(locatorEntry.getKey(), resources); } @@ -189,22 +188,22 @@ public void locatePluginResources() { } public void createPluginCandidates() { - for (final PluginLanguageService languageService : this.languageServices.values()) { - for (final Set resources : this.locatorResources.values()) { + for (final PluginLanguageService languageService : this.languageServices.values()) { + for (final Set resources : this.locatorResources.values()) { for (final PluginResource pluginResource : resources) { if (ResourceType.of(pluginResource) != ResourceType.PLUGIN) { continue; } try { - final List> candidates = languageService.createPluginCandidates(this.standardEnvironment, pluginResource); + final List candidates = languageService.createPluginCandidates(this.standardEnvironment, pluginResource); if (candidates.isEmpty()) { continue; } this.pluginCandidates.computeIfAbsent(languageService, k -> new LinkedList<>()).addAll(candidates); if (pluginResource instanceof SecureJarPluginResource jarResource) { - jarResource.addCandidates((List) candidates); + jarResource.addCandidates(candidates); } } catch (final Exception ex) { this.standardEnvironment.logger().error("Failed to create plugin candidates", ex); diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java index c2d44a79c6f..385ca924d71 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/VanillaTransformationService.java @@ -109,7 +109,7 @@ public List beginScanning(final IEnvironment environment) { final List languageResources = new ArrayList<>(); - for (final Set resources : this.pluginPlatform.getResources().values()) { + for (final Set resources : this.pluginPlatform.getResources().values()) { for (final PluginResource resource : resources) { if (resource instanceof SecureJarPluginResource secureJarResource) { if (ResourceType.of(resource) == ResourceType.LANGUAGE) { @@ -136,7 +136,7 @@ public List completeScan(IModuleLayerManager layerManager) { final List gameResources = new ArrayList<>(); - for (final Set resources : this.pluginPlatform.getResources().values()) { + for (final Set resources : this.pluginPlatform.getResources().values()) { for (final PluginResource resource : resources) { if (resource instanceof SecureJarPluginResource secureJarResource) { // Build jar metadata from first candidate, or fallback to standard diff --git a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java index d06c90af96a..62f42cc0dff 100644 --- a/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java +++ b/vanilla/src/applaunch/java/org/spongepowered/vanilla/applaunch/plugin/resource/SecureJarPluginResource.java @@ -42,7 +42,7 @@ public final class SecureJarPluginResource implements JVMPluginResource { private final SecureJar jar; private PluginJarMetadata pluginJarMetadata; - private List> candidates; + private List candidates; public SecureJarPluginResource(final String locator, final Path[] paths) { Objects.requireNonNull(locator, "locator"); @@ -87,7 +87,7 @@ public Path resourcesRoot() { return this.jar.getRootPath(); } - public void addCandidates(Collection> candidates) { + public void addCandidates(Collection candidates) { if (this.candidates != null) { this.candidates.addAll(candidates); } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java index 7b52a8aadc4..410635b1304 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/JavaPluginLoader.java @@ -32,10 +32,9 @@ import org.spongepowered.plugin.Environment; import org.spongepowered.plugin.InvalidPluginException; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.builtin.jvm.JVMPluginLoader; -import org.spongepowered.plugin.builtin.jvm.JVMPluginResource; +import org.spongepowered.plugin.PluginLoader; -public final class JavaPluginLoader implements JVMPluginLoader { +public final class JavaPluginLoader implements PluginLoader { private final ArtifactVersion version = new DefaultArtifactVersion("1.0"); @@ -45,7 +44,7 @@ public ArtifactVersion version() { } @Override - public VanillaJavaPluginContainer loadPlugin(final Environment environment, final PluginCandidate candidate, final ClassLoader targetClassLoader) + public VanillaJavaPluginContainer loadPlugin(final Environment environment, final PluginCandidate candidate, final ClassLoader targetClassLoader) throws InvalidPluginException { final VanillaJavaPluginContainer container = new VanillaJavaPluginContainer(candidate); try { diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java index 66689339990..f2053bc5117 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaDummyPluginContainer.java @@ -27,12 +27,11 @@ import org.apache.logging.log4j.Logger; import org.spongepowered.common.applaunch.plugin.DummyPluginContainer; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.builtin.StandardPluginContainer; public final class VanillaDummyPluginContainer extends StandardPluginContainer implements DummyPluginContainer { - public VanillaDummyPluginContainer(final PluginCandidate candidate, final Logger logger, final Object instance) { + public VanillaDummyPluginContainer(final PluginCandidate candidate, final Logger logger, final Object instance) { super(candidate, logger); this.initializeInstance(instance); } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java index 24001fabf6f..7e1471bdfa0 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaJavaPluginContainer.java @@ -26,12 +26,11 @@ import org.spongepowered.api.Sponge; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.builtin.StandardPluginContainer; public final class VanillaJavaPluginContainer extends StandardPluginContainer { - public VanillaJavaPluginContainer(final PluginCandidate candidate) { + public VanillaJavaPluginContainer(final PluginCandidate candidate) { super(candidate); } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java index c1d8bb84820..c1aa223a8bc 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/VanillaPluginManager.java @@ -86,16 +86,15 @@ public Collection plugins() { } public void loadPlugins(final VanillaPluginPlatform platform) { - final Map, PluginLanguageService> pluginLanguageLookup = new HashMap<>(); - final Map, PluginLoader> pluginLoaders = new HashMap<>(); + final Map pluginLanguageLookup = new HashMap<>(); + final Map> pluginLoaders = new HashMap<>(); // Initialise the plugin language loaders. - for (final Map.Entry, List>> candidate : platform.getCandidates().entrySet()) { - final PluginLanguageService languageService = candidate.getKey(); + for (final Map.Entry> candidate : platform.getCandidates().entrySet()) { + final PluginLanguageService languageService = candidate.getKey(); final String loaderClass = languageService.pluginLoader(); try { - pluginLoaders.put(languageService, - (PluginLoader) Class.forName(loaderClass).getConstructor().newInstance()); + pluginLoaders.put(languageService, (PluginLoader) Class.forName(loaderClass).getConstructor().newInstance()); } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e); } @@ -105,15 +104,15 @@ public void loadPlugins(final VanillaPluginPlatform platform) { // Priority to platform plugins that will already exist here -- meaning the resolver will act upon them first // and if someone decides to give a plugin an ID that is the same as a platform plugin, the resolver will effectively // reject it. - final Set> resources = new LinkedHashSet<>(); + final Set resources = new LinkedHashSet<>(); pluginLanguageLookup.keySet().stream().filter(x -> this.plugins.containsKey(x.metadata().id())).forEach(resources::add); resources.addAll(pluginLanguageLookup.keySet()); - final ResolutionResult resolutionResult = DependencyResolver.resolveAndSortCandidates(resources, platform.logger()); - final Map, String> failedInstances = new HashMap<>(); - final Map, String> consequentialFailedInstances = new HashMap<>(); + final ResolutionResult resolutionResult = DependencyResolver.resolveAndSortCandidates(resources, platform.logger()); + final Map failedInstances = new HashMap<>(); + final Map consequentialFailedInstances = new HashMap<>(); final ClassLoader launchClassloader = VanillaLaunch.instance().getClass().getClassLoader(); - for (final PluginCandidate candidate : resolutionResult.sortedSuccesses()) { + for (final PluginCandidate candidate : resolutionResult.sortedSuccesses()) { final String id = candidate.metadata().id(); if (id.indexOf('-') >= 0) { platform.logger().warn("The dash character (-) is no longer supported in plugin ids.\n" + @@ -149,8 +148,8 @@ public void loadPlugins(final VanillaPluginPlatform platform) { // If a dependency failed to load, then we should bail on required dependencies too. // This should work fine, we're sorted so all deps should be in place at this stage. if (this.stillValid(candidate, consequentialFailedInstances)) { - final PluginLanguageService languageService = pluginLanguageLookup.get(candidate); - final PluginLoader pluginLoader = pluginLoaders.get(languageService); + final PluginLanguageService languageService = pluginLanguageLookup.get(candidate); + final PluginLoader pluginLoader = pluginLoaders.get(languageService); try { final PluginContainer container = pluginLoader.loadPlugin(platform.getStandardEnvironment(), candidate, launchClassloader); this.addPlugin(container); @@ -180,7 +179,7 @@ public PluginResource resource(final PluginContainer container) { return this.containerToResource.get(container); } - private boolean stillValid(final PluginCandidate candidate, final Map, String> consequential) { + private boolean stillValid(final PluginCandidate candidate, final Map consequential) { final Optional failedId = candidate.metadata().dependencies().stream().filter(x -> !x.optional() && !this.plugins.containsKey(x.id())).findFirst(); if (failedId.isPresent()) { diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/DependencyResolver.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/DependencyResolver.java index aee9d1a5632..3d53223bac9 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/DependencyResolver.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/DependencyResolver.java @@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.util.Tuple; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.PluginResource; import org.spongepowered.plugin.metadata.model.PluginDependency; import java.util.ArrayList; @@ -47,26 +46,26 @@ public final class DependencyResolver { - public static ResolutionResult resolveAndSortCandidates(final Collection> candidates, + public static ResolutionResult resolveAndSortCandidates(final Collection candidates, final Logger logger) { - final Map> nodes = new HashMap<>(); - final ResolutionResult resolutionResult = new ResolutionResult<>(); - for (final PluginCandidate candidate : candidates) { + final Map nodes = new HashMap<>(); + final ResolutionResult resolutionResult = new ResolutionResult(); + for (final PluginCandidate candidate : candidates) { final String id = candidate.metadata().id(); // If we already have an entry, this is now a duplicate ID situation. if (nodes.containsKey(id)) { resolutionResult.duplicateIds().add(id); } else { - nodes.put(id, new Node<>(candidate)); + nodes.put(id, new Node(candidate)); } } - for (final Map.Entry> entry : nodes.entrySet()) { + for (final Map.Entry entry : nodes.entrySet()) { // Attach deps, invalid deps will appear at this point. - final Node node = entry.getValue(); + final Node node = entry.getValue(); for (final PluginDependency pd : node.candidate.metadata().dependencies()) { final boolean isOptional = pd.optional(); - final Node dep = nodes.get(pd.id()); + final Node dep = nodes.get(pd.id()); if (dep == null) { if (isOptional) { @@ -113,21 +112,21 @@ public static ResolutionResult resolveAndSortCandi // Check for invalid deps DependencyResolver.checkCyclic(nodes.values(), resolutionResult); - for (final Node node : nodes.values()) { + for (final Node node : nodes.values()) { DependencyResolver.calculateSecondaryFailures(node, resolutionResult); } // Now to sort them. - final List> original = nodes.values().stream().filter(x -> !x.invalid).collect(Collectors.toCollection(ArrayList::new)); - final List> toLoad = new ArrayList<>(original); - final LinkedHashSet> sorted = new LinkedHashSet<>(); + final List original = nodes.values().stream().filter(x -> !x.invalid).collect(Collectors.toCollection(ArrayList::new)); + final List toLoad = new ArrayList<>(original); + final LinkedHashSet sorted = new LinkedHashSet<>(); toLoad.stream().filter(x -> x.dependencies.isEmpty() && x.optionalDependencies.isEmpty()).forEach(sorted::add); toLoad.removeIf(sorted::contains); int size = toLoad.size(); boolean excludeOptionals = false; while (!toLoad.isEmpty()) { boolean containsOptionalDeps = false; - for (final Node node : toLoad) { + for (final Node node : toLoad) { if (sorted.containsAll(node.dependencies) && DependencyResolver.checkOptionalDependencies(excludeOptionals, sorted, node)) { final boolean hasOptionalDeps = !node.optionalDependencies.isEmpty(); containsOptionalDeps |= hasOptionalDeps; @@ -162,15 +161,15 @@ public static ResolutionResult resolveAndSortCandi } } - final Collection> sortedSuccesses = resolutionResult.sortedSuccesses(); - for (final Node x : sorted) { + final Collection sortedSuccesses = resolutionResult.sortedSuccesses(); + for (final Node x : sorted) { sortedSuccesses.add(x.candidate); } return resolutionResult; } - private static boolean checkOptionalDependencies( - final boolean excludeOptionals, final Collection> sorted, final Node node) { + private static boolean checkOptionalDependencies( + final boolean excludeOptionals, final Collection sorted, final Node node) { if (excludeOptionals) { // We need to make sure we filter out any deps that have "before" requirements - so we load those with all required deps met. return node.optionalDependencies.stream().flatMap(x -> x.beforeRequiredDependency.stream()).distinct().allMatch(sorted::contains); @@ -178,7 +177,7 @@ private static boolean checkOptionalDependencies( return sorted.containsAll(node.optionalDependencies); } - private static void setDependency(final Node before, final Node after, final boolean optional) { + private static void setDependency(final Node before, final Node after, final boolean optional) { if (optional) { before.optionalDependencies.add(after); } else { @@ -203,24 +202,24 @@ private static boolean checkVersion(final @Nullable VersionRange requestedVersio return Objects.equals(requestedVersion.getRecommendedVersion(), dependencyVersion) || requestedVersion.containsVersion(dependencyVersion); } - private static void checkCyclic(final Collection> nodes, final ResolutionResult resolutionResult) { - for (final Node node : nodes) { + private static void checkCyclic(final Collection nodes, final ResolutionResult resolutionResult) { + for (final Node node : nodes) { if (!node.checked) { - final LinkedHashSet> nodeSet = new LinkedHashSet<>(); + final LinkedHashSet nodeSet = new LinkedHashSet<>(); nodeSet.add(node); DependencyResolver.checkCyclic(node, resolutionResult, nodeSet); } } } - private static void checkCyclic(final Node node, final ResolutionResult resolutionResult, - final LinkedHashSet> dependencyPath) { + private static void checkCyclic(final Node node, final ResolutionResult resolutionResult, + final LinkedHashSet dependencyPath) { if (node.invalid) { return; } // We're doing depth first. - for (final Node dependency : node.dependencies) { + for (final Node dependency : node.dependencies) { // We've already done this. Consequential failures will be handled later. if (dependency.checked) { continue; @@ -232,8 +231,8 @@ private static void checkCyclic(final Node node, f node.invalid = true; // We create the dependency path for printing later. boolean append = false; - final List> candidatePath = new LinkedList<>(); - for (final Node depInCycle : dependencyPath) { + final List candidatePath = new LinkedList<>(); + for (final Node depInCycle : dependencyPath) { append |= depInCycle == dependency; // all candidates from here are in the loop. if (append) { @@ -243,7 +242,7 @@ private static void checkCyclic(final Node node, f } // We'll only care about the one. - for (final PluginCandidate dep : candidatePath) { + for (final PluginCandidate dep : candidatePath) { resolutionResult.cyclicDependency().put(dep, candidatePath); } } else { @@ -254,7 +253,7 @@ private static void checkCyclic(final Node node, f } } - private static boolean calculateSecondaryFailures(final Node node, final ResolutionResult resolutionResult) { + private static boolean calculateSecondaryFailures(final Node node, final ResolutionResult resolutionResult) { if (node.secondaryChecked) { return node.invalid; } @@ -266,14 +265,14 @@ private static boolean calculateSecondaryFailures(fin return false; } - for (final Node depNode : node.dependencies) { + for (final Node depNode : node.dependencies) { if (DependencyResolver.calculateSecondaryFailures(depNode, resolutionResult)) { node.invalid = true; resolutionResult.cascadedFailure().computeIfAbsent(node.candidate, k -> new HashSet<>()).add(depNode.candidate); } } - for (final Node depNode : node.beforeRequiredDependency) { + for (final Node depNode : node.beforeRequiredDependency) { if (DependencyResolver.calculateSecondaryFailures(depNode, resolutionResult)) { node.invalid = true; resolutionResult.cascadedFailure().computeIfAbsent(node.candidate, k -> new HashSet<>()).add(depNode.candidate); @@ -282,17 +281,17 @@ private static boolean calculateSecondaryFailures(fin return node.invalid; } - static class Node { + static class Node { - final PluginCandidate candidate; - final Set> beforeRequiredDependency = new HashSet<>(); - final Set> dependencies = new HashSet<>(); - final Set> optionalDependencies = new HashSet<>(); + final PluginCandidate candidate; + final Set beforeRequiredDependency = new HashSet<>(); + final Set dependencies = new HashSet<>(); + final Set optionalDependencies = new HashSet<>(); boolean invalid = false; boolean checked = false; boolean secondaryChecked = false; - public Node(final PluginCandidate candidate) { + public Node(final PluginCandidate candidate) { this.candidate = candidate; } diff --git a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/ResolutionResult.java b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/ResolutionResult.java index 84c1966c702..fb1124b893b 100644 --- a/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/ResolutionResult.java +++ b/vanilla/src/launch/java/org/spongepowered/vanilla/launch/plugin/resolver/ResolutionResult.java @@ -29,7 +29,6 @@ import org.spongepowered.api.util.Tuple; import org.spongepowered.common.util.PrettyPrinter; import org.spongepowered.plugin.PluginCandidate; -import org.spongepowered.plugin.PluginResource; import java.util.Collection; import java.util.HashMap; @@ -38,14 +37,14 @@ import java.util.Map; import java.util.stream.Collectors; -public final class ResolutionResult { +public final class ResolutionResult { - private final LinkedHashSet> sortedSuccesses; + private final LinkedHashSet sortedSuccesses; private final Collection duplicateIds; - private final Map, Collection> missingDependencies; - private final Map, Collection>>> versionMismatch; - private final Map, Collection>> cyclicDependency; - private final Map, Collection>> cascadedFailure; + private final Map> missingDependencies; + private final Map>> versionMismatch; + private final Map> cyclicDependency; + private final Map> cascadedFailure; public ResolutionResult() { this.sortedSuccesses = new LinkedHashSet<>(); @@ -56,7 +55,7 @@ public ResolutionResult() { this.cascadedFailure = new HashMap<>(); } - public Collection> sortedSuccesses() { + public Collection sortedSuccesses() { return this.sortedSuccesses; } @@ -64,25 +63,25 @@ public Collection duplicateIds() { return this.duplicateIds; } - public Map, Collection> missingDependencies() { + public Map> missingDependencies() { return this.missingDependencies; } - public Map, Collection>>> versionMismatch() { + public Map>> versionMismatch() { return this.versionMismatch; } - public Map, Collection>> cyclicDependency() { + public Map> cyclicDependency() { return this.cyclicDependency; } - public Map, Collection>> cascadedFailure() { + public Map> cascadedFailure() { return this.cascadedFailure; } public void printErrorsIfAny( - final Map, String > failedInstance, - final Map, String> consequentialFailedInstance, + final Map failedInstance, + final Map consequentialFailedInstance, final Logger logger) { final int noOfFailures = this.numberOfFailures() + failedInstance.size() + consequentialFailedInstance.size(); if (noOfFailures == 0) { @@ -106,7 +105,7 @@ public void printErrorsIfAny( if (!this.missingDependencies.isEmpty()) { errorPrinter.add(); errorPrinter.add("The following plugins are missing dependencies:"); - for (final Map.Entry, Collection> entry : this.missingDependencies.entrySet()) { + for (final Map.Entry> entry : this.missingDependencies.entrySet()) { errorPrinter.add(" * %s requires [ %s ]", entry.getKey().metadata().id(), String.join(", ", entry.getValue())); @@ -116,9 +115,9 @@ public void printErrorsIfAny( if (!this.versionMismatch.isEmpty()) { errorPrinter.add(); errorPrinter.add("The following plugins require different version(s) of dependencies you have installed:"); - for (final Map.Entry, Collection>>> entry : this.versionMismatch.entrySet()) { - final PluginCandidate candidate = entry.getKey(); - final Collection>> mismatchedDeps = entry.getValue(); + for (final Map.Entry>> entry : this.versionMismatch.entrySet()) { + final PluginCandidate candidate = entry.getKey(); + final Collection> mismatchedDeps = entry.getValue(); final String errorString = mismatchedDeps.stream() .map(x -> String.format("%s version %s (currently version %s)", x.second().metadata().id(), x.first(), x.second().metadata().version())) @@ -132,7 +131,7 @@ public void printErrorsIfAny( if (!this.cyclicDependency.isEmpty()) { errorPrinter.add(); errorPrinter.add("The following plugins were found to have cyclic dependencies:"); - for (final Map.Entry, Collection>> node : this.cyclicDependency.entrySet()) { + for (final Map.Entry> node : this.cyclicDependency.entrySet()) { errorPrinter.add(" * %s has dependency cycle [ ... -> %s -> ... ]", node.getKey().metadata().id(), node.getValue().stream().map(x -> x.metadata().id()).collect(Collectors.joining(" -> "))); @@ -142,7 +141,7 @@ public void printErrorsIfAny( if (!failedInstance.isEmpty()) { errorPrinter.add(); errorPrinter.add("The following plugins threw exceptions when being created (report these to the plugin authors):"); - for (final Map.Entry, String> node : failedInstance.entrySet()) { + for (final Map.Entry node : failedInstance.entrySet()) { errorPrinter.add(" * %s with the error message \"%s\"", node.getKey().metadata().id(), node.getValue()); @@ -150,15 +149,15 @@ public void printErrorsIfAny( } if (!this.cascadedFailure.isEmpty() || !consequentialFailedInstance.isEmpty()) { - final Map, String> mergedFailures = new HashMap<>(consequentialFailedInstance); - for (final Map.Entry, Collection>> entry : this.cascadedFailure.entrySet()) { + final Map mergedFailures = new HashMap<>(consequentialFailedInstance); + for (final Map.Entry> entry : this.cascadedFailure.entrySet()) { final String error = entry.getValue().stream().map(x -> x.metadata().id()).collect(Collectors.joining(", ")); mergedFailures.merge(entry.getKey(), error, (old, incoming) -> old + ", " + incoming); } errorPrinter.add(); errorPrinter.add("The following plugins are not loading because they depend on plugins that will not load:"); - for (final Map.Entry, String> node : mergedFailures.entrySet()) { + for (final Map.Entry node : mergedFailures.entrySet()) { errorPrinter.add(" * %s depends on [ %s ]", node.getKey().metadata().id(), // nothing wrong with this plugin other than the other plugins, From a22f53a882fc92d7a2fa81314e627b9d9c86e404 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Tue, 3 Sep 2024 00:00:14 +0200 Subject: [PATCH 210/226] Cleanup buildscripts --- forge/build.gradle.kts | 76 ++++++++++++---------------------------- vanilla/build.gradle.kts | 42 ++++++++++++---------- 2 files changed, 47 insertions(+), 71 deletions(-) diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index e3c75af6d4c..45e64e85bfb 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -38,13 +38,13 @@ repositories { } // SpongeForge libraries -val serviceLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeServiceLibraries") -val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameLibraries") +val serviceLibrariesConfig: NamedDomainObjectProvider = configurations.register("serviceLibraries") +val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameLibraries") -val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameManagedLibraries") +val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameManagedLibraries") -val serviceShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeServiceShadedLibraries") -val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameShadedLibraries") +val serviceShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("serviceShadedLibraries") +val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameShadedLibraries") val runTaskOnlyConfig: NamedDomainObjectProvider = configurations.register("runTaskOnly") @@ -206,27 +206,27 @@ dependencies { forgeMixins.implementationConfigurationName(project(commonProject.path)) - val serviceLibraries = serviceLibrariesConfig.name - serviceLibraries(apiLibs.pluginSpi) - serviceLibraries(project(transformersProject.path)) - serviceLibraries(platform(apiLibs.configurate.bom)) - serviceLibraries(apiLibs.configurate.core) { + val service = serviceLibrariesConfig.name + service(apiLibs.pluginSpi) + service(project(transformersProject.path)) + service(platform(apiLibs.configurate.bom)) + service(apiLibs.configurate.core) { exclude(group = "org.checkerframework", module = "checker-qual") } - serviceLibraries(apiLibs.configurate.hocon) { + service(apiLibs.configurate.hocon) { exclude(group = "org.spongepowered", module = "configurate-core") exclude(group = "org.checkerframework", module = "checker-qual") } - serviceLibraries(libs.configurate.jackson) { + service(libs.configurate.jackson) { exclude(group = "org.spongepowered", module = "configurate-core") exclude(group = "org.checkerframework", module = "checker-qual") } - val gameLibraries = gameLibrariesConfig.name - gameLibraries("org.spongepowered:spongeapi:$apiVersion") - gameLibraries(libs.javaxInject) - gameLibraries(platform(apiLibs.adventure.bom)) - gameLibraries(libs.adventure.serializerConfigurate4) + val game = gameLibrariesConfig.name + game("org.spongepowered:spongeapi:$apiVersion") + game(libs.javaxInject) + game(platform(apiLibs.adventure.bom)) + game(libs.adventure.serializerConfigurate4) val serviceShadedLibraries = serviceShadedLibrariesConfig.name serviceShadedLibraries(project(transformersProject.path)) { isTransitive = false } @@ -293,7 +293,7 @@ tasks { from(forgeLang.output) } - val forgeServicesDevJar by registering(Jar::class) { + val forgeServicesJar by registering(Jar::class) { archiveClassifier.set("services") manifest.from(forgeManifest) @@ -308,7 +308,7 @@ tasks { // Default classpath is a mess, we better start a new one from scratch classpath = files( configurations.getByName("forgeRuntimeLibrary"), - forgeServicesDevJar, forgeLangJar, runTaskOnlyConfig + forgeServicesJar, forgeLangJar, runTaskOnlyConfig ) testPluginsProject?.also { @@ -327,7 +327,7 @@ tasks { .toList() } - jvmArguments.add("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath + // jvmArguments.add("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath sourceSets.forEach { dependsOn(it.classesTaskName) @@ -427,21 +427,6 @@ sourceSets { } } -afterEvaluate { - sourceSets.configureEach { - // Don't apply Mixin AP - configurations.named(annotationProcessorConfigurationName) { - exclude(group = "org.spongepowered", module = "mixin") - exclude(group = "net.fabricmc", module = "fabric-mixin-compile-extensions") - } - // And don't pass AP parameters - tasks.named(compileJavaTaskName, JavaCompile::class) { - val mixinApArgs = setOf("outRefMapFile", "defaultObfuscationEnv", "outMapFileNamedIntermediary", "inMapFileNamedIntermediary") - options.compilerArgs.removeIf { mixinApArgs.any { mixin -> it.contains(mixin)} } - } - } -} - indraSpotlessLicenser { licenseHeaderFile(rootProject.file("HEADER.txt")) @@ -458,6 +443,9 @@ publishing { artifact(tasks["jar"]) artifact(tasks["sourcesJar"]) + artifact(tasks["forgeLangJar"]) + artifact(tasks["langSourcesJar"]) + artifact(tasks["forgeMixinsJar"]) artifact(tasks["mixinsSourcesJar"]) @@ -491,21 +479,3 @@ publishing { } } } - -tasks.register("printRunTasks") { - group = "debug" - doLast { - tasks.withType(net.fabricmc.loom.task.AbstractRunTask::class) { - println() - println("Task ${this.name}:") - println("mainClass: " + this.mainClass.orNull) - println("mainModule: " + this.mainModule.orNull) - println("allJvmArgs: " + this.allJvmArgs) - println("jvmArgs: " + this.jvmArgs) - println("args: " + this.args) - println("commandLine: " + this.commandLine) - println("environment: " + this.environment) - println("classpath: " + this.classpath.files) - } - } -} diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index 8352b028903..524906a28a6 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -23,17 +23,17 @@ description = "The SpongeAPI implementation for Vanilla Minecraft" version = spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVersion, recommendedVersion) // SpongeVanilla libraries -val installerLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeInstallerLibraries") -val initLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeInitLibraries") // JVM initial classpath -val bootLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootLibraries") -val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameLibraries") { +val installerLibrariesConfig: NamedDomainObjectProvider = configurations.register("installerLibraries") +val initLibrariesConfig: NamedDomainObjectProvider = configurations.register("initLibraries") // JVM initial classpath +val bootLibrariesConfig: NamedDomainObjectProvider = configurations.register("bootLibraries") +val gameLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameLibraries") { extendsFrom(configurations.minecraft.get()) } -val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameManagedLibraries") +val gameManagedLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameManagedLibraries") -val bootShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeBootShadedLibraries") -val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("spongeGameShadedLibraries") +val bootShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("bootShadedLibraries") +val gameShadedLibrariesConfig: NamedDomainObjectProvider = configurations.register("gameShadedLibraries") val runTaskOnlyConfig: NamedDomainObjectProvider = configurations.register("runTaskOnly") @@ -159,7 +159,7 @@ minecraft { ) // ModLauncher - jvmArgs("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath + // jvmArgs("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath mainClass("net.minecraftforge.bootstrap.ForgeBootstrap") allArgumentProviders += CommandLineArgumentProvider { @@ -270,7 +270,6 @@ dependencies { } boot(apiLibs.pluginSpi) { exclude(group = "org.checkerframework", module = "checker-qual") - // exclude(group = "com.google.code.gson", module = "gson") exclude(group = "org.apache.logging.log4j", module = "log4j-api") } boot(libs.lmaxDisruptor) @@ -546,19 +545,26 @@ val vanillaMixinsJar by tasks.existing publishing { publications { register("sponge", MavenPublication::class) { + artifact(tasks["universalJar"]) - artifact(universalJar.get()) - artifact(vanillaInstallerJar.get()) - artifact(vanillaAppLaunchJar.get()) - artifact(vanillaLaunchJar.get()) - artifact(vanillaAccessorsJar.get()) - artifact(vanillaMixinsJar.get()) + artifact(tasks["jar"]) + artifact(tasks["sourcesJar"]) - artifact(tasks["applaunchSourcesJar"]) - artifact(tasks["launchSourcesJar"]) - artifact(tasks["accessorsSourcesJar"]) + artifact(tasks["vanillaInstallerJar"]) + artifact(tasks["installerSourcesJar"]) + + artifact(tasks["vanillaMixinsJar"]) artifact(tasks["mixinsSourcesJar"]) + artifact(tasks["vanillaAccessorsJar"]) + artifact(tasks["accessorsSourcesJar"]) + + artifact(tasks["vanillaLaunchJar"]) + artifact(tasks["launchSourcesJar"]) + + artifact(tasks["vanillaAppLaunchJar"]) + artifact(tasks["applaunchSourcesJar"]) + pom { artifactId = project.name.lowercase() this.name.set(project.name) From 1e8c366d77e58a9f36e16bf357049e2542381459 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 19 Sep 2024 17:51:06 +0200 Subject: [PATCH 211/226] Update plugin-spi to 0.4.0 --- SpongeAPI | 2 +- gradle/verification-metadata.xml | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 894d82d50b7..d62dfef426e 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 894d82d50b7249444ce453990b4f06da68b461b3 +Subproject commit d62dfef426e3e69c6e32fb6cb79b07636d7e9312 diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 8ccf8a4c3d9..e14ec7e3961 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -19,11 +19,10 @@ - - + @@ -5935,6 +5934,14 @@
+ + + + + + + + @@ -5949,6 +5956,14 @@ + + + + + + + + @@ -5975,11 +5990,6 @@ - - - - - From 98392d91976d45c4dce7c96f0c7177a1d0dd9707 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 19 Sep 2024 18:37:10 +0200 Subject: [PATCH 212/226] Bump SpongeAPI --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index d62dfef426e..91e3e5f9ae0 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit d62dfef426e3e69c6e32fb6cb79b07636d7e9312 +Subproject commit 91e3e5f9ae07f8edfb62a9ac7118d716bdf5632c From c233dac72bed832048dcaf5f2517701afad3af4f Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Sun, 22 Sep 2024 12:07:39 +0200 Subject: [PATCH 213/226] Fix missing LWJGL natives in SV client --- vanilla/build.gradle.kts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index 524906a28a6..23e1268dcc9 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -310,7 +310,13 @@ dependencies { // All minecraft deps except itself configurations.minecraft.get().resolvedConfiguration.resolvedArtifacts - .map { it.id.componentIdentifier.toString() } + .map { + var id = it.id.componentIdentifier.toString() + if (it.classifier != null) { + id += ":" + it.classifier + } + id + } .filter { !it.startsWith("net.minecraft:joined") } .forEach { boot(it) { isTransitive = false } } From 7ac46ab1da5bc31fd91254e95e8380f18440bf00 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 22 Sep 2024 14:27:37 +0300 Subject: [PATCH 214/226] fix stored enchantments applying only to enchanted book --- .../data/provider/item/stack/BookPagesItemStackData.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java index c048167e2fd..89a51d35765 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java @@ -28,7 +28,6 @@ import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.ItemEnchantments; import org.spongepowered.api.data.Keys; import org.spongepowered.api.item.enchantment.Enchantment; @@ -58,8 +57,7 @@ public static void register(final DataProviderRegistrator registrator) { .create(Keys.STORED_ENCHANTMENTS) .get(h -> BookPagesItemStackData.get(h, DataComponents.STORED_ENCHANTMENTS)) .set((h, v) -> BookPagesItemStackData.set(h, v, Collection::stream, DataComponents.STORED_ENCHANTMENTS)) - .delete(h -> BookPagesItemStackData.delete(h, DataComponents.STORED_ENCHANTMENTS)) - .supports(h -> h.getItem() == Items.ENCHANTED_BOOK); + .delete(h -> BookPagesItemStackData.delete(h, DataComponents.STORED_ENCHANTMENTS)); } // @formatter:on From 9252b6fbb5a53ed27cd3a724cf235bfc2781b1bb Mon Sep 17 00:00:00 2001 From: aromaa Date: Mon, 23 Sep 2024 01:52:14 +0300 Subject: [PATCH 215/226] Optimize ChangeBlockEvent.All transaction building --- .../block/BlockEventBasedTransaction.java | 59 ++++++------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java index 345a2d2d461..6ac23abd473 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java @@ -25,8 +25,6 @@ package org.spongepowered.common.event.tracking.context.transaction.block; import com.google.common.collect.ImmutableList; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.ListMultimap; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.NonNull; @@ -49,8 +47,8 @@ import org.spongepowered.common.event.tracking.context.transaction.world.WorldBasedTransaction; import org.spongepowered.math.vector.Vector3i; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; abstract class BlockEventBasedTransaction extends WorldBasedTransaction { @@ -75,53 +73,30 @@ public final Optional generateEvent( if (!o.isPresent()) { return Optional.empty(); } - final ListMultimap positions = LinkedListMultimap.create(); + + final Map eventTransactions = new HashMap<>(); for (final GameTransaction<@NonNull ?> transaction : transactions) { final BlockEventBasedTransaction blockTransaction = (BlockEventBasedTransaction) transaction; - if (!positions.containsKey(blockTransaction.affectedPosition)) { - positions.put( - blockTransaction.affectedPosition, - blockTransaction.getOriginalSnapshot() - ); - } - if (blockTransaction.getResultingSnapshot() != null) { - positions.put( - blockTransaction.affectedPosition, - blockTransaction.getResultingSnapshot() - ); - } + final SpongeBlockSnapshot original = blockTransaction.getOriginalSnapshot(); + final SpongeBlockSnapshot result = blockTransaction.getResultingSnapshot(); + final Operation operation = context.getBlockOperation(original, result); + final BlockTransaction eventTransaction = new BlockTransaction(original, result, operation); + eventTransactions.merge(blockTransaction.affectedPosition, eventTransaction, (oldValue, newValue) -> { + final ImmutableList.Builder intermediary = ImmutableList.builderWithExpectedSize(oldValue.intermediary().size() + 1); + intermediary.addAll(oldValue.intermediary()); + intermediary.add(oldValue.finalReplacement()); + final Operation mergedOperation = context.getBlockOperation((SpongeBlockSnapshot) oldValue.original(), (SpongeBlockSnapshot) newValue.finalReplacement()); + return new BlockTransaction(oldValue.original(), newValue.finalReplacement(), intermediary.build(), mergedOperation); + }); } - final ImmutableList eventTransactions = positions.asMap().values() - .stream() - .map(spongeBlockSnapshots -> { - final List snapshots = new ArrayList<>(spongeBlockSnapshots); - if (snapshots.isEmpty() || snapshots.size() < 2) { - // Error case - return Optional.empty(); - } - final SpongeBlockSnapshot original = snapshots.get(0); - final SpongeBlockSnapshot result = snapshots.get(snapshots.size() - 1); - final ImmutableList intermediary; - if (snapshots.size() > 2) { - intermediary = ImmutableList.copyOf(snapshots.subList(1, snapshots.size() - 2)); - } else { - intermediary = ImmutableList.of(); - } - final Operation operation = context.getBlockOperation(original, result); - final BlockTransaction eventTransaction = new BlockTransaction(original, result, intermediary, operation); - return Optional.of(eventTransaction); - }) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(ImmutableList.toImmutableList()); - if (eventTransactions.isEmpty()) { return Optional.empty(); } + return Optional.of(SpongeEventFactory.createChangeBlockEventAll( currentCause, - eventTransactions, + ImmutableList.copyOf(eventTransactions.values()), o.get() )); } From 8b4cf4e28e95e4a5034bdf4ebdb1f1f5f47e9ed0 Mon Sep 17 00:00:00 2001 From: aromaa Date: Mon, 23 Sep 2024 01:55:41 +0300 Subject: [PATCH 216/226] Optimize ChangeBlockEvent.Post transaction building --- .../type/BlockTransactionType.java | 60 +++++++------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java index ca6fb81628b..b8605f062fe 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java @@ -24,11 +24,8 @@ */ package org.spongepowered.common.event.tracking.context.transaction.type; -import com.google.common.collect.ImmutableList; import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; -import net.minecraft.core.BlockPos; import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.block.transaction.BlockTransaction; @@ -46,7 +43,7 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.Collections; import java.util.Optional; public final class BlockTransactionType extends TransactionType { @@ -69,49 +66,36 @@ protected void consumeEventsAndMarker( if (!serverWorld.isPresent()) { return; } - final ListMultimap positions = LinkedListMultimap.create(); + // Gather transactions that were valid - events.stream() - .filter(event -> !event.isCancelled()) - .flatMap(event -> event.transactions().stream()) - .filter(BlockTransaction::isValid) - .forEach(transactions -> { - // Then "put" the most recent transactions such that we have a complete rebuild of - // each position according to what originally existed and then - // the ultimate final block on that position - final SpongeBlockSnapshot original = (SpongeBlockSnapshot) transactions.original(); - positions.put(original.getBlockPos(), original); - positions.put(original.getBlockPos(), (SpongeBlockSnapshot) transactions.finalReplacement()); - }); + final ArrayList transactions = new ArrayList<>(); + for (final ChangeBlockEvent.All event : events) { + if (event.isCancelled()) { + continue; + } - // Do not bother turning the positions into receipts if it's empty - // just return. - if (positions.isEmpty()) { - return; - } - final ImmutableList transactions = positions.asMap() - .values() - .stream() - .map(spongeBlockSnapshots -> { - final List snapshots = new ArrayList<>(spongeBlockSnapshots); - if (snapshots.isEmpty() || snapshots.size() < 2) { - // Error case - return Optional.empty(); + transactions.ensureCapacity(event.transactions().size()); + for (final BlockTransaction transaction : event.transactions()) { + if (!transaction.isValid()) { + continue; } - final SpongeBlockSnapshot original = snapshots.get(0); - final SpongeBlockSnapshot result = snapshots.get(snapshots.size() - 1); + + final SpongeBlockSnapshot original = (SpongeBlockSnapshot) transaction.original(); + final SpongeBlockSnapshot result = (SpongeBlockSnapshot) transaction.finalReplacement(); final Operation operation = context.getBlockOperation(original, result); final BlockTransactionReceipt eventTransaction = new BlockTransactionReceipt(original, result, operation); + transactions.add(eventTransaction); context.postBlockTransactionApplication(original.blockChange, eventTransaction); - return Optional.of(eventTransaction); - }) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(ImmutableList.toImmutableList()); + } + } + + if (transactions.isEmpty()) { + return; + } final Cause cause = PhaseTracker.getInstance().currentCause(); - SpongeCommon.post(SpongeEventFactory.createChangeBlockEventPost(cause, transactions, serverWorld.get())); + SpongeCommon.post(SpongeEventFactory.createChangeBlockEventPost(cause, Collections.unmodifiableList(transactions), serverWorld.get())); }); } } From 7fc0c47747d8bf087545a530da12fe2965c3a8f3 Mon Sep 17 00:00:00 2001 From: aromaa Date: Mon, 23 Sep 2024 02:25:42 +0300 Subject: [PATCH 217/226] Switch to volume stream application phase on forEach & applyUntil --- .../world/volume/SpongeVolumeStream.java | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java b/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java index 701133d2a1b..2d3f8779f6e 100644 --- a/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java +++ b/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java @@ -206,17 +206,7 @@ public Stream> toStream() { @Override public void apply(final VolumeCollector collector) { - final PhaseTracker instance = PhaseTracker.getInstance(); - try (final @Nullable PhaseContext<@NonNull ?> context = instance.getPhaseContext().isApplyingStreams() - ? null - : PluginPhase.State.VOLUME_STREAM_APPLICATION - .createPhaseContext(instance) - .setVolumeStream(this) - .spawnType(() -> PhaseTracker.getCauseStackManager().context(EventContextKeys.SPAWN_TYPE).orElse(null)) - ) { - if (context != null) { - context.buildAndSwitch(); - } + this.startPhase(() -> { this.stream.forEach(element -> { final W targetVolume = collector.target().get(); final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( @@ -227,35 +217,39 @@ public void apply(final VolumeCollector colle collector.applicator() .apply(targetVolume, transformed); }); - } + }); } @Override public void applyUntil(final VolumeCollector collector, final Predicate predicate) { - boolean doWork = true; - for (final Iterator> iterator = this.stream.iterator(); doWork && iterator.hasNext(); ) { - final W targetVolume = collector.target().get(); - final VolumeElement element = iterator.next(); - final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( - collector.target(), - element::type, - element.position() - )); - final R apply = collector.applicator() - .apply(targetVolume, transformed); - doWork = predicate.test(apply); - } + this.startPhase(() -> { + boolean doWork = true; + for (final Iterator> iterator = this.stream.iterator(); doWork && iterator.hasNext(); ) { + final W targetVolume = collector.target().get(); + final VolumeElement element = iterator.next(); + final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( + collector.target(), + element::type, + element.position() + )); + final R apply = collector.applicator() + .apply(targetVolume, transformed); + doWork = predicate.test(apply); + } + }); } @Override public void forEach(final VolumeConsumer visitor) { - this.stream.forEach(element -> visitor.consume( - element.volume(), - element.type(), - element.position().x(), - element.position().y(), - element.position().z() - )); + this.startPhase(() -> { + this.stream.forEach(element -> visitor.consume( + element.volume(), + element.type(), + element.position().x(), + element.position().y(), + element.position().z() + )); + }); } @Override @@ -263,4 +257,20 @@ public void forEach(final Consumer> consumer) { this.stream.forEach(consumer); } + private void startPhase(final Runnable runnable) { + final PhaseTracker instance = PhaseTracker.getInstance(); + try (final @Nullable PhaseContext<@NonNull ?> context = instance.getPhaseContext().isApplyingStreams() + ? null + : PluginPhase.State.VOLUME_STREAM_APPLICATION + .createPhaseContext(instance) + .setVolumeStream(this) + .spawnType(() -> PhaseTracker.getCauseStackManager().context(EventContextKeys.SPAWN_TYPE).orElse(null)) + ) { + if (context != null) { + context.buildAndSwitch(); + } + + runnable.run(); + } + } } From a1bd4c4a48f8009f20f3ac31c3a20f68b1c92d1d Mon Sep 17 00:00:00 2001 From: aromaa Date: Mon, 23 Sep 2024 03:11:09 +0300 Subject: [PATCH 218/226] Disable VolumeTransformationTest This now requires UnitTestExtension which is broken --- .../util/transformation/VolumeTransformationTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java index ae2d2435294..d0fec3da68f 100644 --- a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java +++ b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java @@ -29,6 +29,7 @@ import com.google.inject.Injector; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -42,6 +43,7 @@ import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.event.EventContextKey; import org.spongepowered.api.registry.RegistryHolder; import org.spongepowered.api.registry.RegistryKey; import org.spongepowered.api.registry.RegistryType; @@ -56,10 +58,12 @@ import org.spongepowered.api.world.volume.archetype.ArchetypeVolume; import org.spongepowered.api.world.volume.stream.StreamOptions; import org.spongepowered.api.world.volume.stream.VolumePositionTranslators; +import org.spongepowered.common.event.SpongeEventContextKeyBuilder; import org.spongepowered.common.registry.SpongeBuilderProvider; import org.spongepowered.common.registry.SpongeFactoryProvider; import org.spongepowered.common.registry.SpongeRegistryKey; import org.spongepowered.common.registry.SpongeRegistryType; +import org.spongepowered.common.test.UnitTestExtension; import org.spongepowered.common.test.stub.StubGame; import org.spongepowered.common.test.stub.StubKey; import org.spongepowered.common.test.stub.StubModule; @@ -81,8 +85,9 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +@Disabled @SuppressWarnings("rawtypes") -@ExtendWith(MockitoExtension.class) +@ExtendWith({ MockitoExtension.class, UnitTestExtension.class }) @MockitoSettings(strictness = Strictness.LENIENT) public final class VolumeTransformationTest { @@ -138,6 +143,7 @@ static void setup() { StubMirror.registerDefaults(mirror); game.register(mirror); + builderProvider.register(EventContextKey.Builder.class, SpongeEventContextKeyBuilder::new); builderProvider.register(Transformation.Builder.class, SpongeTransformationBuilder::new); builderProvider.register(StreamOptions.Builder.class, SpongeStreamOptionsBuilder::new); StubRotations.registerDefaults(rotation); From 1043e51ed3a6dbc7119c846a8add651da7db67ba Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 22 Sep 2024 17:43:09 -0700 Subject: [PATCH 219/226] chore: re-add forge item enchantment check --- .../java/org/spongepowered/forge/hook/ForgeItemHooks.java | 6 ++++++ .../chunk/LevelChunk$BoundTickingBlockEntityAccessor.java | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java index 7698314caa6..296d642e82a 100644 --- a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java +++ b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java @@ -24,8 +24,14 @@ */ package org.spongepowered.forge.hook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; import org.spongepowered.common.hooks.ItemHooks; public class ForgeItemHooks implements ItemHooks { + @Override + public boolean canEnchantmentBeAppliedToItem(Enchantment enchantment, ItemStack stack) { + return stack.canApplyAtEnchantingTable(enchantment); + } } diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java index e60eecb48bb..fbb9996ba79 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java @@ -25,7 +25,6 @@ package org.spongepowered.common.accessor.world.level.chunk; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -34,5 +33,4 @@ public interface LevelChunk$BoundTickingBlockEntityAccessor { @Accessor("blockEntity") BlockEntity accessor$blockEntity(); - @Accessor("ticker") BlockEntityTicker accessor$ticker(); } From 34aba64ec0d12f8ddcee5e0798ac743e665cca2d Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Mon, 23 Sep 2024 17:28:49 +0200 Subject: [PATCH 220/226] Fix launch when jar path contains spaces --- .../java/org/spongepowered/vanilla/installer/InstallerMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java index 992785c98d9..b7220520f38 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java @@ -159,7 +159,7 @@ public void downloadAndRun() throws Exception { .toArray(Path[]::new); final URL rootJar = InstallerMain.class.getProtectionDomain().getCodeSource().getLocation(); - final URI fsURI = new URI("jar", rootJar.toString(), null); + final URI fsURI = new URI("jar:" + rootJar); System.setProperty("sponge.rootJarFS", fsURI.toString()); final FileSystem fs = FileSystems.newFileSystem(fsURI, Map.of()); From cf6890725678a5addaff7c3081fc8c9c5f3a6348 Mon Sep 17 00:00:00 2001 From: Yeregorix Date: Thu, 26 Sep 2024 21:40:22 +0200 Subject: [PATCH 221/226] Bump SpongeAPI --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 91e3e5f9ae0..dee177d3367 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 91e3e5f9ae07f8edfb62a9ac7118d716bdf5632c +Subproject commit dee177d336706b2288c1b3585b196aaf962ec41f From 02f45e8f0b4e757e667acd15b84b3e1967cbbe9c Mon Sep 17 00:00:00 2001 From: aromaa Date: Fri, 27 Sep 2024 20:30:21 +0300 Subject: [PATCH 222/226] Ignore PrepareBlockDropsTransaction when generating ChangeBlockEvent.All The transaction is used to associate the drops to block transaction but it does not actually contain any relevant information about the block change --- .../transaction/block/BlockEventBasedTransaction.java | 7 +++++++ .../transaction/block/PrepareBlockDropsTransaction.java | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java index 6ac23abd473..cfcf5df8381 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java @@ -77,6 +77,9 @@ public final Optional generateEvent( final Map eventTransactions = new HashMap<>(); for (final GameTransaction<@NonNull ?> transaction : transactions) { final BlockEventBasedTransaction blockTransaction = (BlockEventBasedTransaction) transaction; + if (!blockTransaction.actualBlockTransaction()) { + continue; + } final SpongeBlockSnapshot original = blockTransaction.getOriginalSnapshot(); final SpongeBlockSnapshot result = blockTransaction.getResultingSnapshot(); final Operation operation = context.getBlockOperation(original, result); @@ -101,6 +104,10 @@ public final Optional generateEvent( )); } + protected boolean actualBlockTransaction() { + return true; + } + protected abstract SpongeBlockSnapshot getResultingSnapshot(); protected abstract SpongeBlockSnapshot getOriginalSnapshot(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java index acfa63ed442..aafa56eb86d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java @@ -52,9 +52,14 @@ public PrepareBlockDropsTransaction( this.originalState = original; } + @Override + protected boolean actualBlockTransaction() { + return false; + } + @Override protected SpongeBlockSnapshot getResultingSnapshot() { - return null; + throw new UnsupportedOperationException(); } @Override From ffa5ec176ea376f501fafe6576da73a2a2bba15a Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 21 Apr 2024 15:29:53 -0700 Subject: [PATCH 223/226] !feat: Refactor Interactions to use Transactions --- SpongeAPI | 2 +- .../bridge/world/TrackedWorldBridge.java | 13 +++ .../event/SpongeCommonEventFactory.java | 4 +- .../context/transaction/EffectTransactor.java | 10 +- .../context/transaction/GameTransaction.java | 31 +++--- .../ResultingTransactionBySideEffect.java | 6 +- .../context/transaction/TransactionSink.java | 38 ++++--- .../TransactionalCaptureSupplier.java | 5 +- .../effect/AddBlockLootDropsEffect.java | 12 ++- .../transaction/effect/BlockAddedEffect.java | 12 ++- .../transaction/effect/BlockChangeArgs.java | 36 +++++++ .../BroadcastInventoryChangesEffect.java | 12 +-- .../CheckBlockPostPlacementIsSameEffect.java | 13 +-- .../effect/ChunkChangeCompleteEffect.java | 12 +-- .../transaction/effect/EffectResult.java | 19 ++-- .../effect/EntityPerformingDropsEffect.java | 10 +- .../effect/ExplodeBlockEffect.java | 16 ++- .../transaction/effect/InteractionArgs.java | 42 ++++++++ .../effect/InteractionItemEffect.java | 58 ++++++++++ .../InteractionUseItemOnBlockEffect.java | 59 ++++++++++ .../transaction/effect/InventoryEffect.java | 10 +- .../effect/NotifyClientEffect.java | 11 +- .../effect/NotifyNeighborSideEffect.java | 12 ++- .../effect/OldBlockOnReplaceEffect.java | 13 +-- .../PerformBlockDropsFromDestruction.java | 10 +- .../effect/PlayerContainerRefreshEffect.java | 52 +++++++++ .../transaction/effect/PrepareBlockDrops.java | 10 +- .../effect/ProcessingSideEffect.java | 13 +-- .../RemoveTileEntityFromChunkEffect.java | 12 +-- ...SetAndRegisterBlockEntityToLevelChunk.java | 12 +-- .../effect/SetBlockToChunkSectionEffect.java | 12 +-- .../effect/SpawnDestructBlocksEffect.java | 12 +-- .../effect/UpdateChunkLightManagerEffect.java | 11 +- .../effect/UpdateConnectingBlocksEffect.java | 13 ++- .../effect/UpdateHeightMapEffect.java | 11 +- .../effect/UpdateLightSideEffect.java | 13 +-- ...reateNewTileEntityPostPlacementEffect.java | 10 +- .../effect/UpdateWorldRendererEffect.java | 11 +- .../transaction/effect/UseItemArgs.java | 41 +++++++ .../transaction/effect/UseItemEffect.java | 64 +++++++++++ .../WorldBlockChangeCompleteEffect.java | 10 +- .../effect/WorldDestroyBlockLevelEffect.java | 10 +- .../inventory/InteractItemTransaction.java | 101 ++++++++++++++++++ .../inventory/InventoryBasedTransaction.java | 5 + .../transaction/pipeline/ChunkPipeline.java | 8 +- .../pipeline/TileEntityPipeline.java | 21 ++-- .../pipeline/UseBlockPipeline.java | 101 ++++++++++++++++++ .../pipeline/UseItemOnBlockPipeline.java | 100 +++++++++++++++++ .../transaction/pipeline/UseItemPipeline.java | 100 +++++++++++++++++ .../transaction/pipeline/WorldPipeline.java | 20 ++-- .../transaction/type/TransactionTypes.java | 3 + .../ai/goal/RunAroundLikeCrazyGoalMixin.java | 6 +- .../level/ServerLevelMixin_Tracker.java | 85 ++++++++++++++- .../ServerPlayerGameModeMixin_Tracker.java | 100 ++++++++--------- .../VolumeTransformationTest.java | 3 +- 55 files changed, 1157 insertions(+), 279 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java diff --git a/SpongeAPI b/SpongeAPI index 5e2393c5166..2680f76e5e1 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 5e2393c51667d56ae3ef2bd8d37a0523dcee1167 +Subproject commit 2680f76e5e107c87f76362751a706a7987535c7c diff --git a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java index fbc9060b94c..06670ba5551 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java @@ -26,11 +26,16 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.BlockHitResult; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.world.BlockChangeFlag; @@ -41,6 +46,9 @@ import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; import java.util.Optional; @@ -111,4 +119,9 @@ public interface TrackedWorldBridge { */ SpongeBlockSnapshot bridge$createSnapshotWithEntity(BlockState state, BlockPos pos, BlockChangeFlag updateFlag, @Nullable BlockEntity tileEntity); + UseItemOnBlockPipeline bridge$startInteractionUseOnChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); + + UseBlockPipeline bridge$startInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); + + UseItemPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); } diff --git a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java index acb07d0647e..8a7cafccb92 100644 --- a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java +++ b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java @@ -344,10 +344,10 @@ public static InteractBlockEvent.Primary callInteractBlockEventPrimary(final Ser } } - public static InteractBlockEvent.Secondary callInteractBlockEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack heldItem, final Vector3d hitVec, final BlockSnapshot targetBlock, final Direction targetSide, final InteractionHand hand) { + public static InteractBlockEvent.Secondary.Pre callInteractBlockEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack heldItem, final Vector3d hitVec, final BlockSnapshot targetBlock, final Direction targetSide, final InteractionHand hand) { try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { SpongeCommonEventFactory.applyCommonInteractContext(player, heldItem, hand, targetBlock, null, frame); - final InteractBlockEvent.Secondary event = SpongeEventFactory.createInteractBlockEventSecondary(frame.currentCause(), + final InteractBlockEvent.Secondary.Pre event = SpongeEventFactory.createInteractBlockEventSecondaryPre(frame.currentCause(), Tristate.UNDEFINED, Tristate.UNDEFINED, Tristate.UNDEFINED, Tristate.UNDEFINED, targetBlock, hitVec, targetSide); SpongeCommon.post(event); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java index cabf97ef8ca..b1e025c7e73 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java @@ -30,13 +30,13 @@ import java.util.Deque; public class EffectTransactor implements AutoCloseable { - final @Nullable ResultingTransactionBySideEffect previousEffect; + final @Nullable ResultingTransactionBySideEffect previousEffect; public final @Nullable GameTransaction<@NonNull ?> parent; private final TransactionalCaptureSupplier supplier; - private final ResultingTransactionBySideEffect effect; + private final ResultingTransactionBySideEffect effect; - EffectTransactor(final ResultingTransactionBySideEffect effect, final @Nullable GameTransaction<@NonNull ?> parent, - final @Nullable ResultingTransactionBySideEffect previousEffect, final TransactionalCaptureSupplier transactor) { + EffectTransactor(final ResultingTransactionBySideEffect effect, final @Nullable GameTransaction<@NonNull ?> parent, + final @Nullable ResultingTransactionBySideEffect previousEffect, final TransactionalCaptureSupplier transactor) { /* | ChangeBlock(1) <- head will be RemoveTileEntity(1), tail is still RemoveTileentity(1) | |- RemoveTileEntity <- Head will be ChangeBlock(2) tail is still ChangeBlock(2) @@ -55,7 +55,7 @@ public void close() { && this.parent.sideEffects != null && this.parent.getEffects().peekLast() == this.effect ) { - final Deque effects = this.parent.getEffects(); + final Deque> effects = this.parent.getEffects(); effects.removeLast(); if (effects.isEmpty()) { this.parent.sideEffects = null; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java index d546d535e8e..fd733d01d77 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java @@ -54,7 +54,7 @@ public abstract class GameTransaction implements protected boolean cancelled = false; // Children Definitions - @Nullable LinkedList sideEffects; + @Nullable LinkedList> sideEffects; // LinkedList node definitions @Nullable GameTransaction<@NonNull ?> previous; @@ -75,14 +75,14 @@ public final TransactionType getTransactionType() { return this.transactionType; } - final Deque getEffects() { + final Deque> getEffects() { if (this.sideEffects == null) { this.sideEffects = new LinkedList<>(); } return this.sideEffects; } - public final void addLast(final ResultingTransactionBySideEffect effect) { + public final void addLast(final ResultingTransactionBySideEffect effect) { if (this.sideEffects == null) { this.sideEffects = new LinkedList<>(); } @@ -97,7 +97,7 @@ public final boolean hasAnyPrimaryChildrenTransactions() { if (this.sideEffects == null) { return false; } - for (final ResultingTransactionBySideEffect sideEffect : this.sideEffects) { + for (final ResultingTransactionBySideEffect sideEffect : this.sideEffects) { @Nullable GameTransaction<@NonNull ?> transaction = sideEffect.head; while (transaction != null) { if (transaction.transactionType.isPrimary() || transaction.hasChildTransactions()) { @@ -131,10 +131,17 @@ public abstract Optional generateEvent( public final void markCancelled() { this.cancelled = true; this.childIterator().forEachRemaining(GameTransaction::markCancelled); + if (this.next != null && this.next.hasUnknownChainRequiringCancellation()) { + this.next.markCancelled(); + } } public abstract boolean markCancelledTransactions(E event, ImmutableList> transactions); + protected boolean hasUnknownChainRequiringCancellation() { + return false; + } + public void postProcessEvent(final PhaseContext<@NonNull ?> context, final E event) { } @@ -183,16 +190,16 @@ protected void captureState() { } private static class ChildIterator implements Iterator> { - private final Iterator effectIterator; + private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedNext; private @MonotonicNonNull GameTransaction<@NonNull ?> pointer; private boolean hasNoRemainingElements = false; - ChildIterator(final Iterator iterator) { + ChildIterator(final Iterator> iterator) { // We're going to search the iterator's effects until we find the first at least this.effectIterator = iterator; while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.head != null) { this.cachedNext = next.head; this.pointer = next.head; @@ -219,7 +226,7 @@ public boolean hasNext() { // start search for the next, sadly because effects don't make a clean chain, // there can be many effects with no transactions recorded while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.head != null) { this.cachedNext = next.head; return true; @@ -250,16 +257,16 @@ public boolean hasNext() { private static class ReverseChildIterator implements Iterator> { - private final Iterator effectIterator; + private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedPrevious; private @MonotonicNonNull GameTransaction<@NonNull ?> pointer; private boolean hasNoRemainingElements = false; - ReverseChildIterator(final Iterator iterator) { + ReverseChildIterator(final Iterator> iterator) { // We're going to search the iterator's effects until we find the first at least this.effectIterator = iterator; while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.tail != null) { this.pointer = next.tail; this.cachedPrevious = next.tail; @@ -287,7 +294,7 @@ public boolean hasNext() { // start search for the next, sadly because effects don't make a clean chain, // there can be many effects with no transactions recorded while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.tail != null) { this.cachedPrevious = next.tail; return true; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java index c224628dbbc..3cae058b582 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java @@ -33,12 +33,12 @@ import java.util.Iterator; import java.util.Optional; -public class ResultingTransactionBySideEffect { - public final ProcessingSideEffect effect; +public class ResultingTransactionBySideEffect { + public final ProcessingSideEffect effect; @Nullable GameTransaction<@NonNull ?> head; @Nullable GameTransaction<@NonNull ?> tail; - public ResultingTransactionBySideEffect(final ProcessingSideEffect effect) { + public ResultingTransactionBySideEffect(final ProcessingSideEffect effect) { this.effect = effect; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java index da8863ac6b2..7da6b49814f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java @@ -27,6 +27,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -45,12 +46,14 @@ import net.minecraft.world.ticks.ScheduledTick; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.crafting.CraftingInventory; import org.spongepowered.api.item.inventory.transaction.SlotTransaction; +import org.spongepowered.api.util.Direction; import org.spongepowered.api.world.BlockChangeFlag; import org.spongepowered.api.world.BlockChangeFlags; import org.spongepowered.common.SpongeCommon; @@ -73,6 +76,7 @@ import org.spongepowered.common.event.tracking.context.transaction.effect.EntityPerformingDropsEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; +import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.event.tracking.context.transaction.inventory.ClickCreativeMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ClickMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.CloseMenuTransaction; @@ -81,6 +85,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.CraftingTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.DropFromPlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ExplicitInventoryOmittedTransaction; +import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.OpenMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlaceRecipeTransaction; @@ -98,6 +103,7 @@ import org.spongepowered.common.world.BlockChange; import org.spongepowered.common.world.SpongeBlockChangeFlag; import org.spongepowered.common.world.volume.VolumeStreamUtils; +import org.spongepowered.math.vector.Vector3d; import java.lang.ref.WeakReference; import java.util.Objects; @@ -122,7 +128,7 @@ interface TransactionSink { @Deprecated void logTransaction(StatefulTransaction transaction); - EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect); + EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect); default ChangeBlock logBlockChange(final SpongeBlockSnapshot originalBlockSnapshot, final BlockState newState, final BlockChangeFlag flags @@ -175,7 +181,7 @@ default EffectTransactor logBlockDrops( original.blockChange = BlockChange.MODIFY; final PrepareBlockDropsTransaction transaction = new PrepareBlockDropsTransaction(pos, state, original); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(PrepareBlockDrops.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(PrepareBlockDrops.getInstance())); } @SuppressWarnings("ConstantConditions") @@ -269,7 +275,7 @@ default boolean logTileRemoval(final @Nullable BlockEntity tileentity, final Sup final EntityPerformingDropsTransaction transaction = new EntityPerformingDropsTransaction(entity); this.logTransaction(transaction); if (transaction.recorded()) { - return this.pushEffect(new ResultingTransactionBySideEffect(EntityPerformingDropsEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(EntityPerformingDropsEffect.getInstance())); } return null; } @@ -345,44 +351,44 @@ default EffectTransactor logClickContainer( final ClickMenuTransaction transaction = new ClickMenuTransaction( player, menu, slotNum, buttonNum, clickType, slot, ItemStackUtil.snapshotOf(player.containerMenu.getCarried())); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logPlayerInventoryChangeWithEffect(final Player player, final PlayerInventoryTransaction.EventCreator eventCreator) { final PlayerInventoryTransaction transaction = new PlayerInventoryTransaction(player, eventCreator); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logCreativeClickContainer(final int slotNum, final ItemStackSnapshot creativeStack, final Player player) { final ClickCreativeMenuTransaction transaction = new ClickCreativeMenuTransaction(player, slotNum, creativeStack); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logDropFromPlayerInventory(final ServerPlayer player, final boolean dropAll) { final DropFromPlayerInventoryTransaction transaction = new DropFromPlayerInventoryTransaction(player, dropAll); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logOpenInventory(final Player player) { final OpenMenuTransaction transaction = new OpenMenuTransaction(player); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logCloseInventory(final Player player, final boolean clientSource) { final CloseMenuTransaction transaction = new CloseMenuTransaction(player, clientSource); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logPlaceRecipe(final boolean shift, final RecipeHolder> recipe, final ServerPlayer player, final CraftingInventory craftInv) { final PlaceRecipeTransaction transaction = new PlaceRecipeTransaction(player, shift, recipe, craftInv); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default void logSelectTrade(final ServerPlayer player, final int item) { @@ -414,12 +420,20 @@ default void logCrafting(final Player player, @Nullable final ItemStack craftedS default EffectTransactor logIgnoredInventory(AbstractContainerMenu containerMenu) { final ExplicitInventoryOmittedTransaction transaction = new ExplicitInventoryOmittedTransaction(containerMenu); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logInventoryTransaction(final AbstractContainerMenu containerMenu) { final InventoryTransaction transaction = new InventoryTransaction((Inventory) containerMenu); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } + + default void logSecondaryInteractionTransaction( + final ServerPlayer playerIn, final ItemStack stackIn, final Vector3d hitVec, + final BlockSnapshot snapshot, final Direction direction, final InteractionHand handIn) { + final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + this.logTransaction(transaction); + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java index 29288ef3395..9a32ad5960b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java @@ -38,6 +38,7 @@ import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.ICaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; +import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.event.tracking.context.transaction.type.TransactionType; import java.util.Collections; @@ -94,9 +95,9 @@ public boolean isEmpty() { */ @Override - public EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect) { + public EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect) { final GameTransaction<@NonNull ?> parentTransaction = Optional.ofNullable(this.effect) - .map(child -> (GameTransaction) child.tail) + .map(child -> child.tail) .orElse(Objects.requireNonNull(this.tail, "Somehow pushing a new effect without an owning Transaction")); final EffectTransactor effectTransactor = new EffectTransactor(effect, parentTransaction, this.effect, this); this.effect = effect; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java index 51e1a40d109..da1c2c16fc1 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java @@ -40,7 +40,7 @@ import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class AddBlockLootDropsEffect implements ProcessingSideEffect { +public final class AddBlockLootDropsEffect implements ProcessingSideEffect { private static final class Holder { static final AddBlockLootDropsEffect INSTANCE = new AddBlockLootDropsEffect(); @@ -53,10 +53,12 @@ public static AddBlockLootDropsEffect getInstance() { AddBlockLootDropsEffect() {} @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); + final int limit = args.limit(); final PhaseContext<@NonNull ?> phaseContext = PhaseTracker.getInstance().getPhaseContext(); final ServerLevel world = pipeline.getServerWorld(); @@ -70,6 +72,6 @@ public EffectResult processSideEffect( phaseContext.populateLootContext(lootBuilder); - return new EffectResult(newState, oldState.state.getDrops(lootBuilder), false); + return new EffectResult<>(newState, oldState.state.getDrops(lootBuilder), false); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java index bb2a8c66667..9393bc5d5bd 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class BlockAddedEffect implements ProcessingSideEffect { +public final class BlockAddedEffect implements ProcessingSideEffect { private static final class Holder { static final BlockAddedEffect INSTANCE = new BlockAddedEffect(); @@ -42,9 +42,11 @@ public static BlockAddedEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var flag = args.flag(); + final var newState = args.newState(); // Vanilla will check if this is the server // if (!this.level.isClientSide) { // var2.onPlace(this.level, var1, var11, var3); @@ -55,6 +57,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli if (flag.performBlockPhysics()) { newState.onPlace(pipeline.getServerWorld(), oldState.pos, oldState.state, flag.movingBlocks()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java new file mode 100644 index 00000000000..2a572a21dc3 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java @@ -0,0 +1,36 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.common.world.SpongeBlockChangeFlag; + +public record BlockChangeArgs( + BlockState newState, + SpongeBlockChangeFlag flag, + int limit +) implements ProcessingSideEffect.Args { + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java index 8664482ce9b..5d4300c3fb2 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java @@ -25,14 +25,14 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class BroadcastInventoryChangesEffect implements ProcessingSideEffect { +public final class BroadcastInventoryChangesEffect implements ProcessingSideEffect { private static final class Holder { static final BroadcastInventoryChangesEffect INSTANCE = new BroadcastInventoryChangesEffect(); @@ -41,16 +41,16 @@ public static BroadcastInventoryChangesEffect getInstance() { return Holder.INSTANCE; } public static EffectTransactor transact(final TransactionalCaptureSupplier transactor) { - return transactor.pushEffect(new ResultingTransactionBySideEffect(BroadcastInventoryChangesEffect.getInstance())); + return transactor.pushEffect(new ResultingTransactionBySideEffect<>(BroadcastInventoryChangesEffect.getInstance())); } BroadcastInventoryChangesEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java index f3693379738..e1d19a94e6c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class CheckBlockPostPlacementIsSameEffect implements ProcessingSideEffect { +public final class CheckBlockPostPlacementIsSameEffect implements ProcessingSideEffect { private static final class Holder { static final CheckBlockPostPlacementIsSameEffect INSTANCE = new CheckBlockPostPlacementIsSameEffect(); } @@ -40,17 +40,18 @@ public static CheckBlockPostPlacementIsSameEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final int x = oldState.pos.getX() & 15; final int y = oldState.pos.getY() & 15; final int z = oldState.pos.getZ() & 15; final BlockState currentState = chunkSection.getBlockState(x, y, z); if (!currentState.is(newState.getBlock())) { - return new EffectResult(newState, true); + return new EffectResult<>(newState, true); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java index eecb265b5b7..dc78f969d9b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java @@ -26,15 +26,16 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class ChunkChangeCompleteEffect implements ProcessingSideEffect { +public final class ChunkChangeCompleteEffect implements ProcessingSideEffect { private static final class Holder { static final ChunkChangeCompleteEffect INSTANCE = new ChunkChangeCompleteEffect(); } + ChunkChangeCompleteEffect() { } @@ -43,13 +44,12 @@ public static ChunkChangeCompleteEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - final LevelChunk chunk = pipeline.getAffectedChunk(); // this.unsaved = true; // Vanilla, we'll just call the accessor available chunk.setUnsaved(true); - return new EffectResult(oldState.state, true); + return new EffectResult<>(oldState.state, true); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java index 3ceacfb2e23..e6076ae2b0b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java @@ -25,30 +25,35 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collections; import java.util.List; -public final class EffectResult { +public final class EffectResult<@Nullable R> { - public static final EffectResult NULL_RETURN = new EffectResult(null, true); - public static final EffectResult NULL_PASS = new EffectResult(null, false); + public static <@Nullable T> EffectResult nullReturn() { + return new EffectResult<>(null, true); + } + + public static <@Nullable T> EffectResult nullPass() { + return new EffectResult<>(null, false); + } - public final @Nullable BlockState resultingState; + public final @Nullable R resultingState; public final List drops; public final boolean hasResult; - public EffectResult(final @Nullable BlockState resultingState, final boolean hasResult) { + public EffectResult(final @Nullable R resultingState, final boolean hasResult) { this.resultingState = resultingState; this.hasResult = hasResult; this.drops = Collections.emptyList(); } - public EffectResult(final @Nullable BlockState resultingState, final List drops, final boolean hasResult) { + public EffectResult(final @Nullable R resultingState, final List drops, final boolean hasResult) { this.resultingState = resultingState; this.drops = drops; this.hasResult = hasResult; } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java index eeb7ee4e4e5..4d9d4065a3d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class EntityPerformingDropsEffect implements ProcessingSideEffect { +public final class EntityPerformingDropsEffect implements ProcessingSideEffect { private static final class Holder { static final EntityPerformingDropsEffect INSTANCE = new EntityPerformingDropsEffect(); @@ -40,10 +40,10 @@ public static EntityPerformingDropsEffect getInstance() { EntityPerformingDropsEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java index baaf064fadd..7f5351e7cf7 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java @@ -28,14 +28,14 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.phase.general.ExplosionContext; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class ExplodeBlockEffect implements ProcessingSideEffect { +public final class ExplodeBlockEffect implements ProcessingSideEffect { private static final class Holder { static final ExplodeBlockEffect INSTANCE = new ExplodeBlockEffect(); @@ -47,20 +47,18 @@ public static ExplodeBlockEffect getInstance() { ExplodeBlockEffect() {} - @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final PhaseContext<@NonNull ?> phaseContext = PhaseTracker.getInstance().getPhaseContext(); final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos; - if (phaseContext instanceof ExplosionContext) { - oldState.state.getBlock().wasExploded(world, pos, ((ExplosionContext) phaseContext).getExplosion()); + if (phaseContext instanceof ExplosionContext ec) { + oldState.state.getBlock().wasExploded(world, pos, ec.getExplosion()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java new file mode 100644 index 00000000000..fac849e78d2 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java @@ -0,0 +1,42 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public record InteractionArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult blockRaytraceResult, + BlockState blockstate, + ItemStack copiedStack +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java new file mode 100644 index 00000000000..8ccfc3a0b4e --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java @@ -0,0 +1,58 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; + +public final class InteractionItemEffect implements ProcessingSideEffect { + + private static final class Holder { + static final InteractionItemEffect INSTANCE = new InteractionItemEffect(); + } + + public static InteractionItemEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + ) { + final var player = args.player(); + final var world = args.world(); + final var blockstate = args.blockstate(); + final var blockHitResult = args.blockRaytraceResult(); + final InteractionResult result = blockstate.useWithoutItem(world, player, blockHitResult); + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java new file mode 100644 index 00000000000..71d393a62fe --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java @@ -0,0 +1,59 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.ItemInteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; + +public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { + + private static final class Holder { + static final InteractionUseItemOnBlockEffect INSTANCE = new InteractionUseItemOnBlockEffect(); + } + + public static InteractionUseItemOnBlockEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionArgs args + ) { + final var player = args.player(); + final var hand = args.hand(); + final var world = args.world(); + final var blockRaytraceResult = args.blockRaytraceResult(); + final var blockstate = args.blockstate(); + final ItemInteractionResult result = blockstate.useItemOn(args.copiedStack(), world, player, hand, blockRaytraceResult); + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java index 459b9c9c038..e58f1cb2849 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class InventoryEffect implements ProcessingSideEffect { +public final class InventoryEffect implements ProcessingSideEffect { private static final class Holder { static final InventoryEffect INSTANCE = new InventoryEffect(); @@ -40,10 +40,10 @@ public static InventoryEffect getInstance() { InventoryEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java index 63f49fc4df6..ac60a832af4 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java @@ -28,11 +28,12 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class NotifyClientEffect implements ProcessingSideEffect { +public final class NotifyClientEffect implements ProcessingSideEffect { private static final class Holder { static final NotifyClientEffect INSTANCE = new NotifyClientEffect(); @@ -45,9 +46,11 @@ public static NotifyClientEffect getInstance() { NotifyClientEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); final LevelChunk chunk = pipeline.getAffectedChunk(); final ServerLevel world = pipeline.getServerWorld(); @@ -58,7 +61,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli // this.notifyBlockUpdate(pos, blockstate, newWorldState, flags); world.sendBlockUpdated(oldState.pos, oldState.state, newState, flag.getRawFlag()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java index 8702afdf483..309f7f8d8a1 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java @@ -26,11 +26,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class NotifyNeighborSideEffect implements ProcessingSideEffect { +public final class NotifyNeighborSideEffect implements ProcessingSideEffect { private static final class Holder { static final NotifyNeighborSideEffect INSTANCE = new NotifyNeighborSideEffect(); @@ -44,9 +44,11 @@ public static NotifyNeighborSideEffect getInstance() { @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var flag = args.flag(); + final var newState = args.newState(); final ServerLevel world = pipeline.getServerWorld(); // Vanilla isClientSide is redundant @@ -59,7 +61,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli world.updateNeighbourForOutputSignal(oldState.pos, newState.getBlock()); } } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java index ffaaf61c60b..60be05b5664 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class OldBlockOnReplaceEffect implements ProcessingSideEffect { +public final class OldBlockOnReplaceEffect implements ProcessingSideEffect { private static final class Holder { static final OldBlockOnReplaceEffect INSTANCE = new OldBlockOnReplaceEffect(); } @@ -42,9 +42,8 @@ public static OldBlockOnReplaceEffect getInstance() { } @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { // Normally, vanilla does this: // boolean var14 = var11.hasBlockEntity(); @@ -56,7 +55,9 @@ public EffectResult processSideEffect( // However, since we know we're not on the client (ChunkPipeline is not // used outside of server world context) // we can safely just do oldState.onRemove(this.level, var1, var2, var3). + final var flag = args.flag(); + final var newState = args.newState(); oldState.state.onRemove(pipeline.getServerWorld(), oldState.pos, newState, flag.movingBlocks()); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java index 0e6a2b9d443..04439d1ccac 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java @@ -27,11 +27,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class PerformBlockDropsFromDestruction implements ProcessingSideEffect { +public final class PerformBlockDropsFromDestruction implements ProcessingSideEffect { private static final class Holder { static final PerformBlockDropsFromDestruction INSTANCE = new PerformBlockDropsFromDestruction(); @@ -43,11 +43,11 @@ public static PerformBlockDropsFromDestruction getInstance() { PerformBlockDropsFromDestruction() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { Block.dropResources(oldState.state, pipeline.getServerWorld(), oldState.pos, oldState.tileEntity, oldState.destroyer, ItemStack.EMPTY); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java new file mode 100644 index 00000000000..a0f81ef9ad0 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java @@ -0,0 +1,52 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; + +public final class PlayerContainerRefreshEffect implements ProcessingSideEffect { + + private static final class Holder { + static final PlayerContainerRefreshEffect INSTANCE = new PlayerContainerRefreshEffect(); + } + + public static PlayerContainerRefreshEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemOnBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + ) { + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return EffectResult.nullPass(); + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java index 9c3c772729e..4ea2225adf3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class PrepareBlockDrops implements ProcessingSideEffect { +public final class PrepareBlockDrops implements ProcessingSideEffect { private static final class Holder { static final PrepareBlockDrops INSTANCE = new PrepareBlockDrops(); @@ -41,10 +41,10 @@ public static PrepareBlockDrops getInstance() { PrepareBlockDrops() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java index 2d62b184f61..6c4a7d1ff09 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java @@ -24,16 +24,13 @@ */ package org.spongepowered.common.event.tracking.context.transaction.effect; -import net.minecraft.world.level.block.state.BlockState; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; +import org.checkerframework.checker.nullness.qual.Nullable; @FunctionalInterface -public interface ProcessingSideEffect { +public interface ProcessingSideEffect { - EffectResult processSideEffect(BlockPipeline pipeline, PipelineCursor oldState, BlockState newState, SpongeBlockChangeFlag flag, - int limit - ); + EffectResult processSideEffect(T pipeline, C oldState, A args); + + sealed interface Args permits BlockChangeArgs, InteractionArgs, UseItemArgs {} } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java index cc118789df8..be36d177080 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class RemoveTileEntityFromChunkEffect implements ProcessingSideEffect { +public final class RemoveTileEntityFromChunkEffect implements ProcessingSideEffect { private static final class Holder { static final RemoveTileEntityFromChunkEffect INSTANCE = new RemoveTileEntityFromChunkEffect(); @@ -43,14 +43,14 @@ public static RemoveTileEntityFromChunkEffect getInstance() { RemoveTileEntityFromChunkEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final BlockEntity tileEntity = oldState.tileEntity; if (tileEntity == null) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } pipeline.getAffectedChunk().removeBlockEntity(oldState.pos); - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java index 7733123bc27..8a6acbea8f6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java @@ -31,9 +31,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class SetAndRegisterBlockEntityToLevelChunk implements ProcessingSideEffect { +public final class SetAndRegisterBlockEntityToLevelChunk implements ProcessingSideEffect { private static final class Holder { static final SetAndRegisterBlockEntityToLevelChunk INSTANCE = new SetAndRegisterBlockEntityToLevelChunk(); @@ -46,17 +45,16 @@ public static SetAndRegisterBlockEntityToLevelChunk getInstance() { SetAndRegisterBlockEntityToLevelChunk() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel serverWorld = pipeline.getServerWorld(); final @Nullable BlockEntity blockEntity = oldState.tileEntity; final BlockPos pos = oldState.pos; if (serverWorld.isOutsideBuildHeight(pos)) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } pipeline.getAffectedChunk().addAndRegisterBlockEntity(blockEntity); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java index 6db0b84c8fa..3a2d37ecc7b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class SetBlockToChunkSectionEffect implements ProcessingSideEffect { +public final class SetBlockToChunkSectionEffect implements ProcessingSideEffect { private static final class Holder { private static final SetBlockToChunkSectionEffect INSTANCE = new SetBlockToChunkSectionEffect(); @@ -42,17 +42,17 @@ public static SetBlockToChunkSectionEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final int x = oldState.pos.getX() & 15; final int y = oldState.pos.getY() & 15; final int z = oldState.pos.getZ() & 15; final BlockState oldStateReturned = chunkSection.setBlockState(x, y, z, newState); if (oldStateReturned == newState) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java index b167636ec06..5b5304022cf 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java @@ -29,13 +29,13 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; import java.util.List; -public final class SpawnDestructBlocksEffect implements ProcessingSideEffect { +public final class SpawnDestructBlocksEffect implements ProcessingSideEffect { private static final class Holder { static final SpawnDestructBlocksEffect INSTANCE = new SpawnDestructBlocksEffect(); @@ -47,11 +47,9 @@ public static SpawnDestructBlocksEffect getInstance() { SpawnDestructBlocksEffect() {} - @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos; @@ -60,6 +58,6 @@ public EffectResult processSideEffect( drops.forEach(drop -> Block.popResource(world, pos, drop)); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java index b27cfad1ec7..9a665d98ebc 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateChunkLightManagerEffect implements ProcessingSideEffect { +public final class UpdateChunkLightManagerEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateChunkLightManagerEffect INSTANCE = new UpdateChunkLightManagerEffect(); @@ -43,9 +43,8 @@ public static UpdateChunkLightManagerEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final boolean wasEmpty = pipeline.wasEmpty(); @@ -53,6 +52,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli if (wasEmpty != isStillEmpty) { pipeline.getServerWorld().getChunkSource().getLightEngine().updateSectionStatus(oldState.pos, isStillEmpty); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java index ca520619017..7bc888a6774 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java @@ -27,11 +27,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateConnectingBlocksEffect implements ProcessingSideEffect { +public final class UpdateConnectingBlocksEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateConnectingBlocksEffect INSTANCE = new UpdateConnectingBlocksEffect(); @@ -44,11 +44,14 @@ public static UpdateConnectingBlocksEffect getInstance() { UpdateConnectingBlocksEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos; + final var flag = args.flag(); + final var newState = args.newState(); + final var limit = args.limit(); if (flag.updateNeighboringShapes() && limit > 0) { // int i = p_241211_3_ & -34; // Vanilla negates 34 to flip neighbor notification and and "state drops" final int withoutNeighborDropsAndNestedNeighborUpdates = flag.asNestedNeighborUpdates().getRawFlag(); @@ -60,7 +63,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli newState.updateIndirectNeighbourShapes(world, pos, withoutNeighborDropsAndNestedNeighborUpdates, limit - 1); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java index 00693ff8e4a..8d33d0815a9 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java @@ -26,14 +26,14 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.Heightmap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.accessor.world.level.chunk.ChunkAccessAccessor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; import java.util.Map; -public final class UpdateHeightMapEffect implements ProcessingSideEffect { +public final class UpdateHeightMapEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateHeightMapEffect INSTANCE = new UpdateHeightMapEffect(); @@ -46,9 +46,10 @@ public static UpdateHeightMapEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final Map heightMap = ((ChunkAccessAccessor) pipeline.getAffectedChunk()).accessor$heightmaps(); if (heightMap == null) { throw new IllegalStateException("Heightmap dereferenced!"); @@ -60,6 +61,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli heightMap.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(x, y, z, newState); heightMap.get(Heightmap.Types.OCEAN_FLOOR).update(x, y, z, newState); heightMap.get(Heightmap.Types.WORLD_SURFACE).update(x, y, z, newState); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java index 38c38aeaed3..b58ed1430c8 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java @@ -26,11 +26,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateLightSideEffect implements ProcessingSideEffect { +public final class UpdateLightSideEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateLightSideEffect INSTANCE = new UpdateLightSideEffect(); @@ -44,12 +44,13 @@ public static UpdateLightSideEffect getInstance() { } @Override - public EffectResult processSideEffect( + public EffectResult<@Nullable BlockState> processSideEffect( final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + final BlockChangeArgs args ) { + final var flag = args.flag(); if (!flag.updateLighting()) { - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } final int originalOpactiy = oldState.opacity; final ServerLevel serverWorld = pipeline.getServerWorld(); @@ -80,7 +81,7 @@ public EffectResult processSideEffect( // this.profiler.endSection(); serverWorld.getProfiler().pop(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java index 0ecc8ef372d..00137c776da 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java @@ -33,9 +33,8 @@ import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateOrCreateNewTileEntityPostPlacementEffect implements ProcessingSideEffect { +public final class UpdateOrCreateNewTileEntityPostPlacementEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateOrCreateNewTileEntityPostPlacementEffect INSTANCE = new UpdateOrCreateNewTileEntityPostPlacementEffect(); @@ -49,9 +48,10 @@ public static UpdateOrCreateNewTileEntityPostPlacementEffect getInstance() { @SuppressWarnings("deprecation") @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final ServerLevel serverWorld = pipeline.getServerWorld(); final LevelChunk chunk = pipeline.getAffectedChunk(); if (((BlockStateBridge) newState).bridge$hasTileEntity()) { @@ -69,6 +69,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli ((LevelChunkAccessor) chunk).accessor$updateBlockEntityTicker(maybeNewTileEntity); } } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java index 67608577360..6f58022fb8e 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateWorldRendererEffect implements ProcessingSideEffect { +public final class UpdateWorldRendererEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateWorldRendererEffect INSTANCE = new UpdateWorldRendererEffect(); @@ -42,12 +42,13 @@ public static UpdateWorldRendererEffect getInstance() { UpdateWorldRendererEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, + final BlockChangeArgs args ) { + final var newState = args.newState(); if (oldState.state != newState) { pipeline.getServerWorld().setBlocksDirty(oldState.pos, oldState.state, newState); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java new file mode 100644 index 00000000000..aebd7497bb2 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; + +public record UseItemArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult result, + ItemStack copiedStack, + boolean creative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java new file mode 100644 index 00000000000..130e414c734 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java @@ -0,0 +1,64 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.UseOnContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; + +public class UseItemEffect implements ProcessingSideEffect { + + private static final class Holder { + static final UseItemEffect INSTANCE = new UseItemEffect(); + } + + public static UseItemEffect getInstance() { + return UseItemEffect.Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemPipeline pipeline, InteractionResult oldState, UseItemArgs args + ) { + final var stack = args.copiedStack(); + final InteractionResult result; + final var context = new UseOnContext(args.player(), args.hand(), args.result()); + if (args.creative()) { + int $$14 = stack.getCount(); + result = stack.useOn(context); + stack.setCount($$14); + } else { + result = stack.useOn(context); + } + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java index 3afdc4e476f..fd6478789c3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java @@ -25,11 +25,12 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class WorldBlockChangeCompleteEffect implements ProcessingSideEffect{ +public final class WorldBlockChangeCompleteEffect implements ProcessingSideEffect { private static final class Holder { static final WorldBlockChangeCompleteEffect INSTANCE = new WorldBlockChangeCompleteEffect(); @@ -42,12 +43,13 @@ public static WorldBlockChangeCompleteEffect getInstance() { WorldBlockChangeCompleteEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); if (flag.notifyPathfinding()) { pipeline.getServerWorld().onBlockStateChange(oldState.pos, oldState.state, newState); } - return new EffectResult(oldState.state, true); + return new EffectResult<>(oldState.state, true); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java index d1dafaa2841..2bb6737698e 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java @@ -27,11 +27,11 @@ import net.minecraft.world.level.block.BaseFireBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class WorldDestroyBlockLevelEffect implements ProcessingSideEffect { +public final class WorldDestroyBlockLevelEffect implements ProcessingSideEffect { private static final class Holder { static final WorldDestroyBlockLevelEffect INSTANCE = new WorldDestroyBlockLevelEffect(); @@ -44,12 +44,12 @@ public static WorldDestroyBlockLevelEffect getInstance() { WorldDestroyBlockLevelEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { if (!(oldState.state.getBlock() instanceof BaseFireBlock)) { pipeline.getServerWorld().levelEvent(2001, oldState.pos, Block.getId(oldState.state)); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java new file mode 100644 index 00000000000..3302e01d076 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java @@ -0,0 +1,101 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.util.Direction; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; +import org.spongepowered.common.item.util.ItemStackUtil; +import org.spongepowered.common.util.PrettyPrinter; +import org.spongepowered.math.vector.Vector3d; + +import java.util.Optional; +import java.util.function.BiConsumer; + +public class InteractItemTransaction extends GameTransaction { + + + private final Vector3d hitVec; + private final BlockSnapshot snapshot; + private final Direction direction; + private final InteractionHand hand; + private final ItemStackSnapshot stack; + + public InteractItemTransaction(ServerPlayer playerIn, ItemStack stackIn, Vector3d hitVec, BlockSnapshot snapshot, Direction direction, InteractionHand handIn) { + super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + this.stack = ItemStackUtil.snapshotOf(stackIn); + this.hitVec = hitVec; + this.snapshot = snapshot; + this.direction = direction; + this.hand = handIn; + } + + + @Override + public Optional, CauseStackManager.StackFrame>> getFrameMutator( + @Nullable GameTransaction<@NonNull ?> parent + ) { + return Optional.empty(); + } + + @Override + public void addToPrinter(PrettyPrinter printer) { + + } + + @Override + public Optional generateEvent( + final PhaseContext<@NonNull ?> context, + final @Nullable GameTransaction<@NonNull ?> parent, + final ImmutableList> gameTransactions, + final Cause currentCause + ) { + return Optional.empty(); + } + + @Override + public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Composite event) { + + } + + @Override + public boolean markCancelledTransactions( + final InteractBlockEvent.Secondary.Composite event, + final ImmutableList> gameTransactions) { + return false; + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java index 45672accf3a..be736521434 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java @@ -67,6 +67,11 @@ protected InventoryBasedTransaction(final Inventory inventory) { this.inventory = inventory; } + @Override + protected boolean hasUnknownChainRequiringCancellation() { + return true; + } + @Override public Optional, CauseStackManager.StackFrame>> getFrameMutator( @Nullable final GameTransaction<@NonNull ?> parent diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java index a6b34239bc1..7c33c35b7af 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java @@ -37,6 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.block.ChangeBlock; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -118,12 +119,11 @@ public LevelChunkSection getAffectedSection() { for (final ResultingTransactionBySideEffect effect : this.chunkEffects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( + final var args = new BlockChangeArgs(proposedState, flag, limit); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( this, formerState, - proposedState, - flag, - limit + args ); if (result.hasResult) { return result.resultingState; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java index ac6fdd6ac4b..35b6b4d1360 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java @@ -26,6 +26,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import org.checkerframework.checker.nullness.qual.Nullable; @@ -33,6 +34,7 @@ import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -49,7 +51,7 @@ public final class TileEntityPipeline implements BlockPipeline { private final @Nullable Supplier chunkSupplier; private final @Nullable Supplier serverWorld; private final @Nullable Supplier sectionSupplier; - private final List effects; + private final List> effects; private TileEntityPipeline(final Builder builder) { this.chunkSupplier = builder.chunkSupplier; @@ -98,15 +100,18 @@ public boolean wasEmpty() { public boolean processEffects(final PhaseContext context, final PipelineCursor initialCursor) { PipelineCursor currentCursor = initialCursor; - for (final ResultingTransactionBySideEffect effect : this.effects) { + for (final ResultingTransactionBySideEffect effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( - this, - currentCursor, + final BlockChangeArgs args = new BlockChangeArgs( currentCursor.state, (SpongeBlockChangeFlag) BlockChangeFlags.NONE, currentCursor.limit ); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( + this, + currentCursor, + args + ); if (result.resultingState != currentCursor.state) { currentCursor = new PipelineCursor( result.resultingState, @@ -130,13 +135,13 @@ public static final class Builder { @Nullable Supplier serverWorld; @Nullable Supplier chunkSupplier; @Nullable Supplier sectionSupplier; - List effects; + List> effects; - public Builder addEffect(final ProcessingSideEffect effect) { + public Builder addEffect(final ProcessingSideEffect effect) { if (this.effects == null) { this.effects = new LinkedList<>(); } - this.effects.add(new ResultingTransactionBySideEffect(Objects.requireNonNull(effect, "Effect is null"))); + this.effects.add(new ResultingTransactionBySideEffect<>(Objects.requireNonNull(effect, "Effect is null"))); return this; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java new file mode 100644 index 00000000000..4203d6474ad --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java @@ -0,0 +1,101 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; + +import java.util.List; +import java.util.Objects; + +public class UseBlockPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final BlockHitResult blockRaytraceResult; + private final BlockState blockstate; + private final ItemStack copiedStack; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseBlockPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + BlockHitResult blockRaytraceResultIn, + BlockState blockstate, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.blockRaytraceResult = blockRaytraceResultIn; + this.blockstate = blockstate; + this.copiedStack = copiedStack; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(InteractionItemEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java new file mode 100644 index 00000000000..82ba980892b --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionUseItemOnBlockEffect; + +import java.util.List; +import java.util.Objects; + +public final class UseItemOnBlockPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final BlockHitResult blockRaytraceResult; + private final BlockState blockstate; + private final ItemStack copiedStack; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemOnBlockPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + BlockHitResult blockRaytraceResultIn, + BlockState blockstate, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.blockRaytraceResult = blockRaytraceResultIn; + this.blockstate = blockstate; + this.copiedStack = copiedStack; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(InteractionUseItemOnBlockEffect.getInstance()) + ); + this.transactor = transactor; + } + + public ItemInteractionResult processInteraction(PhaseContext context) { + var interaction = ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable ItemInteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java new file mode 100644 index 00000000000..ce4fbd53238 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemEffect; + +import java.util.List; +import java.util.Objects; + +public class UseItemPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final ItemStack copiedStack; + private final BlockHitResult blockRaytraceResult; + private final boolean creative; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + BlockHitResult blockRaytraceResult, + boolean creative, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.copiedStack = copiedStack; + this.blockRaytraceResult = blockRaytraceResult; + this.creative = creative; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(UseItemEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final var args = new UseItemArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java index 81165311770..62ab2617393 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java @@ -36,6 +36,7 @@ import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -52,7 +53,7 @@ public final class WorldPipeline implements BlockPipeline { private final Supplier serverWorld; private final Supplier sectionSupplier; private final boolean wasEmpty; - private final List worldEffects; + private final List> worldEffects; private final ChunkPipeline chunkPipeline; WorldPipeline(final Builder builder) { @@ -101,14 +102,13 @@ public boolean processEffects(final PhaseContext context, final BlockState cu final int oldOpacity = oldState.getLightBlock(serverWorld, pos); PipelineCursor formerState = new PipelineCursor(oldState, oldOpacity, pos, existing, destroyer, limit); - for (final ResultingTransactionBySideEffect effect : this.worldEffects) { + for (final ResultingTransactionBySideEffect effect : this.worldEffects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( + final var args = new BlockChangeArgs(newProposedState, flag, limit); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( this, formerState, - newProposedState, - flag, - limit + args ); if (result.hasResult) { return result.resultingState != null; @@ -134,8 +134,8 @@ public static final class Builder { final Supplier serverWorld; final Supplier chunkSupplier; - final Supplier sectionSupplier; - @MonotonicNonNull List effects; + final Supplier<@Nullable LevelChunkSection> sectionSupplier; + @MonotonicNonNull List> effects; final ChunkPipeline chunkPipeline; Builder(final ChunkPipeline chunkPipeline) { @@ -145,11 +145,11 @@ public static final class Builder { this.chunkPipeline = chunkPipeline; } - public Builder addEffect(final ProcessingSideEffect effect) { + public Builder addEffect(final ProcessingSideEffect effect) { if (this.effects == null) { this.effects = new LinkedList<>(); } - this.effects.add(new ResultingTransactionBySideEffect(Objects.requireNonNull(effect, "Effect is null"))); + this.effects.add(new ResultingTransactionBySideEffect<>(Objects.requireNonNull(effect, "Effect is null"))); return this; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java index 7e628429740..83bb4d3ceb8 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java @@ -29,6 +29,7 @@ import org.spongepowered.api.event.Cancellable; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.block.ChangeBlockEvent; +import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.block.NotifyNeighborBlockEvent; import org.spongepowered.api.event.entity.HarvestEntityEvent; import org.spongepowered.api.event.entity.SpawnEntityEvent; @@ -65,6 +66,8 @@ public final class TransactionTypes { public static final DefaultedRegistryReference> CHANGE_INVENTORY_EVENT = TransactionTypes.key(ResourceKey.sponge("change_inventory")); public static final DefaultedRegistryReference> SLOT_CHANGE = TransactionTypes.key(ResourceKey.sponge("slot_change")); + public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + // SORTFIELDS:OFF // @formatter:on diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/RunAroundLikeCrazyGoalMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/RunAroundLikeCrazyGoalMixin.java index 82e86c1939a..4b8cf417095 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/RunAroundLikeCrazyGoalMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/RunAroundLikeCrazyGoalMixin.java @@ -56,14 +56,14 @@ public abstract class RunAroundLikeCrazyGoalMixin extends GoalMixin { */ @Overwrite public void tick() { - if (!this.horse.isTamed() && this.horse.getRandom().nextInt(50) == 0) { + if (!this.horse.isTamed() && this.horse.getRandom().nextInt(this.shadow$adjustedTickDelay(50)) == 0) { Entity entity = this.horse.getPassengers().get(0); if (entity == null) { return; } - if (entity instanceof Player) { + if (entity instanceof Player p) { int i = this.horse.getTemper(); int j = this.horse.getMaxTemper(); @@ -76,7 +76,7 @@ public void tick() { } } // Sponge end - this.horse.tameWithName((Player)entity); + this.horse.tameWithName(p); return; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java index 970ac0fd2b3..f37180e9335 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java @@ -31,7 +31,9 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockEventData; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.block.Block; @@ -41,6 +43,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.ticks.ScheduledTick; import net.minecraft.world.ticks.TickPriority; @@ -98,6 +101,9 @@ import org.spongepowered.common.event.tracking.context.transaction.pipeline.ChunkPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.TileEntityPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; import org.spongepowered.common.event.tracking.phase.tick.TickPhase; import org.spongepowered.common.mixin.tracker.world.level.LevelMixin_Tracker; @@ -446,11 +452,11 @@ public void scheduleTick(final BlockPos pos, final Fluid fluid, final int trigge // Then build and use the BlockPipeline final ChunkPipeline chunkPipeline = mixinChunk.bridge$createChunkPipeline(pos, newState, currentState, spongeFlag, limit); final WorldPipeline.Builder worldPipelineBuilder = WorldPipeline.builder(chunkPipeline); - worldPipelineBuilder.addEffect((pipeline, oldState, newState1, flag1, cursorLimit) -> { + worldPipelineBuilder.addEffect((pipeline, oldState, args) -> { if (oldState == null) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); }) .addEffect(UpdateLightSideEffect.getInstance()) .addEffect(CheckBlockPostPlacementIsSameEffect.getInstance()) @@ -576,6 +582,79 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable return builder.build(); } + @Override + public UseItemOnBlockPipeline bridge$startInteractionUseOnChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + final var pipeline = new UseItemOnBlockPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + blockRaytraceResultIn, + blockstate, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + return pipeline; + } + + @Override + public UseBlockPipeline bridge$startInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + final var pipeline = new UseBlockPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + blockRaytraceResultIn, + blockstate, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + return pipeline; + } + @Override + public UseItemPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + return new UseItemPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + copiedStack, + blockRaytraceResult, + creative, + instance.getPhaseContext().getTransactor() + ); + } + /** * Technically an overwrite, but because this is simply an override, we can * effectively do as we need to, which is determine if we are performing diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java index 91e3465fc9a..30036cf280f 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java @@ -34,12 +34,10 @@ import net.minecraft.world.MenuProvider; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; @@ -56,16 +54,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.server.level.ServerPlayerGameModeBridge; +import org.spongepowered.common.bridge.world.TrackedWorldBridge; import org.spongepowered.common.bridge.world.inventory.container.ContainerBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.inventory.InventoryEventFactory; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; -import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; -import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.registry.provider.DirectionFacingProvider; import org.spongepowered.common.util.VecHelper; import org.spongepowered.math.vector.Vector3d; @@ -78,7 +72,7 @@ public abstract class ServerPlayerGameModeMixin_Tracker { @Shadow protected net.minecraft.server.level.ServerLevel level; @Shadow private GameType gameModeForPlayer; - @Shadow public abstract boolean isCreative(); + @Shadow public abstract boolean shadow$isCreative(); @Inject(method = "useItem", cancellable = true, at = @At(value = "INVOKE", @@ -105,7 +99,9 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl final BlockSnapshot snapshot = ((ServerWorld) (worldIn)).createSnapshot(VecHelper.toVector3i(blockpos)); final Vector3d hitVec = Vector3d.from(blockRaytraceResultIn.getBlockPos().getX(), blockRaytraceResultIn.getBlockPos().getY(), blockRaytraceResultIn.getBlockPos().getZ()); final org.spongepowered.api.util.Direction direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); - final InteractBlockEvent.Secondary event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final PhaseContext phaseContext = PhaseTracker.getInstance().getPhaseContext(); + phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final InteractBlockEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); final Tristate useItem = event.useItemResult(); final Tristate useBlock = event.useBlockResult(); ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(event.isCancelled()); @@ -113,48 +109,53 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl player.inventoryMenu.sendAllDataToRemote(); return InteractionResult.FAIL; } - // Sponge end - if (this.gameModeForPlayer == GameType.SPECTATOR) { - final MenuProvider inamedcontainerprovider = blockstate.getMenuProvider(worldIn, blockpos); - if (inamedcontainerprovider != null) { - playerIn.openMenu(inamedcontainerprovider); - final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); - final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(playerIn); - frame.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld)(worldIn)).createSnapshot(pos)); - ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); - if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { - return InteractionResult.SUCCESS; + try (final var frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(event); + // Sponge end + if (this.gameModeForPlayer == GameType.SPECTATOR) { + final MenuProvider inamedcontainerprovider = blockstate.getMenuProvider(worldIn, blockpos); + if (inamedcontainerprovider != null) { + playerIn.openMenu(inamedcontainerprovider); + final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); + final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); + try (final CauseStackManager.StackFrame blockHit = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + blockHit.pushCause(playerIn); + blockHit.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); + ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); + if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { + return InteractionResult.SUCCESS; + } } + return InteractionResult.SUCCESS; + } else { + return InteractionResult.PASS; } - return InteractionResult.SUCCESS; - } else { - return InteractionResult.PASS; } - } else { final boolean flag = !playerIn.getMainHandItem().isEmpty() || !playerIn.getOffhandItem().isEmpty(); final boolean flag1 = playerIn.isSecondaryUseActive() && flag; final ItemStack copiedStack = stackIn.copy(); if (useBlock != Tristate.FALSE && !flag1) { // Sponge check useBlock - final ItemInteractionResult result = blockstate.useItemOn(playerIn.getItemInHand(handIn), worldIn, playerIn, handIn, blockRaytraceResultIn); - - if (result.consumesAction()) { + final var useInteraction = ((TrackedWorldBridge) level).bridge$startInteractionUseOnChange(worldIn, playerIn, handIn, blockRaytraceResultIn, blockstate, copiedStack); + if (useInteraction == null) { + return InteractionResult.FAIL; + } + final ItemInteractionResult itemInteract = useInteraction.processInteraction(phaseContext); + if (itemInteract.consumesAction()) { CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(playerIn, blockpos, copiedStack); - return result.result(); + return itemInteract.result(); } - - if (result == ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION && handIn == InteractionHand.MAIN_HAND) { + if (itemInteract == ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION && handIn == InteractionHand.MAIN_HAND) { final AbstractContainerMenu lastOpenContainer = playerIn.containerMenu; // Sponge - final InteractionResult result2 = blockstate.useWithoutItem(worldIn, playerIn, blockRaytraceResultIn); + final var interaction = ((TrackedWorldBridge) level).bridge$startInteractionChange(worldIn, playerIn, handIn, blockRaytraceResultIn, blockstate, copiedStack); + final InteractionResult result2 = interaction.processInteraction(phaseContext); if (result2.consumesAction()) { // Sponge Start if (lastOpenContainer != playerIn.containerMenu) { final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); - try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { - frame.pushCause(playerIn); - frame.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); + try (final CauseStackManager.StackFrame blockUse = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + blockUse.pushCause(playerIn); + blockUse.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { return InteractionResult.FAIL; @@ -166,6 +167,7 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl CriteriaTriggers.DEFAULT_BLOCK_USE.trigger(playerIn, blockpos); return result2; } + } } @@ -175,26 +177,9 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(true); return InteractionResult.PASS; } - // Sponge end - final UseOnContext itemusecontext = new UseOnContext(playerIn, handIn, blockRaytraceResultIn); - final InteractionResult result; - if (this.isCreative()) { - final int i = stackIn.getCount(); - result = stackIn.useOn(itemusecontext); - stackIn.setCount(i); - } else { - result = stackIn.useOn(itemusecontext); - // Sponge start - log change in hand - final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); - final TransactionalCaptureSupplier transactor = context.getTransactor(); - if (!transactor.isEmpty()) { //TODO: Add effect to attach the transaction to be the child of the parents - try (final EffectTransactor ignored = context.getTransactor().pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance()))) { - transactor.logPlayerInventoryChange(this.player, PlayerInventoryTransaction.EventCreator.STANDARD); - this.player.inventoryMenu.broadcastChanges(); - } - } - // Sponge end - } + final var interaction = ((TrackedWorldBridge) level).bridge$startItemInteractionChange(worldIn, playerIn, handIn, copiedStack, blockRaytraceResultIn, this.shadow$isCreative()); + final var result = interaction.processInteraction(phaseContext); + if (result.consumesAction()) { CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(playerIn, blockpos, copiedStack); @@ -203,7 +188,7 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl return result; } else { // Sponge start - if(useBlock == Tristate.FALSE && !flag1) { + if (useBlock == Tristate.FALSE && !flag1) { ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(true); } // Sponge end @@ -213,5 +198,4 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl } } - } diff --git a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java index d0fec3da68f..b78ad302ca2 100644 --- a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java +++ b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java @@ -331,8 +331,7 @@ void testTransformationsOfPositions( .sub(VolumePositionTranslators.BLOCK_OFFSET); final Vector3i invertedBlockPos = invertedTransformedPos.toInt(); final Vector3i expectedPos; - Assertions.assertTrue( - type instanceof StubState, + Assertions.assertInstanceOf(StubState.class, type, () -> String.format("expected state to be a stub state for pos: [%f, %f, %f] but got %s", x, y, z, type ) From 70e5d9a0339b6aee460f915b5a08113c1bcb84bf Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Mon, 6 May 2024 01:06:26 -0700 Subject: [PATCH 224/226] feat: Add other interactions as pipeline transactions --- .editorconfig | 7 +- .../bridge/world/TrackedWorldBridge.java | 5 +- .../event/SpongeCommonEventFactory.java | 4 +- .../transaction/EventByTransaction.java | 27 ++--- .../context/transaction/GameTransaction.java | 13 ++ .../context/transaction/TransactionSink.java | 26 +++- .../TransactionalCaptureSupplier.java | 23 ++-- ...actionArgs.java => InteractionAtArgs.java} | 2 +- .../effect/InteractionItemEffect.java | 4 +- .../InteractionUseItemOnBlockEffect.java | 4 +- .../effect/ProcessingSideEffect.java | 6 +- .../transaction/effect/UseItemArgs.java | 5 +- .../transaction/effect/UseItemAtArgs.java | 41 +++++++ ...efreshEffect.java => UseItemAtEffect.java} | 29 +++-- .../transaction/effect/UseItemEffect.java | 18 +-- .../transaction/effect/UseItemOnArgs.java | 39 ++++++ .../inventory/CompositeTransaction.java | 68 +++++++++++ .../inventory/InteractItemTransaction.java | 53 ++++----- .../InteractItemWithBlockTransaction.java | 112 ++++++++++++++++++ .../pipeline/UseBlockPipeline.java | 6 +- .../pipeline/UseItemAtPipeline.java | 100 ++++++++++++++++ .../pipeline/UseItemOnBlockPipeline.java | 6 +- .../transaction/pipeline/UseItemPipeline.java | 18 +-- .../transaction/type/TransactionTypes.java | 4 +- .../loader/SpongeCommonRegistryLoader.java | 1 + .../core/world/entity/ai/goal/GoalMixin.java | 3 + ...GamePacketListenerImplMixin_Inventory.java | 10 +- .../level/ServerLevelMixin_Tracker.java | 87 +++++++++----- .../ServerPlayerGameModeMixin_Tracker.java | 13 +- .../test/projectile/ProjectileTest.java | 2 +- .../test/volumestream/VolumeStreamTest.java | 2 +- 31 files changed, 577 insertions(+), 161 deletions(-) rename src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/{InteractionArgs.java => InteractionAtArgs.java} (98%) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java rename src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/{PlayerContainerRefreshEffect.java => UseItemAtEffect.java} (68%) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java diff --git a/.editorconfig b/.editorconfig index ac7a0202900..938ae881bc3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,8 @@ insert_final_newline = false max_line_length = 120 tab_width = 4 -[*mixins*.json] -indent_size = 4 \ No newline at end of file +[{*.json,*.jsonc,*.png.mcmeta,mcmod.info,pack.mcmeta}] +indent_size = 2 + +[*mixins.*.json] +indent_size = 4 diff --git a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java index 06670ba5551..99be360f82a 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java @@ -47,6 +47,7 @@ import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; @@ -123,5 +124,7 @@ public interface TrackedWorldBridge { UseBlockPipeline bridge$startInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); - UseItemPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); + UseItemAtPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); + + UseItemPipeline bridge$startItemInteractionUseChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack); } diff --git a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java index 8a7cafccb92..d361495e0cb 100644 --- a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java +++ b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java @@ -302,10 +302,10 @@ public static InteractItemEvent.Primary callInteractItemEventPrimary(final net.m } } - public static InteractItemEvent.Secondary callInteractItemEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack stack, final InteractionHand hand) { + public static InteractItemEvent.Secondary.Pre callInteractItemEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack stack, final InteractionHand hand) { try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { SpongeCommonEventFactory.applyCommonInteractContext(player, stack, hand, null, null, frame); - final InteractItemEvent.Secondary event = SpongeEventFactory.createInteractItemEventSecondary(frame.currentCause(), ItemStackUtil.snapshotOf(stack)); + final var event = SpongeEventFactory.createInteractItemEventSecondaryPre(frame.currentCause(), ItemStackUtil.snapshotOf(stack)); SpongeCommon.post(event); return event; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java index 3112366a713..220810b7e02 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java @@ -32,32 +32,19 @@ import org.spongepowered.api.event.Event; @DefaultQualifier(NonNull.class) -final class EventByTransaction { - - final T event; - final ImmutableList> transactions; - final GameTransaction decider; - final @Nullable GameTransaction<@NonNull ?> parent; - - EventByTransaction(final T event, - final ImmutableList> transactions, - final @Nullable GameTransaction<@NonNull ?> parent, - final GameTransaction decider - ) { - this.parent = parent; - this.event = event; - this.transactions = transactions; - this.decider = decider; - } +public record EventByTransaction( + T event, ImmutableList> transactions, + @Nullable GameTransaction<@NonNull ?> parent, + GameTransaction decider) { public void markCancelled() { - this.decider.markCancelled(); - for (GameTransaction transaction : this.transactions) { + this.decider().markCancelled(); + for (GameTransaction transaction : this.transactions()) { transaction.markCancelled(); } } public boolean isParentOrDeciderCancelled() { - return this.decider.cancelled || (this.parent != null && this.parent.cancelled); + return this.decider().cancelled || (this.parent() != null && this.parent().cancelled); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java index fd733d01d77..9f4eb4ddbfe 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java @@ -46,6 +46,7 @@ import java.util.Optional; import java.util.StringJoiner; import java.util.function.BiConsumer; +import java.util.stream.Stream; @DefaultQualifier(NonNull.class) public abstract class GameTransaction implements TransactionFlow, StatefulTransaction { @@ -189,6 +190,18 @@ protected void captureState() { } + public void associateSideEffectEvents(E e, Stream elements) { + + } + + public void pushCause(CauseStackManager.StackFrame frame, E e) { + frame.pushCause(e); + } + + public void finalizeSideEffects(E e) { + + } + private static class ChildIterator implements Iterator> { private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedNext; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java index 7da6b49814f..6018775a094 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java @@ -27,7 +27,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -47,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; @@ -74,6 +74,7 @@ import org.spongepowered.common.event.tracking.context.transaction.block.ScheduleUpdateTransaction; import org.spongepowered.common.event.tracking.context.transaction.effect.BlockAddedEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.EntityPerformingDropsEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; @@ -86,6 +87,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.DropFromPlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ExplicitInventoryOmittedTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemTransaction; +import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemWithBlockTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.OpenMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlaceRecipeTransaction; @@ -430,10 +432,26 @@ default EffectTransactor logInventoryTransaction(final AbstractContainerMenu con } default void logSecondaryInteractionTransaction( - final ServerPlayer playerIn, final ItemStack stackIn, final Vector3d hitVec, - final BlockSnapshot snapshot, final Direction direction, final InteractionHand handIn) { - final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final ServerPlayer playerIn, final Vector3d hitVec, + final BlockSnapshot snapshot, final Direction direction, InteractBlockEvent.Secondary.Pre event) { + final InteractItemWithBlockTransaction transaction = new InteractItemWithBlockTransaction(playerIn, + hitVec, + snapshot, + direction, + event.originalUseBlockResult(), + event.useBlockResult(), + event.originalUseItemResult(), + event.useItemResult() + ); this.logTransaction(transaction); } + default EffectTransactor logSecondaryInteractItemTransaction( + final ServerPlayer playerIn, final ItemStack stackIn + ) { + final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn); + this.logTransaction(transaction); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InteractionItemEffect.getInstance())); + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java index 9a32ad5960b..d5bb7c3cb0b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java @@ -175,7 +175,7 @@ public boolean processTransactions(final PhaseContext<@NonNull ?> context) { ); boolean cancelledAny = false; for (final EventByTransaction<@NonNull ?> eventWithTransactions : batched) { - final Event event = eventWithTransactions.event; + final Event event = eventWithTransactions.event(); if (eventWithTransactions.isParentOrDeciderCancelled()) { cancelledAny = true; eventWithTransactions.markCancelled(); @@ -186,12 +186,12 @@ public boolean processTransactions(final PhaseContext<@NonNull ?> context) { eventWithTransactions.markCancelled(); cancelledAny = true; } - if (((GameTransaction) eventWithTransactions.decider).markCancelledTransactions(event, eventWithTransactions.transactions)) { + if (((GameTransaction) eventWithTransactions.decider()).markCancelledTransactions(event, eventWithTransactions.transactions())) { cancelledAny = true; } - for (final GameTransaction<@NonNull ?> transaction : eventWithTransactions.transactions) { + for (final GameTransaction<@NonNull ?> transaction : eventWithTransactions.transactions()) { if (transaction.cancelled) { - ((GameTransaction) transaction).markEventAsCancelledIfNecessary(eventWithTransactions.event); + ((GameTransaction) transaction).markEventAsCancelledIfNecessary(eventWithTransactions.event()); } if (!transaction.cancelled) { ((GameTransaction) transaction).postProcessEvent(context, event); @@ -200,12 +200,12 @@ public boolean processTransactions(final PhaseContext<@NonNull ?> context) { } if (cancelledAny) { for (final EventByTransaction<@NonNull ?> eventByTransaction : batched.reverse()) { - if (eventByTransaction.decider.cancelled) { - ((GameTransaction) eventByTransaction.decider).markEventAsCancelledIfNecessary(eventByTransaction.event); + if (eventByTransaction.decider().cancelled) { + ((GameTransaction) eventByTransaction.decider()).markEventAsCancelledIfNecessary(eventByTransaction.event()); } - for (final GameTransaction<@NonNull ?> gameTransaction : eventByTransaction.transactions.reverse()) { + for (final GameTransaction<@NonNull ?> gameTransaction : eventByTransaction.transactions().reverse()) { if (gameTransaction.cancelled) { - ((GameTransaction) gameTransaction).restore(context, eventByTransaction.event); + ((GameTransaction) gameTransaction).restore(context, eventByTransaction.event()); } } } @@ -311,13 +311,16 @@ private static void generateEventForTransaction( if (transaction.sideEffects == null || transaction.sideEffects.isEmpty()) { continue; } - generatedEvent.ifPresent(frame::pushCause); + generatedEvent.ifPresent(e -> transaction.pushCause(frame, e)); for (final ResultingTransactionBySideEffect sideEffect : transaction.sideEffects) { if (sideEffect.head == null) { continue; } - builder.addAll(TransactionalCaptureSupplier.batchTransactions(sideEffect.head, pointer, context, transactionPostEventBuilder)); + final var elements = TransactionalCaptureSupplier.batchTransactions(sideEffect.head, pointer, context, transactionPostEventBuilder); + generatedEvent.ifPresent(e -> transaction.associateSideEffectEvents(e, elements.stream().map(EventByTransaction::event))); + builder.addAll(elements); } + generatedEvent.ifPresent(transaction::finalizeSideEffects); } } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java similarity index 98% rename from src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java rename to src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java index fac849e78d2..5cd9000fdc3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java @@ -31,7 +31,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -public record InteractionArgs( +public record InteractionAtArgs( Level world, ServerPlayer player, InteractionHand hand, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java index 8ccfc3a0b4e..57af8e795a9 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java @@ -29,7 +29,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; -public final class InteractionItemEffect implements ProcessingSideEffect { +public final class InteractionItemEffect implements ProcessingSideEffect.Simple { private static final class Holder { static final InteractionItemEffect INSTANCE = new InteractionItemEffect(); @@ -41,7 +41,7 @@ public static InteractionItemEffect getInstance() { @Override public EffectResult processSideEffect( - UseBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + UseBlockPipeline pipeline, InteractionResult oldState, InteractionAtArgs args ) { final var player = args.player(); final var world = args.world(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java index 71d393a62fe..e0bcef3e8e8 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java @@ -29,7 +29,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; -public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { +public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { private static final class Holder { static final InteractionUseItemOnBlockEffect INSTANCE = new InteractionUseItemOnBlockEffect(); @@ -41,7 +41,7 @@ public static InteractionUseItemOnBlockEffect getInstance() { @Override public EffectResult processSideEffect( - UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionArgs args + UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionAtArgs args ) { final var player = args.player(); final var hand = args.hand(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java index 6c4a7d1ff09..be0e3f21018 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java @@ -29,8 +29,12 @@ @FunctionalInterface public interface ProcessingSideEffect { + interface Simple extends ProcessingSideEffect { + + } + EffectResult processSideEffect(T pipeline, C oldState, A args); - sealed interface Args permits BlockChangeArgs, InteractionArgs, UseItemArgs {} + sealed interface Args permits BlockChangeArgs, InteractionAtArgs, UseItemOnArgs, UseItemAtArgs, UseItemArgs {} } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java index aebd7497bb2..eeb1c6c3f2f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java @@ -25,17 +25,16 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.BlockHitResult; public record UseItemArgs( Level world, ServerPlayer player, InteractionHand hand, - BlockHitResult result, ItemStack copiedStack, - boolean creative + ServerPlayerGameMode gameMode ) implements ProcessingSideEffect.Args { } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java new file mode 100644 index 00000000000..ab8616303c3 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; + +public record UseItemAtArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult result, + ItemStack copiedStack, + boolean creative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java similarity index 68% rename from src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java rename to src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java index a0f81ef9ad0..2f7dc7ea299 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java @@ -25,28 +25,43 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.UseOnContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; -public final class PlayerContainerRefreshEffect implements ProcessingSideEffect { +public class UseItemAtEffect implements ProcessingSideEffect.Simple { private static final class Holder { - static final PlayerContainerRefreshEffect INSTANCE = new PlayerContainerRefreshEffect(); + static final UseItemAtEffect INSTANCE = new UseItemAtEffect(); } - public static PlayerContainerRefreshEffect getInstance() { - return Holder.INSTANCE; + private UseItemAtEffect() { + } + + public static UseItemAtEffect getInstance() { + return UseItemAtEffect.Holder.INSTANCE; } @Override public EffectResult processSideEffect( - UseItemOnBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + UseItemAtPipeline pipeline, InteractionResult oldState, UseItemAtArgs args ) { + final var stack = args.copiedStack(); + final InteractionResult result; + final var context = new UseOnContext(args.player(), args.hand(), args.result()); + if (args.creative()) { + int count = stack.getCount(); + result = stack.useOn(context); + stack.setCount(count); + } else { + result = stack.useOn(context); + } pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { args.player().containerMenu.broadcastChanges(); } - return EffectResult.nullPass(); + return new EffectResult<>(result, true); } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java index 130e414c734..9a102746cc4 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java @@ -25,17 +25,19 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.context.UseOnContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; -public class UseItemEffect implements ProcessingSideEffect { +public class UseItemEffect implements ProcessingSideEffect.Simple { private static final class Holder { static final UseItemEffect INSTANCE = new UseItemEffect(); } + private UseItemEffect() { + } + public static UseItemEffect getInstance() { return UseItemEffect.Holder.INSTANCE; } @@ -44,16 +46,8 @@ public static UseItemEffect getInstance() { public EffectResult processSideEffect( UseItemPipeline pipeline, InteractionResult oldState, UseItemArgs args ) { - final var stack = args.copiedStack(); - final InteractionResult result; - final var context = new UseOnContext(args.player(), args.hand(), args.result()); - if (args.creative()) { - int $$14 = stack.getCount(); - result = stack.useOn(context); - stack.setCount($$14); - } else { - result = stack.useOn(context); - } + final var gameMode = args.gameMode(); + final InteractionResult result = gameMode.useItem(args.player(), args.world(), args.copiedStack(), args.hand()); pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { args.player().containerMenu.broadcastChanges(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java new file mode 100644 index 00000000000..72029fd5deb --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java @@ -0,0 +1,39 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; + +public record UseItemOnArgs( + UseOnContext context, + ItemStack itemStack, + ItemStackSnapshot itemStackSnapshot, + ServerPlayer player, + boolean isCreative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java new file mode 100644 index 00000000000..ab730bdad7c --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java @@ -0,0 +1,68 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import org.spongepowered.api.event.Cancellable; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.CompositeEvent; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.impl.AbstractCompositeEvent; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionType; + +import java.util.stream.Stream; + +public abstract class CompositeTransaction extends GameTransaction { + protected CompositeTransaction(TransactionType transactionType) { + super(transactionType); + } + + @Override + public void associateSideEffectEvents(E event, Stream elements) { + elements.forEach(event.children()::add); + } + + @Override + public void finalizeSideEffects(E post) { + // This finalizes the list to be immutable + ((AbstractCompositeEvent) post).postInit(); + } + + public void pushCause(CauseStackManager.StackFrame frame, E e) { + frame.pushCause(e.baseEvent()); + } + + @Override + public boolean markCancelledTransactions( + final E event, + final ImmutableList> gameTransactions) { + event.children().stream().filter(e -> e instanceof Cancellable) + .map(e -> (Cancellable) e) + .forEach(e -> e.setCancelled(event.isCancelled())); + return false; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java index 3302e01d076..c2a8fc0399c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java @@ -26,50 +26,46 @@ import com.google.common.collect.ImmutableList; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.util.Direction; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.common.util.PrettyPrinter; -import org.spongepowered.math.vector.Vector3d; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -public class InteractItemTransaction extends GameTransaction { +public class InteractItemTransaction extends CompositeTransaction { - - private final Vector3d hitVec; - private final BlockSnapshot snapshot; - private final Direction direction; - private final InteractionHand hand; + private final ServerPlayer player; private final ItemStackSnapshot stack; - public InteractItemTransaction(ServerPlayer playerIn, ItemStack stackIn, Vector3d hitVec, BlockSnapshot snapshot, Direction direction, InteractionHand handIn) { - super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + public InteractItemTransaction( + final ServerPlayer playerIn, final ItemStack stackIn) { + super(TransactionTypes.INTERACT_ITEM_SECONDARY.get()); + this.player = playerIn; this.stack = ItemStackUtil.snapshotOf(stackIn); - this.hitVec = hitVec; - this.snapshot = snapshot; - this.direction = direction; - this.hand = handIn; - } + } @Override public Optional, CauseStackManager.StackFrame>> getFrameMutator( @Nullable GameTransaction<@NonNull ?> parent ) { - return Optional.empty(); + return Optional.of((context, frame) -> { + frame.pushCause(this.player); + }); } @Override @@ -78,24 +74,23 @@ public void addToPrinter(PrettyPrinter printer) { } @Override - public Optional generateEvent( + public Optional generateEvent( final PhaseContext<@NonNull ?> context, final @Nullable GameTransaction<@NonNull ?> parent, - final ImmutableList> gameTransactions, + final ImmutableList> gameTransactions, final Cause currentCause ) { - return Optional.empty(); + final var root = SpongeEventFactory.createInteractItemEventSecondary(currentCause, this.stack); + final List list = new ArrayList<>(); + final var composite = SpongeEventFactory.createInteractItemEventSecondaryPost(currentCause, root, list); + return Optional.of(composite); } - @Override - public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Composite event) { - } @Override - public boolean markCancelledTransactions( - final InteractBlockEvent.Secondary.Composite event, - final ImmutableList> gameTransactions) { - return false; + public void restore(PhaseContext<@NonNull ?> context, InteractItemEvent.Secondary.Post event) { + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java new file mode 100644 index 00000000000..d49727d6adb --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java @@ -0,0 +1,112 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import net.minecraft.server.level.ServerPlayer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.Tristate; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; +import org.spongepowered.common.util.PrettyPrinter; +import org.spongepowered.math.vector.Vector3d; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; + +public class InteractItemWithBlockTransaction extends CompositeTransaction { + + private final Vector3d hitVec; + private final BlockSnapshot snapshot; + private final Direction direction; + private final ServerPlayer player; + private final Tristate originalBlockResult, blockResult, originalItemResult, itemResult; + + public InteractItemWithBlockTransaction( + final ServerPlayer playerIn, final Vector3d hitVec, final BlockSnapshot snapshot, + final Direction direction, + final Tristate originalBlockResult, final Tristate useBlockResult, + final Tristate originalUseItemResult, final Tristate useItemResult) { + super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + this.player = playerIn; + this.hitVec = hitVec; + this.snapshot = snapshot; + this.direction = direction; + this.originalBlockResult = originalBlockResult; + this.blockResult = useBlockResult; + this.originalItemResult = originalUseItemResult; + this.itemResult = useItemResult; + } + + + @Override + public Optional, CauseStackManager.StackFrame>> getFrameMutator( + @Nullable GameTransaction<@NonNull ?> parent + ) { + return Optional.of((context, frame) -> { + frame.pushCause(this.player); + }); + } + + @Override + public void addToPrinter(PrettyPrinter printer) { + + } + + @Override + public Optional generateEvent( + final PhaseContext<@NonNull ?> context, + final @Nullable GameTransaction<@NonNull ?> parent, + final ImmutableList> gameTransactions, + final Cause currentCause + ) { + final var root = SpongeEventFactory.createInteractBlockEventSecondary(currentCause, + this.originalBlockResult, this.blockResult, + this.originalItemResult, this.itemResult, + this.snapshot, this.hitVec, + this.direction + ); + final List list = new ArrayList<>(); + final InteractBlockEvent.Secondary.Post composite = SpongeEventFactory.createInteractBlockEventSecondaryPost(currentCause, root, list); + return Optional.of(composite); + } + + @Override + public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Post event) { + + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java index 4203d6474ad..f543af72bd6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java @@ -37,7 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; -import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionAtArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; import java.util.List; @@ -51,7 +51,7 @@ public class UseBlockPipeline { private final BlockHitResult blockRaytraceResult; private final BlockState blockstate; private final ItemStack copiedStack; - private final List> effects; + private final List> effects; private final TransactionalCaptureSupplier transactor; @@ -79,7 +79,7 @@ public InteractionResult processInteraction(PhaseContext context) { var interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java new file mode 100644 index 00000000000..2f2c5f16b17 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemAtArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemAtEffect; + +import java.util.List; +import java.util.Objects; + +public class UseItemAtPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final ItemStack copiedStack; + private final BlockHitResult blockRaytraceResult; + private final boolean creative; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemAtPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + BlockHitResult blockRaytraceResult, + boolean creative, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.copiedStack = copiedStack; + this.blockRaytraceResult = blockRaytraceResult; + this.creative = creative; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(UseItemAtEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final var args = new UseItemAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java index 82ba980892b..c24001d5719 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java @@ -37,7 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; -import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionAtArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionUseItemOnBlockEffect; import java.util.List; @@ -51,7 +51,7 @@ public final class UseItemOnBlockPipeline { private final BlockHitResult blockRaytraceResult; private final BlockState blockstate; private final ItemStack copiedStack; - private final List> effects; + private final List> effects; private final TransactionalCaptureSupplier transactor; @@ -79,7 +79,7 @@ public ItemInteractionResult processInteraction(PhaseContext context) { var interaction = ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java index ce4fbd53238..f2f315e91a7 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java @@ -29,7 +29,6 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.BlockHitResult; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; @@ -48,26 +47,19 @@ public class UseItemPipeline { private final ServerPlayer player; private final InteractionHand hand; private final ItemStack copiedStack; - private final BlockHitResult blockRaytraceResult; - private final boolean creative; private final List> effects; private final TransactionalCaptureSupplier transactor; - public UseItemPipeline(ServerLevel worldIn, - ServerPlayer playerIn, - InteractionHand handIn, - ItemStack copiedStack, - BlockHitResult blockRaytraceResult, - boolean creative, - final TransactionalCaptureSupplier transactor) { + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { this.worldIn = worldIn; this.player = playerIn; this.hand = handIn; this.copiedStack = copiedStack; - this.blockRaytraceResult = blockRaytraceResult; - this.creative = creative; this.effects = List.of( new ResultingTransactionBySideEffect<>(UseItemEffect.getInstance()) ); @@ -78,7 +70,7 @@ public InteractionResult processInteraction(PhaseContext context) { var interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final var args = new UseItemArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final var args = new UseItemArgs(this.worldIn, this.player, this.hand,this.copiedStack, this.player.gameMode); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java index 83bb4d3ceb8..a48a096715c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java @@ -35,6 +35,7 @@ import org.spongepowered.api.event.entity.SpawnEntityEvent; import org.spongepowered.api.event.item.inventory.AffectSlotEvent; import org.spongepowered.api.event.item.inventory.ChangeInventoryEvent; +import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.event.item.inventory.container.ClickContainerEvent; import org.spongepowered.api.event.item.inventory.container.InteractContainerEvent; import org.spongepowered.api.registry.DefaultedRegistryReference; @@ -66,7 +67,8 @@ public final class TransactionTypes { public static final DefaultedRegistryReference> CHANGE_INVENTORY_EVENT = TransactionTypes.key(ResourceKey.sponge("change_inventory")); public static final DefaultedRegistryReference> SLOT_CHANGE = TransactionTypes.key(ResourceKey.sponge("slot_change")); - public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + public static final DefaultedRegistryReference> INTERACT_ITEM_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); // SORTFIELDS:OFF diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java index 879cadfed56..807d9ae15e4 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java @@ -47,6 +47,7 @@ public class SpongeCommonRegistryLoader { l.add(TransactionTypes.SPAWN_ENTITY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.CHANGE_INVENTORY_EVENT, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.SLOT_CHANGE, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); + l.add(TransactionTypes.INTERACT_BLOCK_SECONDARY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.INTERACT_CONTAINER_EVENT, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); }); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java index ab09ccf8e03..48052fae4f1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java @@ -29,6 +29,7 @@ import org.spongepowered.api.entity.ai.goal.GoalExecutor; import org.spongepowered.api.entity.ai.goal.GoalType; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -42,6 +43,8 @@ @Mixin(Goal.class) public abstract class GoalMixin implements GoalBridge { + @Shadow protected abstract int shadow$adjustedTickDelay(int $$0); + private Supplier impl$type; private GoalExecutor impl$owner; diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java index c95c646d4f6..9819a24b355 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java @@ -49,12 +49,12 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.common.bridge.world.TrackedWorldBridge; import org.spongepowered.common.bridge.world.inventory.container.MenuBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.inventory.custom.SpongeInventoryMenu; import org.spongepowered.common.item.util.ItemStackUtil; @@ -122,12 +122,10 @@ public class ServerGamePacketListenerImplMixin_Inventory { final Level param1, final ItemStack param2, final InteractionHand param3) { final PhaseContext<@NonNull ?> context = PhaseTracker.SERVER.getPhaseContext(); final TransactionalCaptureSupplier transactor = context.getTransactor(); - try (final EffectTransactor ignored = transactor.logPlayerInventoryChangeWithEffect(this.player, PlayerInventoryTransaction.EventCreator.STANDARD)) { - final InteractionResult result = serverPlayerGameMode.useItem(param0, param1, param2, param3); - this.player.inventoryMenu.broadcastChanges(); // capture - return result; + try (final EffectTransactor ignored = transactor.logSecondaryInteractItemTransaction(param0, param2)) { + final var pipeline = ((TrackedWorldBridge) param1).bridge$startItemInteractionUseChange(param1, param0, param3, param2); + return pipeline.processInteraction(context); } - // TrackingUtil.processBlockCaptures called by UseItemPacketState } @Redirect(method = "handleContainerClose", diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java index f37180e9335..41aefc0a148 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java @@ -102,6 +102,7 @@ import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.TileEntityPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; @@ -123,19 +124,21 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implements TrackedWorldBridge { // @formatting:off - @Shadow @Final List players; + @Shadow + @Final + List players; // @formatting:on @Redirect( - // This normally would target this.entityTickList.forEach((var2x) -> - // but we don't have lambda syntax support yet. - method = "lambda$tick$2", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/server/level/ServerLevel;guardEntityTick(Ljava/util/function/Consumer;Lnet/minecraft/world/entity/Entity;)V") + // This normally would target this.entityTickList.forEach((var2x) -> + // but we don't have lambda syntax support yet. + method = "lambda$tick$2", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/level/ServerLevel;guardEntityTick(Ljava/util/function/Consumer;Lnet/minecraft/world/entity/Entity;)V") ) private void tracker$wrapNormalEntityTick(final ServerLevel level, final Consumer entityUpdateConsumer, - final Entity entity + final Entity entity ) { final PhaseContext<@NonNull ?> currentState = PhaseTracker.SERVER.getPhaseContext(); TrackingUtil.tickEntity(entityUpdateConsumer, entity); @@ -154,9 +157,9 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem * or we wrap in this method here. * * @param blockState The block state being ticked - * @param worldIn The world (this world) - * @param posIn The position of the block - * @param randomIn The world random + * @param worldIn The world (this world) + * @param posIn The position of the block + * @param randomIn The world random * @author gabizou - January 11th, 2020 - Minecraft 1.14.3 */ @Redirect(method = "tickBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/Block;)V", @@ -174,11 +177,11 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem } private ScheduledTick tracker$createTick(final BlockPos pos, final T type, final int triggerTick, final TickPriority priority) { - return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long)triggerTick, priority, this.nextSubTickCount()); + return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long) triggerTick, priority, this.nextSubTickCount()); } private ScheduledTick tracker$createTick(final BlockPos pos, final T type, final int triggerTick) { - return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long)triggerTick, this.nextSubTickCount()); + return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long) triggerTick, this.nextSubTickCount()); } @Override @@ -338,16 +341,16 @@ public void scheduleTick(final BlockPos pos, final Fluid fluid, final int trigge @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Explosion tracker$triggerInternalExplosion(org.spongepowered.api.world.explosion.Explosion explosion, - final Function> contextCreator) { + final Function> contextCreator) { // Sponge start final Explosion originalExplosion = (Explosion) explosion; if (ShouldFire.EXPLOSION_EVENT_PRE) { // Set up the pre event final ExplosionEvent.Pre - event = - SpongeEventFactory.createExplosionEventPre( - PhaseTracker.SERVER.currentCause(), - explosion, ((org.spongepowered.api.world.server.ServerWorld) this)); + event = + SpongeEventFactory.createExplosionEventPre( + PhaseTracker.SERVER.currentCause(), + explosion, ((org.spongepowered.api.world.server.ServerWorld) this)); if (SpongeCommon.post(event)) { return (Explosion) explosion; } @@ -453,11 +456,11 @@ public void scheduleTick(final BlockPos pos, final Fluid fluid, final int trigge final ChunkPipeline chunkPipeline = mixinChunk.bridge$createChunkPipeline(pos, newState, currentState, spongeFlag, limit); final WorldPipeline.Builder worldPipelineBuilder = WorldPipeline.builder(chunkPipeline); worldPipelineBuilder.addEffect((pipeline, oldState, args) -> { - if (oldState == null) { - return EffectResult.nullReturn(); - } - return EffectResult.nullPass(); - }) + if (oldState == null) { + return EffectResult.nullReturn(); + } + return EffectResult.nullPass(); + }) .addEffect(UpdateLightSideEffect.getInstance()) .addEffect(CheckBlockPostPlacementIsSameEffect.getInstance()) .addEffect(UpdateWorldRendererEffect.getInstance()) @@ -547,7 +550,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable @Override public SpongeBlockSnapshot bridge$createSnapshot(final net.minecraft.world.level.block.state.BlockState state, final BlockPos pos, - final BlockChangeFlag updateFlag + final BlockChangeFlag updateFlag ) { final SpongeBlockSnapshot.BuilderImpl builder = SpongeBlockSnapshot.BuilderImpl.pooled(); builder.reset(); @@ -595,7 +598,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - final var pipeline = new UseItemOnBlockPipeline( + return new UseItemOnBlockPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -604,9 +607,9 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable copiedStack, instance.getPhaseContext().getTransactor() ); - return pipeline; } + @Override public UseBlockPipeline bridge$startInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer @@ -620,7 +623,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - final var pipeline = new UseBlockPipeline( + return new UseBlockPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -629,10 +632,9 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable copiedStack, instance.getPhaseContext().getTransactor() ); - return pipeline; } @Override - public UseItemPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + public UseItemAtPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer return null; } @@ -644,7 +646,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - return new UseItemPipeline( + return new UseItemAtPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -655,6 +657,27 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable ); } + public UseItemPipeline bridge$startItemInteractionUseChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + return new UseItemPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + } + /** * Technically an overwrite, but because this is simply an override, we can * effectively do as we need to, which is determine if we are performing @@ -698,7 +721,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable final TileEntityPipeline pipeline = TileEntityPipeline.kickOff((ServerLevel) (Object) this, immutable) .addEffect(RemoveTileEntityFromChunkEffect.getInstance()) .build(); - pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), 0,immutable, tileentity, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); + pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), 0, immutable, tileentity, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); return; } super.shadow$removeBlockEntity(immutable); @@ -729,7 +752,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable final TileEntityPipeline pipeline = TileEntityPipeline.kickOff((ServerLevel) (Object) this, immutable) .addEffect(SetAndRegisterBlockEntityToLevelChunk.getInstance()) .build(); - pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), 0,immutable, proposed, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); + pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), 0, immutable, proposed, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); return; } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java index 30036cf280f..b966314fc93 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java @@ -41,7 +41,6 @@ import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.util.Tristate; import org.spongepowered.api.world.server.ServerLocation; @@ -80,7 +79,7 @@ public abstract class ServerPlayerGameModeMixin_Tracker { public void impl$callInteractItemSecondary(final ServerPlayer player, final Level level, final ItemStack stack, final InteractionHand hand, final CallbackInfoReturnable cir ) { - final InteractItemEvent.Secondary event = SpongeCommonEventFactory.callInteractItemEventSecondary(player, stack, hand); + final InteractItemEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractItemEventSecondary(player, stack, hand); if (event.isCancelled()) { player.inventoryMenu.sendAllDataToRemote(); cir.setReturnValue(InteractionResult.FAIL); @@ -98,12 +97,16 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl // Sponge start final BlockSnapshot snapshot = ((ServerWorld) (worldIn)).createSnapshot(VecHelper.toVector3i(blockpos)); final Vector3d hitVec = Vector3d.from(blockRaytraceResultIn.getBlockPos().getX(), blockRaytraceResultIn.getBlockPos().getY(), blockRaytraceResultIn.getBlockPos().getZ()); - final org.spongepowered.api.util.Direction direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); + final var direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); final PhaseContext phaseContext = PhaseTracker.getInstance().getPhaseContext(); - phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); - final InteractBlockEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final var event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); final Tristate useItem = event.useItemResult(); final Tristate useBlock = event.useBlockResult(); + phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, + hitVec, + snapshot, + direction, + event); ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(event.isCancelled()); if (event.isCancelled()) { player.inventoryMenu.sendAllDataToRemote(); diff --git a/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java b/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java index 9d9743c1ce3..1f70e0e6626 100644 --- a/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java @@ -208,7 +208,7 @@ public ProjectileTestListener() { } @Listener - private void onClickBlock(final InteractBlockEvent.Secondary event, @First final ServerPlayer player) { + private void onClickBlock(final InteractBlockEvent.Secondary.Pre event, @First final ServerPlayer player) { final Vector3d interactionPoint = event.interactionPoint(); final ServerWorld world = player.world(); final EntityType nextType = this.projectileTypes.poll(); diff --git a/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java b/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java index 1de067274ed..67e0a85ccb0 100644 --- a/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java @@ -407,7 +407,7 @@ private void onInteract(final InteractBlockEvent.Primary event, @Root final Play } @Listener - public void onInteract(final InteractBlockEvent.Secondary event, @Root final Player player) { + public void onInteract(final InteractBlockEvent.Secondary.Pre event, @Root final Player player) { event.context().get(EventContextKeys.USED_ITEM).ifPresent(snapshot -> { final BlockSnapshot block = event.block(); if (snapshot.type().equals(ItemTypes.WOODEN_AXE.get()) && block != BlockSnapshot.empty()) { From 49ac4184abd8b764b72d95c83e92decc5b3fe703 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 29 Sep 2024 20:46:39 -0700 Subject: [PATCH 225/226] wip: update to the new event generator --- gradle/verification-metadata.xml | 15 +++++++++++++++ .../inventory/CompositeTransaction.java | 5 ++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b1f70826dbb..1d2d7e4fb11 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -19,6 +19,8 @@ + + @@ -583,6 +585,11 @@ + + + + + @@ -603,6 +610,14 @@ + + + + + + + + diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java index ab730bdad7c..c72a64f677d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java @@ -59,9 +59,8 @@ public void pushCause(CauseStackManager.StackFrame frame, E e) { public boolean markCancelledTransactions( final E event, final ImmutableList> gameTransactions) { - event.children().stream().filter(e -> e instanceof Cancellable) - .map(e -> (Cancellable) e) - .forEach(e -> e.setCancelled(event.isCancelled())); + event.setCancelled(true); + gameTransactions.forEach(GameTransaction::markCancelled); return false; } From 2c2dcffeee94967a08161a80b301013077a576e4 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Wed, 9 Oct 2024 17:54:53 -0700 Subject: [PATCH 226/226] chore: update api dependency Signed-off-by: Gabriel Harris-Rouquette --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index 2680f76e5e1..714ccd7778a 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 2680f76e5e107c87f76362751a706a7987535c7c +Subproject commit 714ccd7778affaaf3b5c685c8fdd5c8319fbab6d