It is basicly a copy from MinecartFurnace.class:
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.entity.vehicle.MinecartFurnace;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FurnaceBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class PowercartEntity extends AbstractMinecart {
private static final EntityDataAccessor<Boolean> DATA_ID_FUEL = SynchedEntityData.defineId(MinecartFurnace.class, EntityDataSerializers.BOOLEAN);
private int fuel;
public double xPush;
public double zPush;
private static final Ingredient INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);
public PowercartEntity(EntityType<?> p_38552_, Level p_38553_) {
super((EntityType<MinecartFurnace>)p_38552_, p_38553_);
}
public PowercartEntity(Level p_38555_, double p_38556_, double p_38557_, double p_38558_) {
super(EntityType.FURNACE_MINECART, p_38555_, p_38556_, p_38557_, p_38558_);
}
public AbstractMinecart.Type getMinecartType() {
return AbstractMinecart.Type.FURNACE;
}
protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.define(DATA_ID_FUEL, false);
}
public void tick() {
super.tick();
if (!this.level.isClientSide()) {
if (this.fuel > 0) {
--this.fuel;
}
if (this.fuel <= 0) {
this.xPush = 0.0D;
this.zPush = 0.0D;
}
this.setHasFuel(this.fuel > 0);
}
if (this.hasFuel() && this.random.nextInt(4) == 0) {
this.level.addParticle(ParticleTypes.LARGE_SMOKE, this.getX(), this.getY() + 0.8D, this.getZ(), 0.0D, 0.0D, 0.0D);
}
}
protected double getMaxSpeed() {
return (this.isInWater() ? 3.0D : 4.0D) / 20.0D;
}
@Override
public float getMaxCartSpeedOnRail() {
return 0.2f;
}
public void destroy(DamageSource p_38560_) {
super.destroy(p_38560_);
if (!p_38560_.isExplosion() && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
this.spawnAtLocation(Blocks.FURNACE);
}
}
protected void moveAlongTrack(BlockPos p_38569_, BlockState p_38570_) {
double d0 = 1.0E-4D;
double d1 = 0.001D;
super.moveAlongTrack(p_38569_, p_38570_);
Vec3 vec3 = this.getDeltaMovement();
double d2 = vec3.horizontalDistanceSqr();
double d3 = this.xPush * this.xPush + this.zPush * this.zPush;
if (d3 > 1.0E-4D && d2 > 0.001D) {
double d4 = Math.sqrt(d2);
double d5 = Math.sqrt(d3);
this.xPush = vec3.x / d4 * d5;
this.zPush = vec3.z / d4 * d5;
/*if (this.xPush > 0) this.xPush=5;
if (this.zPush > 0) this.zPush=5;
if (this.xPush < 0) this.xPush=-5;
if (this.zPush < 0) this.zPush=-5;*/
}
}
protected void applyNaturalSlowdown() {
double d0 = this.xPush * this.xPush + this.zPush * this.zPush;
if (d0 > 1.0E-7D) {
d0 = Math.sqrt(d0);
this.xPush /= d0;
this.zPush /= d0;
Vec3 vec3 = this.getDeltaMovement().multiply(0.8D, 0.0D, 0.8D).add(this.xPush, 0.0D, this.zPush);
if (this.isInWater()) {
vec3 = vec3.scale(0.1D);
}
this.setDeltaMovement(vec3);
} else {
this.setDeltaMovement(this.getDeltaMovement().multiply(0.98D, 0.0D, 0.98D));
}
super.applyNaturalSlowdown();
}
public InteractionResult interact(Player p_38562_, InteractionHand p_38563_) {
InteractionResult ret = super.interact(p_38562_, p_38563_);
if (ret.consumesAction()) return ret;
ItemStack itemstack = p_38562_.getItemInHand(p_38563_);
if (INGREDIENT.test(itemstack) && this.fuel + 3600 <= 32000) {
if (!p_38562_.getAbilities().instabuild) {
itemstack.shrink(1);
}
this.fuel += 3600;
}
if (this.fuel > 0) {
this.xPush = this.getX() - p_38562_.getX();
this.zPush = this.getZ() - p_38562_.getZ();
LOGGER.info(this.xPush+" "+this.zPush);
}
return InteractionResult.sidedSuccess(this.level.isClientSide);
}
protected void addAdditionalSaveData(CompoundTag p_38567_) {
super.addAdditionalSaveData(p_38567_);
p_38567_.putDouble("PushX", this.xPush);
p_38567_.putDouble("PushZ", this.zPush);
p_38567_.putShort("Fuel", (short)this.fuel);
}
protected void readAdditionalSaveData(CompoundTag p_38565_) {
super.readAdditionalSaveData(p_38565_);
this.xPush = p_38565_.getDouble("PushX");
this.zPush = p_38565_.getDouble("PushZ");
this.fuel = p_38565_.getShort("Fuel");
}
protected boolean hasFuel() {
return this.entityData.get(DATA_ID_FUEL);
}
protected void setHasFuel(boolean p_38577_) {
this.entityData.set(DATA_ID_FUEL, p_38577_);
}
public BlockState getDefaultDisplayBlockState() {
return Blocks.FURNACE.defaultBlockState().setValue(FurnaceBlock.FACING, Direction.NORTH).setValue(FurnaceBlock.LIT, Boolean.valueOf(this.hasFuel()));
}
}
And i created an item. When i use the item, my wannabe Powercart is placed on the rail but with the default texture. When i use the summon command, my Cart is also created, but i see only the shadow.
Here is the item:
package com.broschi.powercart.common;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jline.utils.Log;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockSource;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.core.dispenser.DispenseItemBehavior;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseRailBlock;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.RailShape;
import net.minecraft.world.level.gameevent.GameEvent;
public class PowercartItem extends Item {
private static final Logger LOGGER = LogManager.getLogger();
private static final DispenseItemBehavior DISPENSE_ITEM_BEHAVIOR = new DefaultDispenseItemBehavior() {
private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
public ItemStack execute(BlockSource p_42949_, ItemStack p_42950_) {
Direction direction = p_42949_.getBlockState().getValue(DispenserBlock.FACING);
Level level = p_42949_.getLevel();
double d0 = p_42949_.x() + (double) direction.getStepX() * 1.125D;
double d1 = Math.floor(p_42949_.y()) + (double) direction.getStepY();
double d2 = p_42949_.z() + (double) direction.getStepZ() * 1.125D;
BlockPos blockpos = p_42949_.getPos().relative(direction);
BlockState blockstate = level.getBlockState(blockpos);
RailShape railshape = blockstate.getBlock() instanceof BaseRailBlock
? ((BaseRailBlock) blockstate.getBlock()).getRailDirection(blockstate, level, blockpos, null)
: RailShape.NORTH_SOUTH;
double d3;
if (blockstate.is(BlockTags.RAILS)) {
if (railshape.isAscending()) {
d3 = 0.6D;
} else {
d3 = 0.1D;
}
} else {
if (!blockstate.isAir() || !level.getBlockState(blockpos.below()).is(BlockTags.RAILS)) {
return this.defaultDispenseItemBehavior.dispense(p_42949_, p_42950_);
}
BlockState blockstate1 = level.getBlockState(blockpos.below());
RailShape railshape1 = blockstate1.getBlock() instanceof BaseRailBlock
? blockstate1.getValue(((BaseRailBlock) blockstate1.getBlock()).getShapeProperty())
: RailShape.NORTH_SOUTH;
if (direction != Direction.DOWN && railshape1.isAscending()) {
d3 = -0.4D;
} else {
d3 = -0.9D;
}
}
AbstractMinecart abstractminecart = new PowercartEntity(level, d0, d1 + d3, d2);
if (p_42950_.hasCustomHoverName()) {
abstractminecart.setCustomName(p_42950_.getHoverName());
}
level.addFreshEntity(abstractminecart);
p_42950_.shrink(1);
return p_42950_;
}
protected void playSound(BlockSource p_42947_) {
p_42947_.getLevel().levelEvent(1000, p_42947_.getPos(), 0);
}
};
public PowercartItem(Properties properties) {
super((new Item.Properties()).stacksTo(64).tab(CreativeModeTab.TAB_TRANSPORTATION));
DispenserBlock.registerBehavior(this, DISPENSE_ITEM_BEHAVIOR);
}
@Override
public InteractionResult useOn(UseOnContext context) {
Level level = context.getLevel();
BlockPos pos = context.getClickedPos();
BlockState state = level.getBlockState(pos);
if (!state.is(BlockTags.RAILS)) {
return InteractionResult.FAIL;
} else {
ItemStack itemstack = context.getItemInHand();
if (!level.isClientSide) {
RailShape shape = state.getBlock() instanceof BaseRailBlock ? ((BaseRailBlock)state.getBlock()).getRailDirection(state, level, pos, (AbstractMinecart)null) : RailShape.NORTH_SOUTH;
double d0 = 0.0D;
if (shape.isAscending()) {
d0 = 0.5D;
}
PowercartEntity cart = new PowercartEntity(level, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.0625D + d0, (double)pos.getZ() + 0.5D);
level.addFreshEntity(cart);
}
itemstack.shrink(1);
return InteractionResult.SUCCESS;
}
}
}