diff --git a/gradle.properties b/gradle.properties index 34eea5a..805dd7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ org.gradle.jvmargs=-Xmx1G # Mod Properties - mod_version = 0.21.0 + mod_version = 0.21.1 maven_group = com.github.zly2006 archives_base_name = carpet-sls-addition diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java index c8db903..16e4b1d 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java @@ -2,6 +2,7 @@ package com.github.zly2006.carpetslsaddition; import carpet.CarpetExtension; import carpet.CarpetServer; +import com.github.zly2006.carpetslsaddition.block.entity.SLSDeepSlateBlockEntity; import com.github.zly2006.carpetslsaddition.command.BotCommand; import com.github.zly2006.carpetslsaddition.command.HatCommand; import com.github.zly2006.carpetslsaddition.command.SitCommand; @@ -14,6 +15,8 @@ import com.mojang.brigadier.CommandDispatcher; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.Version; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntityType; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; @@ -42,6 +45,7 @@ public class ServerMain implements ModInitializer, CarpetExtension { public void onInitialize() { INSTANCE = this; CarpetServer.manageExtension(this); + registerBlockEntities(); } @Override @@ -86,4 +90,8 @@ public class ServerMain implements ModInitializer, CarpetExtension { SitCommand.register(dispatcher); BotCommand.register(dispatcher); } + + public void registerBlockEntities() { + SLSDeepSlateBlockEntity.BLOCK_ENTITY_TYPE = SLSDeepSlateBlockEntity.createType(BlockEntityType.Builder.create(SLSDeepSlateBlockEntity::new, Blocks.DEEPSLATE)); + } } diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/block/entity/SLSDeepSlateBlockEntity.java b/src/main/java/com/github/zly2006/carpetslsaddition/block/entity/SLSDeepSlateBlockEntity.java new file mode 100644 index 0000000..d7dff8d --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/block/entity/SLSDeepSlateBlockEntity.java @@ -0,0 +1,56 @@ +package com.github.zly2006.carpetslsaddition.block.entity; + +import com.mojang.datafixers.types.Type; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.datafixer.TypeReferences; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.util.Util; +import net.minecraft.util.math.BlockPos; + +import static net.minecraft.nbt.NbtElement.BYTE_TYPE; + +/** + * 没有很好的让深板岩保留BlockEntity的方案,暂时不使用 + */ +@Deprecated +public class SLSDeepSlateBlockEntity extends BlockEntity { + public static BlockEntityType BLOCK_ENTITY_TYPE; + + private boolean deepSlateCore = false; + + public SLSDeepSlateBlockEntity(BlockPos pos, BlockState state) { + super(SLSDeepSlateBlockEntity.BLOCK_ENTITY_TYPE, pos, state); + } + + @Override + protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.readNbt(nbt, registryLookup); + if (nbt.contains("deep_slate_core", BYTE_TYPE)) { + deepSlateCore = nbt.getBoolean("deep_slate_core"); + } + } + + @Override + protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(nbt, registryLookup); + nbt.putBoolean("deep_slate_core", deepSlateCore); + } + + public boolean isDeepSlateCore() { + return deepSlateCore; + } + + public void setDeepSlateCore(boolean deepSlateCore) { + this.deepSlateCore = deepSlateCore; + } + + public static BlockEntityType createType(BlockEntityType.Builder builder) { + Type type = Util.getChoiceType(TypeReferences.BLOCK_ENTITY, "sls_deepslate"); + return Registry.register(Registries.BLOCK_ENTITY_TYPE, "sls_deepslate", builder.build(type)); + } +} diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/carpet/MixinEntityPlayerMPFake.java b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/carpet/MixinEntityPlayerMPFake.java index 854de44..7b62a1a 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/carpet/MixinEntityPlayerMPFake.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/carpet/MixinEntityPlayerMPFake.java @@ -1,6 +1,7 @@ package com.github.zly2006.carpetslsaddition.mixin.carpet; import carpet.patches.EntityPlayerMPFake; +import carpet.utils.Translations; import com.github.zly2006.carpetslsaddition.SLSCarpetSettings; import com.github.zly2006.carpetslsaddition.ServerMain; import com.github.zly2006.carpetslsaddition.util.access.SLSBotAccessor; @@ -64,7 +65,7 @@ public abstract class MixinEntityPlayerMPFake extends ServerPlayerEntity impleme if (liveTime > SLSCarpetSettings.botMaxOnlineTime * 1000) { ServerMain.server.getPlayerManager().broadcast( - Text.translatable("carpet.slsa.bot.bot_timeout", this.getNameForScoreboard(), getFormattedTime(SLSCarpetSettings.botMaxOnlineTime)) + Text.literal(Translations.tr("carpet.slsa.bot.bot_timeout").formatted(this.getNameForScoreboard(), getFormattedTime(SLSCarpetSettings.botMaxOnlineTime))) .setStyle( Style.EMPTY.withColor(Formatting.RED) ), diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinFallingBlockEntity.java b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinFallingBlockEntity.java index db7bfe4..ff47eeb 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinFallingBlockEntity.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinFallingBlockEntity.java @@ -1,32 +1,125 @@ package com.github.zly2006.carpetslsaddition.mixin.entity; +import carpet.utils.Translations; import com.github.zly2006.carpetslsaddition.SLSCarpetSettings; +import com.github.zly2006.carpetslsaddition.block.entity.SLSDeepSlateBlockEntity; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ItemEnchantmentsComponent; +import net.minecraft.component.type.NbtComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; +import static net.minecraft.nbt.NbtElement.COMPOUND_TYPE; + @Mixin(FallingBlockEntity.class) public abstract class MixinFallingBlockEntity extends Entity { + @Shadow private BlockState block; + @Shadow private boolean destroyedOnLanding; + public MixinFallingBlockEntity(EntityType type, World world) { super(type, world); } - @Inject(method = "handleFallDamage", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getOtherEntities(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;Ljava/util/function/Predicate;)Ljava/util/List;", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILSOFT) - private void handleFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource, CallbackInfoReturnable cir, int i, Predicate predicate, DamageSource damageSource2, float f) { - if (SLSCarpetSettings.obtainableReinforcedDeepSlate) { - predicate = entity -> entity instanceof ItemEntity; - this.getWorld().getOtherEntities(this, this.getBoundingBox(), predicate).forEach((entity) -> entity.damage(damageSource2, f)); + @Inject(method = "handleFallDamage", at = @At(value = "TAIL")) + private void handleFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource, CallbackInfoReturnable cir) { + if (!SLSCarpetSettings.obtainableReinforcedDeepSlate || !this.block.isIn(BlockTags.ANVIL)) { + return; } + + Predicate deepSlatePredicated = (entity) -> { + if (entity instanceof ItemEntity itemEntity) { + var itemStack = itemEntity.getStack(); + return itemStack.isOf(Items.DEEPSLATE) && itemStack.getCount() >= 64; + } + + return false; + }; + + this.getWorld().getOtherEntities(this, this.getBoundingBox(), deepSlatePredicated).forEach((entity) -> { + var deepSlateEntity = (ItemEntity) entity; // deepSlatePredicated保证转换的安性 + var stackNbtComponent = deepSlateEntity.getStack().getOrDefault(DataComponentTypes.BLOCK_ENTITY_DATA, NbtComponent.DEFAULT); + if (!tryCreateDeepSlateCore(deepSlateEntity, stackNbtComponent)) { + ((ItemEntity) entity).setStack(new ItemStack(Items.REINFORCED_DEEPSLATE, 1)); + } + + markSuccessfulForged(); + }); + } + + /** + * 尝试创造一个深板岩核心 + * @param itemEntity 深板岩物品实体,不应传入非深板岩的物品 + * @param itemComponent 深板岩物品的Block Entity数据 + * @return 是否创建成功 + */ + @Unique + private boolean tryCreateDeepSlateCore(ItemEntity itemEntity, NbtComponent itemComponent) { + AtomicBoolean success = new AtomicBoolean(true); + var itemStack = itemEntity.getStack().copy(); + + itemComponent.apply( blockEntityData -> { + if (blockEntityData.getBoolean("deep_slate_core")) { + success.set(false); + return; + } + + blockEntityData.putBoolean("deep_slate_core", true); + BlockItem.setBlockEntityData(itemStack, SLSDeepSlateBlockEntity.BLOCK_ENTITY_TYPE, blockEntityData); + + itemStack.set( + DataComponentTypes.CUSTOM_NAME, + Text.literal(Translations.tr("carpet.slsa.block.deep_slate_core")) + .setStyle(Style.EMPTY.withColor(Formatting.LIGHT_PURPLE)) + ); + + itemStack.setCount(1); + + var pos = itemEntity.getPos(); + itemEntity.discard(); + + var coreEntity = new ItemEntity(this.getWorld(), pos.getX(), pos.getY(), pos.getZ(), itemStack); + coreEntity.setPickupDelay(40); + float f = this.random.nextFloat() * 0.5F; + float g = this.random.nextFloat() * (float) (Math.PI * 2); + coreEntity.setVelocity(-MathHelper.sin(g) * f, 0.2F, MathHelper.cos(g) * f); + this.getWorld().spawnEntity(coreEntity); + }); + + return success.get(); + } + + @Unique + private void markSuccessfulForged() { + this.getWorld().playSoundAtBlockCenter(this.getBlockPos(), SoundEvents.BLOCK_ANVIL_USE, SoundCategory.BLOCKS, 1.0F, 1.0F, false); + this.destroyedOnLanding = true; } } diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinItemEntity.java b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinItemEntity.java deleted file mode 100644 index 417f080..0000000 --- a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/entity/MixinItemEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.github.zly2006.carpetslsaddition.mixin.entity; - -import com.github.zly2006.carpetslsaddition.SLSCarpetSettings; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.ItemEntity; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.damage.DamageTypes; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(ItemEntity.class) -public abstract class MixinItemEntity extends Entity { - public MixinItemEntity(EntityType type, World world) { - super(type, world); - } - - @Shadow - public abstract ItemStack getStack(); - - @Shadow - public abstract void setStack(ItemStack stack); - - @Inject(method = "damage", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ItemEntity;discard()V"), cancellable = true) - private void damage(DamageSource source, float amount, CallbackInfoReturnable cir) { - if (source.getTypeRegistryEntry().matchesKey(DamageTypes.FALLING_ANVIL) && SLSCarpetSettings.obtainableReinforcedDeepSlate) { - if ((getStack().isOf(Items.DEEPSLATE) || getStack().isOf(Items.COBBLED_DEEPSLATE)) - && getStack().getCount() == 64) { - setStack(new ItemStack(Items.REINFORCED_DEEPSLATE)); - cir.setReturnValue(true); - } - } - } -} diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/mixin/item/MixinItem.java b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/item/MixinItem.java new file mode 100644 index 0000000..9b88dab --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/mixin/item/MixinItem.java @@ -0,0 +1,31 @@ +package com.github.zly2006.carpetslsaddition.mixin.item; + +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Item.class) +public class MixinItem { + @Redirect( + method = "hasGlint", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;hasEnchantments()Z" + ) + ) + public boolean hasGlint(ItemStack itemStack) { + if (!itemStack.isOf(Items.DEEPSLATE)) { + return itemStack.hasEnchantments(); + } + + return itemStack.getOrDefault( + DataComponentTypes.BLOCK_ENTITY_DATA, + NbtComponent.DEFAULT + ).copyNbt().getBoolean("deep_slate_core") || itemStack.hasEnchantments(); + } +} diff --git a/src/main/resources/assets/slsaddition/lang/en_us.json b/src/main/resources/assets/slsaddition/lang/en_us.json index 5bbf512..f6c7633 100644 --- a/src/main/resources/assets/slsaddition/lang/en_us.json +++ b/src/main/resources/assets/slsaddition/lang/en_us.json @@ -60,5 +60,7 @@ "carpet.slsa.bot.bot_timeout": "The bot %s has exceeded the maximum online time of %s, and has been disconnected now.", "carpet.slsa.bot.respawned": "The bot %s's online time has been reset.", - "carpet.slsa.bot.not_a_bot": "The player %s is not created by carpet sls addition, so you can't reset the online time." + "carpet.slsa.bot.not_a_bot": "The player %s is not created by carpet sls addition, so you can't reset the online time.", + + "carpet.slsa.block.deep_slate_core": "Deepslate Core" } diff --git a/src/main/resources/assets/slsaddition/lang/zh_cn.json b/src/main/resources/assets/slsaddition/lang/zh_cn.json index abc0956..31dbedd 100644 --- a/src/main/resources/assets/slsaddition/lang/zh_cn.json +++ b/src/main/resources/assets/slsaddition/lang/zh_cn.json @@ -60,5 +60,7 @@ "carpet.slsa.bot.bot_timeout": "假人%s在线时间已超出服务器设定的最大在线时长%s,已被自动踢出", "carpet.slsa.bot.respawned": "假人%s的在线时长已重置!", - "carpet.slsa.bot.not_a_bot": "假人%s不是由Carpet SLS Addition生成的,所以你不能重置它的在线时间!" + "carpet.slsa.bot.not_a_bot": "假人%s不是由Carpet SLS Addition生成的,所以你不能重置它的在线时间!", + + "carpet.slsa.block.deep_slate_core": "深板岩核心" } diff --git a/src/main/resources/slsaddition.mixins.json b/src/main/resources/slsaddition.mixins.json index 90a7d01..35a20e4 100644 --- a/src/main/resources/slsaddition.mixins.json +++ b/src/main/resources/slsaddition.mixins.json @@ -22,11 +22,11 @@ "entity.MixinEnderDragonFight", "entity.MixinEndermanGoal", "entity.MixinFallingBlockEntity", - "entity.MixinItemEntity", "entity.MixinMobEntity", "entity.MixinPlayerEntity", "entity.MixinServerPlayerEntity", "entity.MixinVillagerEntity", + "item.MixinItem", "player.MixinPlayerInventory", "screen.MixinAnvilScreenHandler", "server.MixinMinecraftServer",