当前位置:网站首页>Minecraft 1.18.1, 1.18.2 module development 22 Sniper rifle
Minecraft 1.18.1, 1.18.2 module development 22 Sniper rifle
2022-07-06 02:13:00 【Jay_ fearless】
Minecraft 1.18.1、1.18.2 Module development 05. The emitter + Missiles
Today we implement a sniper gun in the module .
1. With the first 5 This tutorial is similar , We need to make models of guns and bullets first :
However, this time we hope that the sniper gun will enter the opening state when the Deputy , So we need to set up a first person field of view of the sniper gun in the form of an assistant .
Then export as .json file , Will export .json File put in resources\assets\ Your module name \models\item
in :
2. stay Items Create a new item class of our bullets in the bag ItemSniperAmmo
:
ItemSniperAmmo
package com.joy187.re8joymod.items;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySniperAmmo;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item.Properties;
import net.minecraft.world.level.Level;
public class ItemSniperAmmo extends Item {
public ItemSniperAmmo() {
super(new Properties().tab(Main.TUTORIAL_TAB).stacksTo(16));
}
public EntitySniperAmmo createArrow(Level p_200887_1_, ItemStack p_200887_2_, LivingEntity p_200887_3_) {
EntitySniperAmmo arrowentity = new EntitySniperAmmo(p_200887_1_, p_200887_3_);
return arrowentity;
}
public boolean isInfinite(ItemStack stack, ItemStack bow, net.minecraft.world.entity.player.Player player) {
int enchant = net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY_ARROWS, bow);
return enchant <= 0 ? false : this.getClass() == ItemSniperAmmo.class;
}
}
stay Init Bag ItemInit Class to add our throwing object declaration :
ItemInit.java
public class ItemInit {
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS,
Main.MOD_ID);
// Our throw item statement
public static RegistryObject<Item> SNIPERAMMO = ITEMS.register("sniperammo",()->
{
return new ItemSniperAmmo();
});
private static <T extends Item> RegistryObject<T> register(final String name, final Supplier<T> item) {
return ITEMS.register(name, item);
}
}
3. stay entity Create our bullet entity class in the package EntitySniperAmmo
EntitySniperAmmo.java
package com.joy187.re8joymod.entity;
import com.joy187.re8joymod.init.EntityInit;
import com.joy187.re8joymod.init.ItemInit;
import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.monster.AbstractSkeleton;
import net.minecraft.world.entity.monster.Blaze;
import net.minecraft.world.entity.monster.Ravager;
import net.minecraft.world.entity.projectile.ThrowableItemProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraftforge.network.NetworkHooks;
public class EntitySniperAmmo extends ThrowableItemProjectile{
public int explosionPower = 1,id=91082;
public double damage;
private int ticksInGround;
private static final EntityDataAccessor<Integer> ID_EFFECT_COLOR = SynchedEntityData.defineId(EntitySniperAmmo.class, EntityDataSerializers.INT);
public EntitySniperAmmo(EntityType<?> entityIn, Level level) {
super((EntityType<? extends EntitySniperAmmo>) entityIn, level);
//this.size(1.0F, 1.0F);
this.damage = 24D;
// TODO Auto-generated constructor stub
}
public EntitySniperAmmo(Level world, LivingEntity entity) {
super(EntityInit.SNIPERAMMO.get(), entity, world);
this.damage= 24D;
}
// Our bullets are bound to previous items
@Override
protected Item getDefaultItem() {
return ItemInit.SNIPERAMMO.get();
}
// Damage caused when an object strikes an entity
protected void onHitEntity(EntityHitResult result) {
super.onHitEntity(result);
Entity entity = result.getEntity();
int i = 24;
if(entity instanceof Blaze || entity instanceof Ravager){
i = 28;
}
if(entity instanceof EntityBei || entity instanceof EntityHeisen){
i= 35;
}
if(entity instanceof EntityUrias || entity instanceof EntityUriass){
i= 25;
}
if(entity instanceof EntityLycana || entity instanceof AbstractSkeleton){
i= 45;
}
entity.hurt(DamageSource.thrown(this, this.getOwner()), (float)(i+random.nextFloat()*0.5*this.damage));
}
protected void onHit(EntityHitResult p_70227_1_) {
super.onHit(p_70227_1_);
if (!this.level.isClientSide) {
this.level.broadcastEntityEvent(this, (byte)3);
this.remove(Entity.RemovalReason.KILLED);
}
}
@Override
public Packet<?> getAddEntityPacket() {
FriendlyByteBuf pack = new FriendlyByteBuf(Unpooled.buffer());
pack.writeDouble(getX());
pack.writeDouble(getY());
pack.writeDouble(getZ());
pack.writeInt(getId());
pack.writeUUID(getUUID());
return NetworkHooks.getEntitySpawningPacket(this);
}
}
4. Render our missiles ,render Create a new rendering class in the package RenderSniperAmmo
RenderSniperAmmo.java
package com.joy187.re8joymod.entity.render;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySniperAmmo;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
public class RenderSniperAmmo extends EntityRenderer<EntitySniperAmmo> {
// The mapping position of your bullet
public static final ResourceLocation TEXTURE = new ResourceLocation(Main.MOD_ID ,"textures/item/zhihu.png");
private static final float MIN_CAMERA_DISTANCE_SQUARED = 12.25F;
private final ItemRenderer itemRenderer;
private final float scale;
private final boolean fullBright;
public RenderSniperAmmo(EntityRendererProvider.Context manager) {
//this.itemRenderer = manager.getItemRenderer();
super(manager);
this.itemRenderer=manager.getItemRenderer();
this.scale=0.25F;
this.fullBright=false;
}
private static final RenderType field_229044_e_ = RenderType.entityCutoutNoCull(TEXTURE);
protected int getSkyLightLevel(EntitySniperAmmo p_239381_1_, BlockPos p_239381_2_) {
return 1;
}
@Override
public ResourceLocation getTextureLocation(EntitySniperAmmo p_110775_1_) {
return TEXTURE;
}
public void render(EntitySniperAmmo entityIn, float entityYaw, float partialTicks, PoseStack poseStackIn, MultiBufferSource bufferIn, int packedLightIn) {
if (entityIn.tickCount >= 2 || !(this.entityRenderDispatcher.camera.getEntity().distanceToSqr(entityIn) < 12.25D)) {
poseStackIn.pushPose();
poseStackIn.scale(this.scale, this.scale, this.scale);
poseStackIn.mulPose(this.entityRenderDispatcher.cameraOrientation());
poseStackIn.mulPose(Vector3f.YP.rotationDegrees(180.0F));
this.itemRenderer.renderStatic(entityIn.getItem(), ItemTransforms.TransformType.GROUND, packedLightIn, OverlayTexture.NO_OVERLAY, poseStackIn, bufferIn, entityIn.getId());
poseStackIn.popPose();
super.render(entityIn, entityYaw, partialTicks, poseStackIn, bufferIn, packedLightIn);
}
}
private static void vertexRender(VertexConsumer p_229045_0_, Matrix4f p_229045_1_, Matrix3f p_229045_2_, int p_229045_3_, float p_229045_4_, int p_229045_5_, int p_229045_6_, int p_229045_7_) {
p_229045_0_.vertex(p_229045_1_, p_229045_4_ - 0.5F, (float)p_229045_5_ - 0.25F, 0.0F).color(255, 255, 255, 255).overlayCoords(OverlayTexture.NO_OVERLAY).normal(p_229045_2_, 0.0F, 1.0F, 0.0F).endVertex();
}
}
stay ClientModEventSubscriber.java
Add the rendering event registration of our throwing object :
ClientModEventSubscriber.java
package com.joy187.re8joymod;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import com.joy187.re8joymod.entity.EntityRe8Dimi;
import com.joy187.re8joymod.entity.model.ModelRe8Dimi;
import com.joy187.re8joymod.entity.render.RenderMoSpitter;
import com.joy187.re8joymod.entity.render.RenderRe8Dimi;
import com.joy187.re8joymod.init.EntityInit;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.ThrownItemRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.event.entity.EntityAttributeCreationEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@Mod.EventBusSubscriber(modid = Main.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ClientModEventSubscriber
{
@SubscribeEvent
public static void onRegisterLayers(EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(ModelRe8Dimi.LAYER_LOCATION, ModelRe8Dimi::createBodyLayer);
}
@SubscribeEvent
public static void onRegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(EntityInit.RE8DIMI.get(), RenderRe8Dimi::new);
// Add rendering events for our missiles
event.registerEntityRenderer(EntityInit.SNIPERAMMO.get(), RenderSniperAmmo::new);
}
@SubscribeEvent
public static void onAttributeCreate(EntityAttributeCreationEvent event) {
event.put(EntityInit.RE8DIMI.get(), EntityRe8Dimi.prepareAttributes().build());
}
}
5. The bullet is finished , Come to the firearms section . stay Item Our new sniper guns ItemF2
ItemF2.java
package com.joy187.re8joymod.items;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import com.joy187.re8joymod.ClientModEventSubscriber;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySniperAmmo;
import com.joy187.re8joymod.init.ItemInit;
import com.joy187.re8joymod.init.SoundInit;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ProjectileWeaponItem;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.Vanishable;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.Level;
public class ItemF2 extends ProjectileWeaponItem implements Vanishable {
public ItemF2() {
super(new ItemF2.Properties().tab(Main.TUTORIAL_TAB).stacksTo(1));
}
public ItemF2(Item.Properties name) {
super(name);
}
public void releaseUsing(ItemStack p_77615_1_, Level level, LivingEntity p_77615_3_, int p_77615_4_) {
if (p_77615_3_ instanceof Player) {
Player Player = (Player)p_77615_3_;
//OneHandedPose.renderFirstPersonArms(Player, Player.HAND_SLOTS, p_77615_1_, Player.getPose(), Player.buffer, p_77615_4_, p_77615_4_);
boolean flag = Player.getAbilities().instabuild || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, p_77615_1_) > 0;
// ItemStack itemstack = Player.getProjectile(p_77615_1_);
ItemStack itemstack = this.findAmmo(Player);
int i = this.getUseDuration(p_77615_1_) - p_77615_4_;
i = net.minecraftforge.event.ForgeEventFactory.onArrowLoose(p_77615_1_, level, Player, i, !itemstack.isEmpty() || flag);
if (i < 0) return;
if (!itemstack.isEmpty() || flag) {
if (itemstack.isEmpty()) {
itemstack = new ItemStack(ItemInit.SNIPERAMMO.get().asItem());
}
float f = getPowerForTime(i);
if (!((double)f < 0.1D)) {
boolean flag1 = Player.getAbilities().instabuild || (itemstack.getItem() instanceof ItemSniperAmmo && ((ItemSniperAmmo)itemstack.getItem()).isInfinite(itemstack, p_77615_1_, Player));
if (!level.isClientSide) {
ItemSniperAmmo arrowitem = (ItemSniperAmmo)(itemstack.getItem() instanceof ItemSniperAmmo ? itemstack.getItem() : ItemInit.SNIPERAMMO.get().asItem());
EntitySniperAmmo abstractarrowentity = arrowitem.createArrow(level, itemstack, Player);
abstractarrowentity = customArrow(abstractarrowentity);
//abstractarrowentity.setItem(itemstack);
abstractarrowentity.shootFromRotation(Player, Player.getXRot(), Player.getYRot(), 0.2F, f * 30.0F, 0.75F);
abstractarrowentity.level.addParticle(ParticleTypes.FLAME, abstractarrowentity.getX(), abstractarrowentity.getY(), abstractarrowentity.getZ(), abstractarrowentity.position().x , abstractarrowentity.position().y, abstractarrowentity.position().z);
abstractarrowentity.playSound(SoundInit.R2FIRE.get(), 4.5F,4.5F);
if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.FLAMING_ARROWS, p_77615_1_) > 0) {
abstractarrowentity.setSecondsOnFire(100);
}
p_77615_1_.hurtAndBreak(1, Player, (p_220009_1_) -> {
p_220009_1_.broadcastBreakEvent(Player.getUsedItemHand());
});
abstractarrowentity.level.addParticle(ParticleTypes.FLAME, abstractarrowentity.getX(), abstractarrowentity.getY(), abstractarrowentity.getZ(), abstractarrowentity.position().x * -0.2D, 0.08D, abstractarrowentity.position().z * -0.2D);
level.addFreshEntity(abstractarrowentity);
}
// The sound emitted
level.playSound((Player)null, Player.getX(), Player.getY(), Player.getZ(), SoundInit.R2FIRE.get(), SoundSource.PLAYERS, 4.5F, 4.5F / (Player.getRandom().nextFloat() * 0.2F + 1.2F) + f * 0.5F);
if (!flag1 && !Player.getAbilities().instabuild) {
itemstack.shrink(1);
if (itemstack.isEmpty()) {
Player.getInventory().removeItem(itemstack);
}
}
// After each successful launch, the interval 1.5s Launch again (30=20*1.5)
Player.getCooldowns().addCooldown(this, 30);
Player.awardStat(Stats.ITEM_USED.get(this));
}
}
}
}
public InteractionResultHolder<ItemStack> use(Level level, Player palyerIn, InteractionHand handIn) {
ItemStack itemstack = palyerIn.getItemInHand(handIn);
boolean flag = !this.findAmmo(palyerIn).isEmpty();
InteractionResultHolder<ItemStack> ret = net.minecraftforge.event.ForgeEventFactory.onArrowNock(itemstack, level, palyerIn, handIn, flag);
if (ret != null) return ret;
if (!palyerIn.getAbilities().instabuild && !flag) {
return InteractionResultHolder.fail(itemstack);
} else {
palyerIn.startUsingItem(handIn);
return InteractionResultHolder.consume(itemstack);
}
}
public static float getPowerForTime(int p_185059_0_) {
float f = (float)p_185059_0_ / 20.0F;
f = (f * f + f * 2.0F) / 3.0F;
if (f > 1.0F) {
f = 1.0F;
}
return f;
}
public int getUseDuration(ItemStack p_77626_1_) {
return 500;
}
public Predicate<ItemStack> getAllSupportedProjectiles() {
return ARROW_OR_FIREWORK;
}
public EntitySniperAmmo customArrow(EntitySniperAmmo arrow) {
return arrow;
}
public int getDefaultProjectileRange() {
return 15;
}
// Determine whether we can find our exclusive bullets
protected ItemStack findAmmo(Player player)
{
if (this.isSniperAmmo(player.getItemInHand(InteractionHand.OFF_HAND)))
{
return player.getItemInHand(InteractionHand.OFF_HAND);
}
else if (this.isSniperAmmo(player.getItemInHand(InteractionHand.MAIN_HAND)))
{
return player.getItemInHand(InteractionHand.MAIN_HAND);
}
else
{
for (int i = 0; i < player.getInventory().getContainerSize(); ++i)
{
ItemStack itemstack = player.getInventory().getItem(i);
if (this.isSniperAmmo(itemstack))
{
return itemstack;
}
}
return ItemStack.EMPTY;
}
}
protected boolean isSniperAmmo(ItemStack stack)
{
return stack.getItem() instanceof ItemSniperAmmo;
}
@Override
public boolean onEntitySwing(ItemStack stack, LivingEntity entity)
{
return true;
}
public void initializeClient(java.util.function.Consumer<net.minecraftforge.client.IItemRenderProperties> consumer) {
}
// Monitor the state of firearms
public void inventoryTick(ItemStack p_77663_1_, Level p_77663_2_, Entity p_77663_3_, int p_77663_4_, boolean p_77663_5_) {
if(p_77663_3_ instanceof Player)
{
ItemStack item = ((Player)p_77663_3_).getItemInHand(InteractionHand.OFF_HAND);
// If the player's deputy is equipped with this gun
if(item.getItem() == ItemInit.F2RIFLE.get())
{
// Let the field of vision become open ( The smaller the value, the larger the magnification )
Minecraft.getInstance().options.fov=12;
}
else {
// Return to the field of vision when you are not in the Deputy
Minecraft.getInstance().options.fov=70;
}
}
}
@Override
public void appendHoverText(ItemStack stack, @Nullable Level worldIn, List<Component> tooltip, TooltipFlag flagIn) {
tooltip.add(Component.nullToEmpty(ChatFormatting.GOLD+"Press 'F' to offhand for scoping."));
tooltip.add(Component.nullToEmpty(ChatFormatting.GOLD+"Ammo Type:Sniper Rifle Ammo"));
}
}
stay ItemInit
Class to add our gun declaration :
ItemInit.java
public static RegistryObject<Item> SA110 = ITEMS.register("sa110",()->
{
return new ItemF2();
});
6. We designed a special sound for our guns , stay SoundInit Register in :
SoundInit.java
package com.joy187.re8joymod.init;
import net.minecraftforge.registries.RegistryObject;
import com.joy187.re8joymod.Main;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
public class SoundInit {
public static final DeferredRegister<SoundEvent> SOUNDS = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, Main.MOD_ID);
// The sound of our guns
public static final RegistryObject<SoundEvent> R2FIRE = build("entity.m1851.f2rifle");
private static RegistryObject<SoundEvent> build(String id)
{
return SOUNDS.register(id, () -> new SoundEvent(new ResourceLocation(Main.MOD_ID, id)));
}
}
In the main class of the project Main Function will be SoundInit
Class to register :
public Main() {
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
ItemInit.ITEMS.register(bus);
BlockInit.BLOCKS.register(bus);
EntityInit.ENTITY_TYPES.register(bus);
EffectInit.EFFECTS.register(bus);
PotionInit.POTIONS.register(bus);
// Add this
SoundInit.SOUNDS.register(bus);
}
Convert sound files to .ogg
Format , Put in src\main\resources\assets\ Yours modid\sounds\entity\m1851
Under the path .
7. The code section ends , Enter the resource pack production process . stay resources In bag sounds.json
Add our gun sound to the file :
sounds.json
"entity.m1851.f2rifle":{
"category":"entity",
"subtitle" :"entity.m1851.f2rifle.sub",
"sounds":[{ "name": "re8joymod:entity/m1851/f2rifle", "stream":true }]
},
stay lang In bag en_us.json
Add guns 、 Bullet items 、 English name of bullet entity :
en_us.json
"entity.re8joymod.sniperammo": "Sniper Rifle Ammo",
"item.re8joymod.f2rifle": "F2 Rifle",
"item.re8joymod.sniperammo": "Sniper Rifle Ammo",
stay lang In bag zh_cn.json
Add guns 、 Bullet items 、 Chinese name of bullet entity :
zh_cn.json
"item.re8joymod.sniperammo": " Sniper gun bullets ",
"item.re8joymod.f2rifle": "F2 sniper rifle ",
"entity.re8joymod.sniperammo": " Sniper gun bullets ",
8. Save the project , Run game tests :
The main hand is in the form of sniper gun :
Press ’F’ Key to switch to the sniper gun form when the second hand
Pong! Pong!
边栏推荐
- Online reservation system of sports venues based on PHP
- 729. 我的日程安排表 I / 剑指 Offer II 106. 二分图
- SPI communication protocol
- Overview of spark RDD
- Folio. Ink is a free, fast and easy-to-use image sharing tool
- 阿里测开面试题
- Thinking about the best practice of dynamics 365 development collaboration
- Use the list component to realize the drop-down list and address list
- Global and Chinese market of wheelchair climbing machines 2022-2028: Research Report on technology, participants, trends, market size and share
- Redis key operation
猜你喜欢
0211 embedded C language learning
Selenium waiting mode
02. Go language development environment configuration
PHP campus movie website system for computer graduation design
Leetcode sum of two numbers
在线怎么生成富文本
Use the list component to realize the drop-down list and address list
[depth first search notes] Abstract DFS
SPI communication protocol
Executing two identical SQL statements in the same sqlsession will result in different total numbers
随机推荐
Redis-列表
A basic lintcode MySQL database problem
National intangible cultural heritage inheritor HD Wang's shadow digital collection of "Four Beauties" made an amazing debut!
D22:indeterminate equation (indefinite equation, translation + problem solution)
Ali test Open face test
[eight part essay] what is the difference between unrepeatable reading and unreal reading?
Xshell 7 Student Edition
Using SA token to solve websocket handshake authentication
MySQL learning notes - subquery exercise
Initialize MySQL database when docker container starts
Adapter-a technology of adaptive pre training continuous learning
2022年版图解网络PDF
更改对象属性的方法
Compact lidar global and Chinese markets 2022-2028: technology, participants, trends, market size and share Research Report
Unity learning notes -- 2D one-way platform production method
[flask] official tutorial -part2: Blueprint - view, template, static file
leetcode-2. Palindrome judgment
使用npm发布自己开发的工具包笔记
01. Go language introduction
selenium 等待方式