Add Tooltips and Creative URL Opener
Twine/pipeline/head This commit looks good Details

This commit is contained in:
TheBrokenRail 2020-06-17 17:57:52 -04:00
parent a7a1794ba0
commit bea02add8c
19 changed files with 323 additions and 23 deletions

View File

@ -2,6 +2,7 @@ package com.thebrokenrail.twine;
import com.thebrokenrail.twine.advancement.BoatCriterion;
import com.thebrokenrail.twine.block.CreativeItemSpawnerBlock;
import com.thebrokenrail.twine.block.CreativeURLOpenerBlock;
import com.thebrokenrail.twine.block.GlowingObsidianBlock;
import com.thebrokenrail.twine.item.BackpackItem;
import com.thebrokenrail.twine.item.DivinerItem;
@ -31,6 +32,8 @@ public class Twine implements ModInitializer {
public static final CreativeItemSpawnerBlock CREATIVE_ITEM_SPAWNER_BLOCK = new CreativeItemSpawnerBlock();
public static final CreativeURLOpenerBlock CREATIVE_URL_OPENER_BLOCK = new CreativeURLOpenerBlock();
public static final ItemGroup ITEM_GROUP = FabricItemGroupBuilder.build(new Identifier(NAMESPACE, "item_group"), () -> new ItemStack(GLOWING_OBSIDIAN));
public static final Item SMALL_BACKPACK = new BackpackItem(false);
@ -63,5 +66,8 @@ public class Twine implements ModInitializer {
Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "creative_item_spawner"), CREATIVE_ITEM_SPAWNER_BLOCK);
Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "creative_item_spawner"), new BlockItem(CREATIVE_ITEM_SPAWNER_BLOCK, new Item.Settings().group(ITEM_GROUP)));
Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "creative_url_opener"), CREATIVE_URL_OPENER_BLOCK);
Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "creative_url_opener"), new BlockItem(CREATIVE_URL_OPENER_BLOCK, new Item.Settings().group(ITEM_GROUP)));
}
}

View File

@ -1,55 +1,47 @@
package com.thebrokenrail.twine.block;
import com.thebrokenrail.twine.util.ItemUtil;
import com.thebrokenrail.twine.util.block.DirectionalBlock;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.DispenserBlock;
import net.minecraft.block.Material;
import net.minecraft.block.dispenser.DispenserBehavior;
import net.minecraft.block.dispenser.ItemDispenserBehavior;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPointer;
import net.minecraft.util.math.BlockPointerImpl;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import java.util.List;
import java.util.Random;
@SuppressWarnings("deprecation")
public class CreativeItemSpawnerBlock extends Block {
public static final DirectionProperty FACING = DispenserBlock.FACING;
public class CreativeItemSpawnerBlock extends DirectionalBlock {
public static final BooleanProperty TRIGGERED = Properties.TRIGGERED;
public CreativeItemSpawnerBlock() {
super(Settings.of(Material.STONE).strength(-1.0F, 3600000.0F).dropsNothing());
setDefaultState(stateManager.getDefaultState().with(FACING, Direction.SOUTH).with(TRIGGERED, false));
setDefaultState(stateManager.getDefaultState().with(TRIGGERED, false));
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(FACING, TRIGGERED);
}
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {
return state.with(FACING, rotation.rotate(state.get(FACING)));
}
@Override
public BlockState mirror(BlockState state, BlockMirror mirror) {
return state.rotate(mirror.getRotation(state.get(FACING)));
super.appendProperties(builder);
builder.add(TRIGGERED);
}
@Override
@ -91,7 +83,9 @@ public class CreativeItemSpawnerBlock extends Block {
}
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
return getDefaultState().with(FACING, ctx.getSide());
@Environment(EnvType.CLIENT)
public void buildTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext options) {
super.buildTooltip(stack, world, tooltip, options);
ItemUtil.addTooltip("block", "creative_item_spawner", 3, tooltip);
}
}

View File

@ -0,0 +1,73 @@
package com.thebrokenrail.twine.block;
import com.thebrokenrail.twine.packet.OpenURLS2CPacket;
import com.thebrokenrail.twine.util.ItemUtil;
import com.thebrokenrail.twine.util.block.DirectionalBlock;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState;
import net.minecraft.block.Material;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.LecternBlockEntity;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import java.util.List;
@SuppressWarnings("deprecation")
public class CreativeURLOpenerBlock extends DirectionalBlock {
public CreativeURLOpenerBlock() {
super(Settings.of(Material.STONE).strength(-1.0F, 3600000.0F).dropsNothing());
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient()) {
BlockPos targetPos = pos.offset(state.get(FACING).getOpposite());
BlockEntity entity = world.getBlockEntity(targetPos);
if (entity instanceof LecternBlockEntity) {
ItemStack stack = ((LecternBlockEntity) entity).getBook();
Tag pages = stack.getOrCreateTag().get("pages");
ListTag pagesList;
if (pages instanceof ListTag) {
pagesList = (ListTag) pages;
} else {
pagesList = new ListTag();
}
String url = pagesList.getString(0);
if (stack.getItem() == Items.WRITTEN_BOOK) {
Text urlText = Text.Serializer.fromJson(url);
if (urlText != null) {
url = urlText.asString();
}
}
if (url.length() > 0) {
OpenURLS2CPacket.send((ServerPlayerEntity) player, url);
}
}
}
return ActionResult.SUCCESS;
}
@Override
@Environment(EnvType.CLIENT)
public void buildTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext options) {
super.buildTooltip(stack, world, tooltip, options);
ItemUtil.addTooltip("block", "creative_url_opener", 4, tooltip);
}
}

View File

@ -1,15 +1,24 @@
package com.thebrokenrail.twine.block;
import com.thebrokenrail.twine.util.ItemUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.Material;
import net.minecraft.block.MaterialColor;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.Monster;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import java.util.List;
public class GlowingObsidianBlock extends Block {
public GlowingObsidianBlock() {
super(Settings.of(Material.STONE, MaterialColor.BLACK).requiresTool().strength(50.0F, 1200.0F).lightLevel(state -> 4));
@ -27,4 +36,11 @@ public class GlowingObsidianBlock extends Block {
}
}
}
@Override
@Environment(EnvType.CLIENT)
public void buildTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext options) {
super.buildTooltip(stack, world, tooltip, options);
ItemUtil.addTooltip("block", "glowing_obsidian", 2, tooltip);
}
}

View File

@ -1,14 +1,17 @@
package com.thebrokenrail.twine.client;
import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.packet.OpenURLS2CPacket;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.gui.screen.ingame.CraftingScreen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.item.DyeableItem;
import net.minecraft.util.Identifier;
@Environment(EnvType.CLIENT)
public class TwineClient implements ClientModInitializer {
@ -17,5 +20,6 @@ public class TwineClient implements ClientModInitializer {
ScreenRegistry.register(Twine.BACKPACK_SCREEN_TYPE, GenericContainerScreen::new);
ScreenRegistry.register(Twine.BOAT_CRAFTING_SCREEN_TYPE, CraftingScreen::new);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> tintIndex > 0 ? -1 : ((DyeableItem) stack.getItem()).getColor(stack), Twine.SMALL_BACKPACK, Twine.LARGE_BACKPACK);
ClientSidePacketRegistry.INSTANCE.register(new Identifier(Twine.NAMESPACE, "open_url"), OpenURLS2CPacket::handle);
}
}

View File

@ -1,8 +1,12 @@
package com.thebrokenrail.twine.item;
import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.util.ItemUtil;
import com.thebrokenrail.twine.util.backpack.gui.BackpackScreenHandler;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.DyeableItem;
@ -17,6 +21,8 @@ import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World;
import java.util.List;
public class BackpackItem extends Item implements DyeableItem {
private final boolean large;
@ -49,4 +55,11 @@ public class BackpackItem extends Item implements DyeableItem {
}
return new TypedActionResult<>(ActionResult.CONSUME, stack);
}
@Override
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, World world, List<Text> tooltip, TooltipContext context) {
super.appendTooltip(stack, world, tooltip, context);
ItemUtil.addTooltip("item", "backpack", 3, tooltip);
}
}

View File

@ -2,11 +2,16 @@ package com.thebrokenrail.twine.item;
import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.component.StageDataComponent;
import com.thebrokenrail.twine.util.ItemUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Formatting;
@ -15,6 +20,8 @@ import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.List;
public class DivinerItem extends Item {
public DivinerItem() {
super(new Settings().group(Twine.ITEM_GROUP).maxDamage(6));
@ -42,4 +49,11 @@ public class DivinerItem extends Item {
}
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
}
@Override
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, World world, List<Text> tooltip, TooltipContext context) {
super.appendTooltip(stack, world, tooltip, context);
ItemUtil.addTooltip("item", "diviner", 2, tooltip);
}
}

View File

@ -0,0 +1,28 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.component.StageDataComponent;
import com.thebrokenrail.twine.util.StageUtil;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.Monster;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
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(LivingEntity.class)
public class MixinLivingEntity {
@Inject(at = @At("HEAD"), method = "takeKnockback", cancellable = true)
public void takeKnockback(float f, double d, double e, CallbackInfo info) {
if (this instanceof Monster) {
StageDataComponent component = StageDataComponent.getFromWorld((ServerWorld) ((LivingEntity) (Object) this).getEntityWorld());
BlockPos blockPos = ((LivingEntity) (Object) this).getBlockPos();
int stage = component.findEffectiveStageOfChunk((ServerWorld) (((LivingEntity) (Object) this).getEntityWorld()), blockPos);
if (stage >= StageUtil.MOBS_TAKE_NO_KNOCKBACK) {
info.cancel();
}
}
}
}

View File

@ -0,0 +1,33 @@
package com.thebrokenrail.twine.packet;
import com.thebrokenrail.twine.Twine;
import io.netty.buffer.Unpooled;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ConfirmChatLinkScreen;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
public class OpenURLS2CPacket {
@Environment(EnvType.CLIENT)
public static void handle(PacketContext context, PacketByteBuf buf) {
String url = buf.readString();
MinecraftClient.getInstance().openScreen(new ConfirmChatLinkScreen(open -> {
if (open) {
Util.getOperatingSystem().open(url);
}
MinecraftClient.getInstance().openScreen(null);
}, url, false));
}
public static void send(ServerPlayerEntity player, String url) {
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
buf.writeString(url);
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(new Identifier(Twine.NAMESPACE, "open_url"), buf));
}
}

View File

@ -0,0 +1,16 @@
package com.thebrokenrail.twine.util;
import com.thebrokenrail.twine.Twine;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import java.util.List;
public class ItemUtil {
public static void addTooltip(String type, String name, int lines, List<Text> tooltip) {
for (int i = 0; i < lines; i++) {
tooltip.add(new TranslatableText(type + '.' + Twine.NAMESPACE + '.' + name + ".tooltip_" + (i + 1)).formatted(Formatting.GRAY));
}
}
}

View File

@ -7,4 +7,5 @@ public class StageUtil {
public static final int HOSTILE_MOBS_TARGET_PASSIVE_MOBS = 1;
public static final int IRON_GOLEMS_TARGET_PLAYERS = 3;
public static final int MOBS_NO_LONGER_BURN_IN_SUNLIGHT = 5;
public static final int MOBS_TAKE_NO_KNOCKBACK = 5;
}

View File

@ -0,0 +1,41 @@
package com.thebrokenrail.twine.util.block;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.DispenserBlock;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.math.Direction;
@SuppressWarnings("deprecation")
public class DirectionalBlock extends Block {
protected static final DirectionProperty FACING = DispenserBlock.FACING;
public DirectionalBlock(Settings settings) {
super(settings);
setDefaultState(stateManager.getDefaultState().with(FACING, Direction.SOUTH));
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {
return state.with(FACING, rotation.rotate(state.get(FACING)));
}
@Override
public BlockState mirror(BlockState state, BlockMirror mirror) {
return state.rotate(mirror.getRotation(state.get(FACING)));
}
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
return getDefaultState().with(FACING, ctx.getSide());
}
}

View File

@ -0,0 +1,27 @@
{
"variants": {
"facing=down": {
"model": "twine:block/creative_url_opener",
"x": 90
},
"facing=east": {
"model": "twine:block/creative_url_opener",
"y": 90
},
"facing=north": {
"model": "twine:block/creative_url_opener"
},
"facing=south": {
"model": "twine:block/creative_url_opener",
"y": 180
},
"facing=up": {
"model": "twine:block/creative_url_opener",
"x": 270
},
"facing=west": {
"model": "twine:block/creative_url_opener",
"y": 270
}
}
}

View File

@ -4,9 +4,18 @@
"item.twine.large_backpack": "Large Backpack",
"item.twine.small_backpack": "Small Backpack",
"item.twine.backpack.tooltip_1": "This item can carry extra items inside",
"item.twine.backpack.tooltip_2": "of it, but only items of the same type",
"item.twine.backpack.tooltip_3": "or unstackable items",
"block.twine.glowing_obsidian": "Glowing Obsidian",
"block.twine.glowing_obsidian.tooltip_1": "This block heals monsters",
"block.twine.glowing_obsidian.tooltip_2": "and hurts everything else",
"block.twine.creative_item_spawner": "Creative Item Spawner",
"block.twine.creative_item_spawner.tooltip_1": "This block copies the items in",
"block.twine.creative_item_spawner.tooltip_2": "a block on the §cred§r side and",
"block.twine.creative_item_spawner.tooltip_3": "them on the §dpurple§r side",
"advancements.twine.root.title": "Twine",
"advancements.twine.root.description": "A simple survival mod for Minecraft encouraging a nomadic lifestyle",
@ -27,10 +36,19 @@
"advancements.twine.diviner.description": "Construct a Diviner with a Crafting Table",
"item.twine.diviner": "Diviner",
"item.twine.diviner.tooltip_1": "This item shows you the bigger",
"item.twine.diviner.tooltip_2": "picture of your area in the world",
"chat.twine.diviner_info_1": "Effective Stage Of Area: %s",
"chat.twine.diviner_info_2": "Effective Stage Of Area Increases In: %s Ticks",
"chat.twine.diviner_info_3": "Personal Stage Of Area: %s",
"chat.twine.diviner_info_4": "Personal Center Of Area: X: %s Z: %s",
"chat.twine.diviner_info_5": "Personal Stage Of Area Increases In: %s Ticks",
"chat.twine.diviner_info_never": "Never"
"chat.twine.diviner_info_never": "Never",
"block.twine.creative_url_opener": "Creative URL Opener",
"block.twine.creative_url_opener.tooltip_1": "If this block is facing a lectern when",
"block.twine.creative_url_opener.tooltip_2": "used, it will prompt the user to open",
"block.twine.creative_url_opener.tooltip_3": "the first page of the lectern's book",
"block.twine.creative_url_opener.tooltip_4": "as a URL in a web browser"
}

View File

@ -0,0 +1,12 @@
{
"parent": "minecraft:block/cube",
"textures": {
"particle": "twine:block/creative_url_opener_side",
"down": "twine:block/creative_url_opener_side",
"up": "twine:block/creative_url_opener_side",
"north": "twine:block/creative_url_opener_side",
"east": "twine:block/creative_url_opener_side",
"south": "twine:block/creative_url_opener_back",
"west": "twine:block/creative_url_opener_side"
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "twine:block/creative_url_opener"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

View File

@ -7,6 +7,7 @@
"CriteriaHook",
"MixinBoatEntity",
"MixinDefaultBiomeFeatures",
"MixinLivingEntity",
"MixinMobEntity",
"MixinServerPlayerEntity",
"MixinServerPlayNetworkHandler",