Jump to content

Entities not updating rotation (not rendering it at least)


Recommended Posts

Posted

We have our own custom entities which I try to let faceBlocks or faceEntities.

 

Using things like:

 

        worker.faceEntity(entityToAttack, 30.0F, 30.0F);
        worker.getLookHelper().setLookPositionWithEntity(entityToAttack, 30.0F, 30.0F);

 

But our entity doesn't really face it, when I hit it ingame it updates the rotation but else it will still look into the same direction even if his variables have been changed already.

(LookPosition he takes only a glance into the wished direction)

 

package com.minecolonies.entity;

import com.minecolonies.MineColonies;
import com.minecolonies.client.render.RenderBipedCitizen;
import com.minecolonies.colony.*;
import com.minecolonies.colony.buildings.AbstractBuildingWorker;
import com.minecolonies.colony.buildings.BuildingFarmer;
import com.minecolonies.colony.buildings.BuildingHome;
import com.minecolonies.colony.jobs.AbstractJob;
import com.minecolonies.configuration.Configurations;
import com.minecolonies.entity.ai.basic.AbstractEntityAIInteract;
import com.minecolonies.entity.ai.minimal.*;
import com.minecolonies.entity.pathfinding.PathNavigate;
import com.minecolonies.inventory.InventoryCitizen;
import com.minecolonies.lib.Constants;
import com.minecolonies.network.messages.BlockParticleEffectMessage;
import com.minecolonies.util.*;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.ContainerPlayer;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Field;
import java.util.*;

/**
* The Class used to represent the citizen entities.
*/
public class EntityCitizen extends EntityAgeable implements INpc
{
    private static final DataParameter<Integer> DATA_TEXTURE         = EntityDataManager.<Integer>createKey(EntityCitizen.class, DataSerializers.VARINT);
    private static final DataParameter<Integer> DATA_LEVEL           = EntityDataManager.<Integer>createKey(EntityCitizen.class, DataSerializers.VARINT);
    private static final DataParameter<Integer> DATA_IS_FEMALE       = EntityDataManager.<Integer>createKey(EntityCitizen.class, DataSerializers.VARINT);
    private static final DataParameter<Integer> DATA_COLONY_ID       = EntityDataManager.<Integer>createKey(EntityCitizen.class, DataSerializers.VARINT);
    private static final DataParameter<Integer> DATA_CITIZEN_ID      = EntityDataManager.<Integer>createKey(EntityCitizen.class, DataSerializers.VARINT);
    private static final DataParameter<String>  DATA_MODEL           = EntityDataManager.<String>createKey(EntityCitizen.class, DataSerializers.STRING);
    private static final DataParameter<String>  DATA_RENDER_METADATA = EntityDataManager.<String>createKey(EntityCitizen.class, DataSerializers.STRING);

    /**
     * The movement speed for the citizen to run away.
     */
    private static final int MOVE_AWAY_SPEED = 2;

    /**
     * The range for the citizen to move away.
     */
    private static final int MOVE_AWAY_RANGE = 6;

    /**
     * Number of ticks to heal the citizens
     */
    private static final int HEAL_CITIZENS_AFTER = 200;

    /**
     * Tag's to save data to NBT
     */
    private static final String TAG_COLONY_ID      = "colony";
    private static final String TAG_CITIZEN        = "citizen";
    private static final String TAG_HELD_ITEM_SLOT = "HeldItemSlot";
    private static final String TAG_STATUS         = "status";

    /**
     * The delta yaw value for looking at things.
     */
    private static final float FACING_DELTA_YAW = 10F;

    /**
     * The range in which we can hear a block break sound.
     */
    private static final double BLOCK_BREAK_SOUND_RANGE = 16.0D;

    /**
     * The range in which someone will see the particles from a block breaking.
     */
    private static final double BLOCK_BREAK_PARTICLE_RANGE = 16.0D;

    /**
     * Divide experience by a factor to ensure more levels fit in an int.
     */
    private static final int EXP_DIVIDER               = 10;

    /**
     * Chance the citizen will rant about bad weather. 20 ticks per 60 seconds = 5 minutes.
     */
    private static final int RANT_ABOUT_WEATHER_CHANCE = 20*60*5;
    private static Field navigatorField;
    protected Status                   status  = Status.IDLE;
    private   RenderBipedCitizen.Model modelId = RenderBipedCitizen.Model.SETTLER;
    private String           renderMetadata;
    private ResourceLocation texture;
    private InventoryCitizen inventory;
    private int              colonyId;
    private int citizenId = 0;
    private int level;
    private int textureId;
    /**
     * Skill modifier defines how fast a citizen levels in a certain skill
     */
    private double skillModifier = 0;
    private boolean     female;
    @Nullable
    private Colony      colony;
    @Nullable
    private CitizenData citizenData;
    @NotNull
    private Map<String, Integer> statusMessages = new HashMap<>();
    private PathNavigate newNavigator;

    /**
     * Height of the citizen.
     */
    private static final double CITIZEN_HEIGHT = 1.8D;

    /**
     * Width of the citizen.
     */
    private static final double CITIZEN_WIDTH = 0.6D;

    /**
     * Defines how far the citizen will be rendered.
     */
    private static final double RENDER_DISTANCE_WEIGHT = 2.0D;

    /**
     * Citizen constructor.
     *
     * @param world the world the citizen lives in.
     */
    public EntityCitizen(World world)
    {
        super(world);
        setSize((float)CITIZEN_WIDTH, (float)CITIZEN_HEIGHT);
        this.enablePersistence();
        this.setAlwaysRenderNameTag(Configurations.alwaysRenderNameTag);
        this.inventory = new InventoryCitizen("Minecolonies Inventory", false, this);
        this.newNavigator = new PathNavigate(this, world);
        updateNavigatorField();
        if(world.isRemote)
        {
            setRenderDistanceWeight(RENDER_DISTANCE_WEIGHT);
        }
        this.newNavigator.setCanSwim(true);
        this.newNavigator.setEnterDoors(true);

        initTasks();
    }
    
    /**
     *
     */
    private synchronized void updateNavigatorField()
    {
        if (navigatorField == null)
        {
            Field[] fields = EntityLiving.class.getDeclaredFields();
            for (@NotNull Field field : fields)
            {
                if (field.getType().equals(net.minecraft.pathfinding.PathNavigate.class))
                {
                    field.setAccessible(true);
                    navigatorField = field;
                    break;
                }
            }
        }

        if (navigatorField == null)
        {
            throw new IllegalStateException("Navigator field should not be null, contact developers.");
        }

        try
        {
            navigatorField.set(this, this.newNavigator);
        }
        catch (IllegalAccessException e)
        {
            Log.getLogger().error("Navigator error", e);
        }
    }

    /**
     * Initiates basic citizen tasks.
     */
    private void initTasks()
    {
        this.tasks.addTask(0, new EntityAISwimming(this));

        if(this.getColonyJob() == null || !this.getColonyJob().getName().equals("com.minecolonies.job.Guard"))
        {
            this.tasks.addTask(1, new EntityAICitizenAvoidEntity(this, EntityMob.class, 8.0F, 0.6D, 1.6D));
        }
        this.tasks.addTask(2, new EntityAIGoHome(this));
        this.tasks.addTask(3, new EntityAISleep(this));
        this.tasks.addTask(4, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(4, new EntityAIOpenFenceGate(this, true));
        this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(6, new EntityAIWatchClosest2(this, EntityCitizen.class, 5.0F, 0.02F));
        this.tasks.addTask(7, new EntityAICitizenWander(this, 0.6D));
        this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityLiving.class, 6.0F));

        onJobChanged(getColonyJob());
    }

    /**
     * Defines job changes and state changes of the citizen.
     * @param job the set job.
     */
    public void onJobChanged(@Nullable AbstractJob job)
    {
        //  Model
        if (job != null)
        {
            modelId = job.getModel();
        }
        else
        {
            switch (getLevel())
            {
                case 1:
                    modelId = RenderBipedCitizen.Model.CITIZEN;
                    break;
                case 2:
                    modelId = RenderBipedCitizen.Model.NOBLE;
                    break;
                case 3:
                    modelId = RenderBipedCitizen.Model.ARISTOCRAT;
                    break;
                default:
                    modelId = RenderBipedCitizen.Model.SETTLER;
                    break;
            }
        }

        dataManager.set(DATA_MODEL, modelId.name());
        setRenderMetadata("");


        //  AI Tasks
        @NotNull Object[] currentTasks = this.tasks.taskEntries.toArray();
        for (@NotNull Object task : currentTasks)
        {
            if (((EntityAITasks.EntityAITaskEntry) task).action instanceof AbstractEntityAIInteract)
            {
                this.tasks.removeTask(((EntityAITasks.EntityAITaskEntry) task).action);
            }
        }

        if (job != null)
        {
            job.addTasks(this.tasks);
            if (ticksExisted > 0  && getWorkBuilding() != null)
            {
                BlockPosUtil.tryMoveLivingToXYZ(this, getWorkBuilding().getLocation());
            }
        }
    }

    public AbstractJob getColonyJob()
    {
        return citizenData != null ? citizenData.getJob() : null;
    }

    public int getLevel()
    {
        return level;
    }

    public void setRenderMetadata(String metadata)
    {
        renderMetadata = metadata;
        dataManager.set(DATA_RENDER_METADATA, renderMetadata);
        //Display some debug info always available while testing
        //tofo: remove this when in Beta!
        //Will help track down some hard to find bugs (Pathfinding etc.)
        if (citizenData != null)
        {
            if (this.getColonyJob() != null && Configurations.enableInDevelopmentFeatures)
            {
                setCustomNameTag(citizenData.getName() + " (" + getStatus() + ")[" + this.getColonyJob()
                                                                                       .getNameTagDescription() + "]");
            }
            else
            {
                setCustomNameTag(citizenData.getName());
            }
        }
    }

    /**
     * calculate this workers building.
     *
     * @return the building or null if none present.
     */
    @Nullable
    public AbstractBuildingWorker getWorkBuilding()
    {
        return (citizenData != null) ? citizenData.getWorkBuilding() : null;
    }

    public Status getStatus()
    {
        return status;
    }

    public void setStatus(Status status)
    {
        this.status = status;
    }

    /**
     * Checks if a worker is at his working site.
     * If he isn't, sets it's path to the location
     *
     * @param site  the place where he should walk to
     * @param range Range to check in
     * @return True if worker is at site, otherwise false.
     */
    public boolean isWorkerAtSiteWithMove(@NotNull BlockPos site, int range)
    {
        return EntityUtils.isWorkerAtSiteWithMove(this, site.getX(), site.getY(), site.getZ(), range)
                 //Fix for getting stuck sometimes
                 || EntityUtils.isWorkerAtSite(this, site.getX(), site.getY(), site.getZ(), range + 1);
    }

    @Nullable
    public <J extends AbstractJob> J getColonyJob(@NotNull Class<J> type)
    {
        return citizenData != null ? citizenData.getJob(type) : null;
    }

    /**
     * Change the citizens Rotation to look at said block
     *
     * @param block the block he should look at
     */
    public void faceBlock(@Nullable BlockPos block)
    {
        if (block == null)
        {
            return;
        }

        double xDifference = block.getX() - this.posX;
        double zDifference = block.getZ() - this.posZ;
        double yDifference = block.getY() - (this.posY + (double) this.getEyeHeight());

        double squareDifference = Math.sqrt(xDifference * xDifference + zDifference * zDifference);
        double intendedRotationYaw = (Math.atan2(zDifference, xDifference) * 180.0D / Math.PI) - 90.0;
        double intendedRotationPitch = -(Math.atan2(yDifference, squareDifference) * 180.0D / Math.PI);
        this.setRotation((float) this.updateRotation(this.rotationYaw, intendedRotationYaw, 30), (float) this.updateRotation(this.rotationPitch, intendedRotationPitch, 30));
    }

    /**
     * Returns the new rotation degree calculated from the current and intended rotation up to a max.
     *
     * @param currentRotation  the current rotation the citizen has
     * @param intendedRotation the wanted rotation he should have after applying this
     * @param maxIncrement     the 'movement speed'
     * @return a rotation value he should move
     */
    private double updateRotation(double currentRotation, double intendedRotation, double maxIncrement)
    {
        double wrappedAngle = MathHelper.wrapDegrees(intendedRotation - currentRotation);

        if (wrappedAngle > maxIncrement)
        {
            wrappedAngle = maxIncrement;
        }

        if (wrappedAngle < -maxIncrement)
        {
            wrappedAngle = -maxIncrement;
        }

        return currentRotation + wrappedAngle;
    }

    /**
     * Collect exp orbs around the entity
     */
    public void gatherXp()
    {
        for (@NotNull EntityXPOrb orb : getXPOrbsOnGrid())
        {
            addExperience(orb.getXpValue());
            orb.setDead();
        }
    }

    /**
     * Defines the area in which the citizen automatically gathers experience
     *
     * @return a list of xp orbs around the entity
     */
    private List<EntityXPOrb> getXPOrbsOnGrid()
    {
        @NotNull AxisAlignedBB bb = new AxisAlignedBB(posX - 2, posY - 2, posZ - 2, posX + 2, posY + 2, posZ + 2);

        return worldObj.getEntitiesWithinAABB(EntityXPOrb.class, bb);
    }

    /**
     * Add experience points to citizen.
     * Increases the citizen level if he has sufficient experience.
     * This will reset the experience.
     *
     * @param xp the amount of points added
     */
    public void addExperience(double xp)
    {
        double maxValue = Integer.MAX_VALUE - citizenData.getExperience();

        double localXp = xp * skillModifier / EXP_DIVIDER;
        if (localXp > maxValue)
        {
            localXp = maxValue;
        }
        citizenData.addExperience(localXp);

        while (ExperienceUtils.getXPNeededForNextLevel(citizenData.getLevel()) < citizenData.getExperience())
        {
            citizenData.increaseLevel();
        }

        citizenData.markDirty();
    }

    /**
     * Entities treat being on ladders as not on ground; this breaks navigation logic
     */
    @Override
    protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos)
    {
        if (!onGround)
        {
            int px = MathHelper.floor_double(posX);
            int py = (int) posY;
            int pz = MathHelper.floor_double(posZ);

            this.onGround =
              worldObj.getBlockState(new BlockPos(px, py, pz)).getBlock().isLadder(worldObj.getBlockState(new BlockPos(px, py, pz)), worldObj, new BlockPos(px, py, pz), this);
        }

        super.updateFallState(y, onGroundIn, state, pos);
    }

    /**
     * Called when the mob's health reaches 0.
     *
     * @param par1DamageSource the attacking entity
     */
    @Override
    public void onDeath(DamageSource par1DamageSource)
    {
        dropExperience();
        this.setDead();

        if (colony != null)
        {
            LanguageHandler.sendPlayersLocalizedMessage(
              colony.getMessageEntityPlayers(),
              "tile.blockHutTownHall.messageColonistDead",
              citizenData.getName());

            colony.removeCitizen(getCitizenData());
        }
        super.onDeath(par1DamageSource);
    }

    /**
     * Drop some experience share depending on the experience and experienceLevel.
     */
    private void dropExperience()
    {
        int experience;

        if (!this.worldObj.isRemote && this.recentlyHit > 0 && this.canDropLoot() && this.worldObj.getGameRules().getBoolean("doMobLoot"))
        {
            experience = (int) (citizenData.getLevel() * 100 + this.getExperiencePoints());

            while (experience > 0)
            {
                int j = EntityXPOrb.getXPSplit(experience);
                experience -= j;
                this.worldObj.spawnEntityInWorld(new EntityXPOrb(this.worldObj, this.posX, this.posY, this.posZ, j));
            }
        }

        //Spawn particle explosion of xp orbs on death
        for (int i = 0; i < 20; ++i)
        {
            double d2 = this.rand.nextGaussian() * 0.02D;
            double d0 = this.rand.nextGaussian() * 0.02D;
            double d1 = this.rand.nextGaussian() * 0.02D;
            this.worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE,
              this.posX + (this.rand.nextDouble() * this.width * 2.0F) - (double) this.width,
              this.posY + (this.rand.nextDouble() * this.height),
              this.posZ + (this.rand.nextDouble() * this.width * 2.0F) - (double) this.width,
              d2,
              d0,
              d1);
        }
    }

    @Nullable
    public CitizenData getCitizenData()
    {
        return citizenData;
    }

    /**
     * Get the experience points the entity currently has.
     * <p>
     *
     * @return the amount of xp this entity has
     */
    private double getExperiencePoints()
    {
        return citizenData.getExperience();
    }

    @Override
    public EntityAgeable createChild(EntityAgeable var1)
    {
        //TODO 
        return null;
    }

    /**
     * Called when a player tries to interact with a citizen.
     *
     * @param player which interacts with the citizen
     * @return If citizen should interact or not.
     */
    @Override
    public boolean processInteract(@NotNull EntityPlayer player, EnumHand hand, @Nullable ItemStack stack)
    {
        if (worldObj.isRemote)
        {
            CitizenDataView citizenDataView = getCitizenDataView();
            if (citizenDataView != null)
            {
                MineColonies.proxy.showCitizenWindow(citizenDataView);
            }
        }
        return true;
    }

    @Override
    public void entityInit()
    {
        super.entityInit();
        dataManager.register(DATA_COLONY_ID, colonyId);
        dataManager.register(DATA_CITIZEN_ID, citizenId);
        dataManager.register(DATA_TEXTURE, 0);
        dataManager.register(DATA_LEVEL, 0);
        dataManager.register(DATA_IS_FEMALE, 0);
        dataManager.register(DATA_MODEL, RenderBipedCitizen.Model.SETTLER.name());
        dataManager.register(DATA_RENDER_METADATA, "");
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound compound)
    {
        super.writeEntityToNBT(compound);
        compound.setInteger(TAG_STATUS, status.ordinal());
        if (colony != null && citizenData != null)
        {
            compound.setInteger(TAG_COLONY_ID, colony.getID());
            compound.setInteger(TAG_CITIZEN, citizenData.getId());
        }

        inventory.writeToNBT(compound);
        compound.setInteger(TAG_HELD_ITEM_SLOT, inventory.getHeldItemSlot());
    }

    @Override
    public void readEntityFromNBT(NBTTagCompound compound)
    {
        super.readEntityFromNBT(compound);

        status = Status.values()[compound.getInteger(TAG_STATUS)];
        colonyId = compound.getInteger(TAG_COLONY_ID);
        citizenId = compound.getInteger(TAG_CITIZEN);

        if (isServerWorld())
        {
            updateColonyServer();
        }
        inventory.readFromNBT(compound);

        inventory.setHeldItem(compound.getInteger(TAG_HELD_ITEM_SLOT));
    }

    /**
     * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
     * use this to react to sunlight and start to burn.
     */
    @Override
    public void onLivingUpdate()
    {
        if (recentlyHit > 0)
        {
            citizenData.markDirty();
        }
        if (worldObj.isRemote)
        {
            updateColonyClient();
        }
        else
        {
            pickupItems();
            cleanupChatMessages();
            updateColonyServer();
            if(worldObj.isDaytime() && !worldObj.isRaining())
            {
                SoundUtils.playRandomSound(worldObj, this);
            }
            else if(worldObj.isRaining() && 1 >=rand.nextInt(RANT_ABOUT_WEATHER_CHANCE) && this.getColonyJob() != null)
            {
                SoundUtils.playSoundAtCitizenWithChance(worldObj, this.getPosition(), this.getColonyJob().getBadWeatherSound(), 1);
            }
        }

        if (isEntityInsideOpaqueBlock() || isInsideOfMaterial(Material.LEAVES))
        {
            getNavigator().moveAwayFromXYZ(this.getPosition(), MOVE_AWAY_RANGE, MOVE_AWAY_SPEED);
        }

        checkHeal();
        super.onLivingUpdate();
    }

    /**
     * Getter of the citizens random object.
     * @return random object.
     */
    public Random getRandom()
    {
        return rand;
    }

    private void updateColonyClient()
    {
        if (dataManager.isDirty())
        {
            if (colonyId == 0)
            {
                colonyId = dataManager.get(DATA_COLONY_ID);
            }

            if (citizenId == 0)
            {
                citizenId = dataManager.get(DATA_CITIZEN_ID);
            }

            female = dataManager.get(DATA_IS_FEMALE) != 0;
            level = dataManager.get(DATA_LEVEL);
            modelId = RenderBipedCitizen.Model.valueOf(dataManager.get(DATA_MODEL));
            textureId = dataManager.get(DATA_TEXTURE);
            renderMetadata = dataManager.get(DATA_RENDER_METADATA);
            setTexture();
            dataManager.setClean();
        }
        updateArmSwingProgress();
    }

    /**
     * Pick up all items in a range around the citizen.
     */
    private void pickupItems()
    {
        @NotNull List<EntityItem> retList = new ArrayList<>();
        //I know streams look better but they are flawed in type erasure
        for (Object o : worldObj.getEntitiesWithinAABB(EntityItem.class, getEntityBoundingBox().expand(2.0F, 0.0F, 2.0F)))
        {
            if (o instanceof EntityItem)
            {
                retList.add((EntityItem) o);
            }
        }

        retList.stream()
          .filter(item -> item != null)
          .filter(item -> !item.isDead)
          .filter(item -> canPickUpLoot())
          .forEach(this::tryPickupEntityItem);
    }

    private void cleanupChatMessages()
    {
        //Only check if there are messages and once a second
        if (statusMessages.size() > 0 && ticksExisted % 20 == 0)
        {
            @NotNull Iterator<Map.Entry<String, Integer>> it = statusMessages.entrySet().iterator();
            while (it.hasNext())
            {
                if (ticksExisted - it.next().getValue() > 20 * Configurations.chatFrequency)
                {
                    it.remove();
                }
            }
        }
    }

    /**
     * Checks the citizens health status and heals the citizen if necessary.
     */
    private void checkHeal()
    {
        if (citizenData != null && getOffsetTicks() % HEAL_CITIZENS_AFTER == 0 && getHealth() < getMaxHealth())
        {
            heal(1);
            citizenData.markDirty();
        }
    }

    /**
     * Sets the textures of all citizens and distinguishes between male and female
     */
    private void setTexture()
    {
        if (!worldObj.isRemote)
        {
            return;
        }

        RenderBipedCitizen.Model model = getModelID();

        String textureBase = "textures/entity/";
        textureBase += model.textureBase;
        textureBase += female ? "Female" : "Male";

        int moddedTextureId = (textureId % model.numTextures) + 1;
        texture = new ResourceLocation(Constants.MOD_ID, textureBase + moddedTextureId + renderMetadata + ".png");
    }

    public int getOffsetTicks()
    {
        return this.ticksExisted + 7 * this.getEntityId();
    }

    public RenderBipedCitizen.Model getModelID()
    {
        return modelId;
    }

    /**
     * Server-specific update for the EntityCitizen
     */
    public void updateColonyServer()
    {
        if (colonyId == 0)
        {
            setDead();
            return;
        }

        if (colony == null)
        {
            handleNullColony();
        }
    }

    /**
     * Handles extreme cases like colony or citizen is null.
     */
    private void handleNullColony()
    {
        Colony c = ColonyManager.getColony(colonyId);

        if (c == null)
        {
            Log.getLogger().warn(String.format("EntityCitizen '%s' unable to find Colony #%d", getUniqueID(), colonyId));
            setDead();
            return;
        }

        CitizenData data = c.getCitizen(citizenId);
        if (data == null)
        {
            //  Citizen does not exist in the Colony
            Log.getLogger().warn(String.format("EntityCitizen '%s' attempting to register with Colony #%d as Citizen %d, but not known to colony",
              getUniqueID(),
              colonyId,
              citizenId));
            setDead();
            return;
        }

        @Nullable EntityCitizen existingCitizen = data.getCitizenEntity();
        if (existingCitizen != null && existingCitizen != this)
        {
            // This Citizen already has a different Entity registered to it
            handleExistingCitizen(data, existingCitizen);
            return;
        }

        setColony(c, data);
    }

    private void handleExistingCitizen(@NotNull CitizenData data, @NotNull EntityCitizen existingCitizen)
    {
        Log.getLogger().warn(String.format("EntityCitizen '%s' attempting to register with Colony #%d as Citizen #%d, but already have a citizen ('%s')",
          getUniqueID(),
          colonyId,
          citizenId,
          existingCitizen.getUniqueID()));
        if (!existingCitizen.getUniqueID().equals(this.getUniqueID()))
        {
            setDead();
        }
        else
        {
            data.setCitizenEntity(this);
        }
    }

    /**
     * Assigns a citizen to a colony.
     * @param c the colony.
     * @param data the data of the new citizen.
     */
    public void setColony(@Nullable Colony c, @Nullable CitizenData data)
    {
        if (c == null)
        {
            colony = null;
            colonyId = 0;
            citizenId = 0;
            citizenData = null;
            setDead();
            return;
        }

        colony = c;
        colonyId = colony.getID();
        citizenId = data.getId();
        citizenData = data;

        setCustomNameTag(citizenData.getName());

        female = citizenData.isFemale();
        textureId = citizenData.getTextureId();

        dataManager.set(DATA_COLONY_ID, colonyId);
        dataManager.set(DATA_CITIZEN_ID, citizenId);
        dataManager.set(DATA_IS_FEMALE, female ? 1 : 0);
        dataManager.set(DATA_TEXTURE, textureId);
        updateLevel();

        citizenData.setCitizenEntity(this);

        onJobChanged(getColonyJob());

        inventory.createMaterialStore(c.getMaterialSystem());
    }

    /**
     * Updates the level of the citizen.
     */
    private void updateLevel()
    {
        level = citizenData != null ? citizenData.getLevel() : 0;
        dataManager.set(DATA_LEVEL, level);
    }

    /**
     * Getter of the dataview, the clientside representation of the citizen.
     * @return the view.
     */
    private CitizenDataView getCitizenDataView()
    {
        if (colonyId != 0 && citizenId != 0)
        {
            ColonyView colonyView = ColonyManager.getColonyView(colonyId);
            if (colonyView != null)
            {
                return colonyView.getCitizen(citizenId);
            }
        }

        return null;
    }

    /**
     * Applies attributes like health, charisma etc to the citizens.
     */
    @Override
    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
        getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.3D);

        //path finding search range
        getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(100);
    }

    @NotNull
    @Override
    public PathNavigate getNavigator()
    {
        return newNavigator;
    }
    
    /**
     * Drop the equipment for this entity.
     */
    @Override
    protected void dropEquipment(boolean par1, int par2)
    {
        //Drop actual inventory
        for (int i = 0; i < inventory.getSizeInventory(); i++)
        {
            ItemStack itemstack = inventory.getStackInSlot(i);
            if (itemstack != null && itemstack.stackSize > 0)
            {
                entityDropItem(itemstack);
            }
        }
    }

    /**
     * Returns false if the newer Entity AI code should be run
     */
    @Override
    public boolean isAIDisabled()
    {
        return false;
    }

    /**
     * Return this citizens inventory.
     *
     * @return the inventory this citizen has.
     */
    @NotNull
    public InventoryCitizen getInventoryCitizen()
    {
        return inventory;
    }

    /**
     * Handles the dropping of items from the entity.
     * @param itemstack to drop.
     * @return the dropped item.
     */
    private EntityItem entityDropItem(@NotNull ItemStack itemstack)
    {
        return entityDropItem(itemstack, 0.0F);
    }

    /**
     * Getter of the resource location of the texture.
     * @return location of the texture.
     */
    public ResourceLocation getTexture()
    {
        return texture;
    }

    /**
     * Getter which checks if the citizen is female.
     * @return true if female.
     */
    public boolean isFemale()
    {
        return female;
    }

    /**
     * Clears the colony of the citizen.
     */
    public void clearColony()
    {
        setColony(null, null);
    }

    public boolean isAtHome()
    {
        @Nullable BlockPos homePosition = getHomePosition();
        return homePosition != null && homePosition.distanceSq((int) Math.floor(posX), (int) posY, (int) Math.floor(posZ)) <= 16;
    }

    /**
     * Returns the home position of each citizen (His house or town hall)
     *
     * @return location
     */
    @Nullable
    @Override
    public BlockPos getHomePosition()
    {
        @Nullable BuildingHome homeBuilding = getHomeBuilding();
        if (homeBuilding != null)
        {
            return homeBuilding.getLocation();
        }
        else if (getColony() != null && getColony().getTownHall() != null)
        {
            return getColony().getTownHall().getLocation();
        }

        return null;
    }

    private BuildingHome getHomeBuilding()
    {
        return (citizenData != null) ? citizenData.getHomeBuilding() : null;
    }

    @Nullable
    public Colony getColony()
    {
        return colony;
    }

    public boolean isInventoryFull()
    {
        return InventoryUtils.isInventoryFull(getInventoryCitizen());
    }

    @NotNull
    public DesiredActivity getDesiredActivity()
    {
        if (!worldObj.isDaytime())
        {
            return DesiredActivity.SLEEP;
        }
        else if (worldObj.isRaining())
        {
            return DesiredActivity.IDLE;
        }
        else
        {
            return DesiredActivity.WORK;
        }
    }

    /**
     * We override this method and execute no code to avoid citizens travelling to the nether.
     *
     * @param dimensionIn dimension to travel to.
     */
    @Override
    @Nullable
    public Entity changeDimension(int dimensionIn)
    {
        return null;
    }

    @NotNull
    @Override
    public BlockPos getPosition()
    {
        return new BlockPos(posX, posY, posZ);
    }

    /**
     * Returns the first slot in the inventory with a specific item.
     * @param targetItem the item.
     * @return the slot.
     */
    public int findFirstSlotInInventoryWith(Item targetItem)
    {
        return InventoryUtils.findFirstSlotInInventoryWith(getInventoryCitizen(), targetItem);
    }

    /**
     * Returns the first slot in the inventory with a specific block.
     * @param block the block.
     * @return the slot.
     */
    public int findFirstSlotInInventoryWith(Block block)
    {
        return InventoryUtils.findFirstSlotInInventoryWith(getInventoryCitizen(), block);
    }

    /**
     * Returns the amount of a certain block in the inventory.
     * @param block the block.
     * @return the quantity.
     */
    public int getItemCountInInventory(Block block)
    {
        return InventoryUtils.getItemCountInInventory(getInventoryCitizen(), block);
    }

    /**
     * Returns the amount of a certain item in the inventory.
     * @param targetItem the block.
     * @return the quantity.
     */
    public int getItemCountInInventory(Item targetItem)
    {
        return InventoryUtils.getItemCountInInventory(getInventoryCitizen(), targetItem);
    }

    /**
     * Checks if citizen has a certain block in the inventory.
     * @param block the block.
     * @return true if so.
     */
    public boolean hasItemInInventory(Block block)
    {
        return InventoryUtils.hasitemInInventory(getInventoryCitizen(), block);
    }

    /**
     * Checks if citizen has a certain item in the inventory.
     * @param item the item.
     * @return true if so.
     */
    public boolean hasItemInInventory(Item item)
    {
        return InventoryUtils.hasitemInInventory(getInventoryCitizen(), item);
    }

    /**
     * Citizen will try to pick up a certain item.
     * @param entityItem the item he wants to pickup.
     */
    private void tryPickupEntityItem(@NotNull EntityItem entityItem)
    {
        if (!this.worldObj.isRemote)
        {
            if (entityItem.cannotPickup())
            {
                return;
            }

            ItemStack itemStack = entityItem.getEntityItem();

            int i = itemStack.stackSize;
            if (i <= 0 || InventoryUtils.addItemStackToInventory(this.getInventoryCitizen(), itemStack))
            {
                this.worldObj.playSound((EntityPlayer) null,
                  this.getPosition(),
                        SoundEvents.ENTITY_ITEM_PICKUP,
                  SoundCategory.AMBIENT,
                  0.2F,
                  (float) ((this.rand.nextGaussian() * 0.7D + 1.0D) * 2.0D));
                this.onItemPickup(this, i);

                if (itemStack.stackSize <= 0)
                {
                    entityItem.setDead();
                }
            }
        }
    }

    /**
     * Removes the currently held item.
     */
    public void removeHeldItem()
    {
        setItemStackToSlot(EntityEquipmentSlot.MAINHAND, null);
    }

    /**
     * Sets the currently held item.
     *
     * @param slot from the inventory slot.
     */
    public void setHeldItem(int slot)
    {
        inventory.setHeldItem(slot);
        setItemStackToSlot(EntityEquipmentSlot.MAINHAND, inventory.getStackInSlot(slot));
    }

    /**
     * Swing entity arm, create sound and particle effects.
     * <p>
     * Will not break the block.
     *
     * @param blockPos Block position
     */
    public void hitBlockWithToolInHand(@Nullable final BlockPos blockPos)
    {
        if (blockPos == null)
        {
            return;
        }
        hitBlockWithToolInHand(blockPos, false);
    }

    /**
     * Swing entity arm, create sound and particle effects.
     * <p>
     * If breakBlock is true then it will break the block (different sound and particles),
     * and damage the tool in the citizens hand.
     *
     * @param blockPos   Block position
     * @param breakBlock if we want to break this block
     */
    private void hitBlockWithToolInHand(@Nullable final BlockPos blockPos, final boolean breakBlock)
    {
        if (blockPos == null)
        {
            return;
        }

        this.getLookHelper().setLookPosition(blockPos.getX(), blockPos.getY(), blockPos.getZ(), FACING_DELTA_YAW, getVerticalFaceSpeed());

        this.swingArm(this.getActiveHand());

        IBlockState blockState = worldObj.getBlockState(blockPos);
        Block block = blockState.getBlock();
        if (breakBlock)
        {
            if (!worldObj.isRemote)
            {
                MineColonies.getNetwork().sendToAllAround(
                  new BlockParticleEffectMessage(blockPos, worldObj.getBlockState(blockPos), BlockParticleEffectMessage.BREAK_BLOCK),
                  new NetworkRegistry.TargetPoint(worldObj.provider.getDimension(), blockPos.getX(), blockPos.getY(), blockPos.getZ(), BLOCK_BREAK_SOUND_RANGE));
            }
            worldObj.playSound(null,
              blockPos,
              block.getSoundType(blockState, worldObj, blockPos, this).getBreakSound(),
              SoundCategory.BLOCKS,
              block.getSoundType(blockState, worldObj, blockPos, this).getVolume(),
              block.getSoundType(blockState, worldObj, blockPos, this).getPitch());
            worldObj.setBlockToAir(blockPos);

            damageItemInHand(1);
        }
        else
        {
            //todo: might remove this
            if (!worldObj.isRemote)
            {
                MineColonies.getNetwork().sendToAllAround(
                  //todo: correct side
                  new BlockParticleEffectMessage(blockPos, worldObj.getBlockState(blockPos), 1),
                  new NetworkRegistry.TargetPoint(worldObj.provider.getDimension(), blockPos.getX(), blockPos.getY(), blockPos.getZ(), BLOCK_BREAK_PARTICLE_RANGE));
            }
            worldObj.playSound((EntityPlayer) null,
                    blockPos,
                    block.getSoundType(blockState, worldObj, blockPos, this).getBreakSound(),
                    SoundCategory.BLOCKS,
                    block.getSoundType(blockState, worldObj, blockPos, this).getVolume(),
                    block.getSoundType(blockState, worldObj, blockPos, this).getPitch());
        }
    }

    /**
     * Damage the current held item.
     *
     * @param damage amount of damage
     */
    public void damageItemInHand(final int damage)
    {
        final ItemStack heldItem = inventory.getHeldItemMainhand();
        //If we hit with bare hands, ignore
        if (heldItem == null)
        {
            return;
        }
        heldItem.damageItem(damage, this);

        //check if tool breaks
        if (heldItem.stackSize < 1)
        {
            getInventoryCitizen().setInventorySlotContents(getInventoryCitizen().getHeldItemSlot(), null);
            this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, null);
        }
    }

    /**
     * Swing entity arm, create sound and particle effects.
     * <p>
     * This will break the block (different sound and particles),
     * and damage the tool in the citizens hand.
     *
     * @param blockPos Block position
     */
    public void breakBlockWithToolInHand(@Nullable final BlockPos blockPos)
    {
        if (blockPos == null)
        {
            return;
        }
        hitBlockWithToolInHand(blockPos, true);
    }

    /**
     * Sends a localized message from the citizen containing a language string with a key and arguments.
     *
     * @param key  the key to retrieve the string.
     * @param args additional arguments.
     */
    public void sendLocalizedChat(String key, Object... args)
    {
        sendChat(LanguageHandler.format(key, args));
    }

    /**
     * Sends a chat string close to the citizen.
     *
     * @param msg the message string.
     */
    private void sendChat(@Nullable String msg)
    {
        if (msg == null || msg.length() == 0 || statusMessages.containsKey(msg))
        {
            return;
        }

        statusMessages.put(msg, ticksExisted);

        LanguageHandler.sendPlayersMessage(
          colony.getMessageEntityPlayers(),
          //TODO does this need to go through the LanguageHandler#format?
          LanguageHandler.format(this.getColonyJob().getName()) + " " + this.getCustomNameTag() + ": " + msg);
    }

    /**
     * Intelligence getter
     *
     * @return citizen intelligence value
     */
    public int getIntelligence()
    {
        return citizenData.getIntelligence();
    }

    /**
     * Charisma getter
     *
     * @return citizen Charisma value
     */
    public int getCharisma()
    {
        return citizenData.getCharisma();
    }

    /**
     * Strength getter
     *
     * @return citizen Strength value
     */
    public int getStrength()
    {
        return citizenData.getStrength();
    }

    /**
     * Endurance getter
     *
     * @return citizen Endurance value
     */
    public int getEndurance()
    {
        return citizenData.getEndurance();
    }

    /**
     * Dexterity getter
     *
     * @return citizen Dexterity value
     */
    public int getDexterity()
    {
        return citizenData.getDexterity();
    }

    /**
     * Set the skill modifier which defines how fast a citizen levels in a certain skill
     *
     * @param modifier input modifier
     */
    public void setSkillModifier(int modifier)
    {
        skillModifier = modifier;
    }

    /**
     * ExperienceLevel getter
     *
     * @return citizen ExperienceLevel value
     */
    public int getExperienceLevel()
    {
        return citizenData.getLevel();
    }

    /**
     * Called when the citizen wakes up.
     */
    public void onWakeUp()
    {
        if (this.getWorkBuilding() instanceof BuildingFarmer)
        {
            ((BuildingFarmer) this.getWorkBuilding()).resetFields();
        }
    }

    /**
     * Enum describing the citizens activity.
     */
    public enum DesiredActivity
    {
        SLEEP,
        IDLE,
        WORK
    }

    /**
     * Used for chat messages, sounds, and other need based interactions
     * Created: June 20, 2014
     *
     * @author Colton
     */
    public enum Status
    {
        IDLE,
        SLEEPING,
        WORKING,
        GETTING_ITEMS,
        NEED_ASSISTANCE,
        PATHFINDING_ERROR
    }
}

Posted

He does not update his rotation at all, let it be entities, blocks or simply just updating rotation manually.

He only updates it when he is walking in that direction or when he gets hit or touched by something.

Posted
  On 10/15/2016 at 5:11 PM, Raycoms said:

And I just can't let them walk into the direction because they might be fighting or close to a cliff/lava/water so that wouldn't be the smartest solution.

Move them up 0.0001 or similar amount.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Posted

If I do that:

 

        customEntity.moveEntity(customEntity.posX, customEntity.posY + 0.001D, customEntity.posZ);

 

he actually vanishes and gets removed by minecraft.

 

Posted

MoveEntity is for moving by an amount, not to a location.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
 worker.faceEntity(entityToAttack, 30.0F, 30.0F);
        worker.getLookHelper().setLookPositionWithEntity(entityToAttack, 30.0F, 30.0F);
        worker.moveEntity(0, 0.01D, 0);

        worker.swingArm(EnumHand.MAIN_HAND);
        worker.playSound(SoundEvents.ENTITY_SKELETON_SHOOT, 1.0F, 1.0F / (worker.getRNG().nextFloat() * 0.4F + 0.8F));
        worker.worldObj.spawnEntityInWorld(arrowEntity);

Posted

I have to move him into the direction:

 

worker.faceEntity(entityToAttack, 180.0F, 180.0F);
        worker.getLookHelper().setLookPositionWithEntity(entityToAttack, 180.0F, 180.0F);

        double xDiff = targetEntity.posX - worker.posX;
        double zDiff = targetEntity.posZ - worker.posZ;

        double goToX = xDiff > 0? 0.01 : -0.01;
        double goToZ = zDiff > 0? 0.01 : -0.01;

        worker.moveEntity(goToX, 0, goToZ);

 

works.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Codice Sconto Temu 100$ DI SCONTO → [acu639380] per Clienti Esistenti Ottieni  100$ di sconto con il Codice Promozionale Temu (acu639380) Temu continua a dominare il mondo dell’e-commerce con sconti imbattibili e prodotti di tendenza – e giugno 2025 non fa eccezione. Con il codice sconto Temu (acu639380), puoi ottenere fino a  100$ di sconto, sia che tu sia un nuovo cliente sia che tu stia tornando a fare acquisti. Grazie alla consegna ultra-rapida, spedizione gratuita in 67 paesi e sconti fino al 90%, Temu propone pacchetti esclusivi e codici promozionali imperdibili questo giugno. Ecco come sfruttare al meglio il codice (acu639380) e iniziare subito a risparmiare. Perché Giugno 2025 è il Momento Migliore per Acquistare su Temu Giugno è ricco di offerte a tempo limitato, nuovi arrivi di tendenza e sconti nascosti in tutte le categorie. Dalla moda all’elettronica, dalla bellezza agli articoli per la casa, Temu offre prodotti indispensabili a prezzi imbattibili. Usa il codice (acu639380) per accedere a:  100$ di sconto per nuovi utenti  100$ di sconto per clienti esistenti 40% di sconto extra su categorie selezionate Pacchetto di buoni da  100$ per nuovi e vecchi clienti Regalo di benvenuto gratuito per chi acquista per la prima volta Vantaggi Esclusivi dei Codici Sconto Temu Questi sconti sono pensati per ogni tipo di acquirente. Ottieni il massimo con: Codice Temu (acu639380)  100$ di sconto – Riduci il totale sui tuoi acquisti in blocco Codice Temu per utenti esistenti – Offerte premium riservate ai clienti fedeli Codice Temu per nuovi utenti – Grandi risparmi sul primo ordine Codice Temu 40% di sconto – Perfetto per moda e prodotti stagionali Pacchetto coupon da  100$ Temu – Risparmia su più ordini Coupon per nuovi utenti Temu – Inizia con un regalo + sconto Offerte Localizzate con il Codice Temu (acu639380) Grazie alla presenza globale di Temu, puoi accedere a offerte personalizzate ovunque ti trovi: Codice Temu  100$ di sconto – USA Codice Temu  100$ di sconto – Canada Codice Temu  100$ di sconto – Regno Unito Codice Temu  100$ di sconto – Giappone Codice Temu 40% di sconto – Messico Codice Temu 40% di sconto – Brasile Codice Temu  100$ di sconto – Germania Codice Temu  100$ di sconto – Francia Codice Temu per nuovi utenti – Argentina Coupon Temu per utenti esistenti – Italia Codice promozionale Temu (acu639380) – Spagna, giugno 2025 Cosa Comprare su Temu a Giugno 2025 L’ampio catalogo Temu include migliaia di categorie. Ecco alcuni articoli su cui usare il codice sconto (acu639380): Gadget intelligenti e accessori Moda per tutte le età Decorazioni per la casa e soluzioni salvaspazio Prodotti per il benessere, fitness e bellezza Utensili da cucina e pentolame Articoli per ufficio, giochi e regali La Mia Esperienza Risparmiando  100$ con il Codice Temu (acu639380) Quando ho usato il codice (acu639380) da cliente abituale, ho ricevuto immediatamente  100$ di sconto. Combinandolo con la promozione del 40% e il pacchetto da  100$, ho ottenuto oltre 200 $ di valore per meno di 80 $. Anche tu puoi farlo. Ti basta inserire (acu639380) al checkout, e lo sconto si applica automaticamente – con spedizione gratuita in tutto il mondo inclusa. Altri Sconti Temu per Giugno 2025 Questo mese è pieno di offerte a rotazione, pacchetti a sorpresa e vendite flash giornaliere. Resta aggiornato su: Nuove uscite con il coupon per nuovi utenti Temu Aggiornamenti settimanali dei codici per clienti esistenti Promozioni regionali con il codice (acu639380) per giugno 2025 Conclusione Ovunque ti trovi – in Nord America, Europa o Sud America – il codice Temu (acu639380) è la chiave per risparmiare alla grande. Con offerte per nuovi utenti e clienti fedeli, questo è il momento perfetto per approfittare dei prezzi imbattibili di Temu. Usa il codice acu639380 oggi stesso per ottenere vantaggi esclusivi e trasformare il tuo shopping in un’esperienza smart e conveniente.      
    • Come Ottenere il Codice Sconto Temu da 100$ [acu639380] per un Nuovo Ordine Vuoi approfittare di risparmi esclusivi sul tuo prossimo acquisto su Temu? Sei nel posto giusto! Utilizzando il codice sconto Temu (acu639380) puoi ottenere 100 $ di sconto immediato, fino al 40% di sconto extra e persino regali gratuiti con il tuo ordine. Che tu sia un nuovo utente o un cliente fedele, i codici promozionali Temu rendono lo shopping ancora più conveniente. Temu offre una vasta gamma di prodotti di tendenza a prezzi imbattibili, con spedizione veloce e gratuita in 67 paesi. Con sconti fino al 90% su articoli selezionati, non sorprende che Temu sia diventato il sito preferito dagli acquirenti più attenti. Continua a leggere per scoprire come ottenere queste incredibili offerte e sfruttare al massimo il codice sconto Temu (acu639380) a giugno 2025. Codice Sconto Temu per Giugno 2025 Giugno è il mese perfetto per iniziare a risparmiare grazie alle ultime offerte Temu. Il codice esclusivo (acu639380) offre vantaggi incredibili, tra cui: 100 $ di sconto per nuovi utenti – Perfetto per il tuo primo ordine 100 $ di sconto per utenti esistenti – Continua a risparmiare anche sui tuoi acquisti abituali 40% di sconto extra – Ancora più vantaggi su prodotti selezionati Pacchetto coupon da 100$ – Disponibile sia per nuovi che per vecchi clienti Regali gratuiti – Sorprese esclusive quando applichi il codice Temu (acu639380) Come Ottenere il Codice Sconto Temu da 100 $ [acu639380] su un Nuovo Ordine Segui questi semplici passaggi per utilizzare il codice Temu (acu639380) e ottenere uno sconto di 100 $ sul tuo ordine: Registrati o accedi: Crea un account su Temu se sei un nuovo utente, oppure effettua il login se sei già cliente Scegli i prodotti: Aggiungi i tuoi articoli preferiti al carrello Applica il codice: Inserisci il codice (acu639380) al momento del pagamento Goditi il risparmio: Guarda il totale diminuire di 100 $ all’istante Vantaggi dell’Uso dei Codici Sconto Temu Quando acquisti con i codici promozionali Temu, accedi a un mondo di vantaggi e risparmi. Ecco i benefici principali: 100 $ di sconto per nuovi utenti – Inizia alla grande 100 $ di sconto per utenti esistenti – Anche i clienti abituali vengono premiati 40% di sconto extra – Somma altri risparmi su prodotti già scontati Regalo gratuito per nuovi utenti – Un benvenuto speciale per te Pacchetto coupon da 100 $ – Perfetto per massimizzare i tuoi risparmi Codici Esclusivi Temu per Nuovi ed Esistenti Clienti Ecco una panoramica dei migliori codici Temu disponibili a giugno 2025: Temu codice (acu639380) 100 $ di sconto per nuovi utenti Ideale per chi effettua il primo ordine e vuole iniziare con un bel risparmio Temu codice (acu639380) 100 $ di sconto per clienti esistenti I clienti di ritorno possono continuare a risparmiare Temu codice (acu639380) 40% di sconto Sconti ulteriori su prodotti selezionati Pacchetto coupon Temu da 100 $ Ottieni una collezione di buoni sconto da usare in più ordini Coupon Temu per nuovi utenti Sconti e vantaggi esclusivi per chi acquista per la prima volta Codice promo Temu (acu639380) per giugno 2025 Sblocca tutte le offerte attive del mese Codici Temu per Paese Scopri come utilizzare il codice Temu nei diversi paesi: Codice Temu 100 $ di sconto – USA Codice Temu 100 $ di sconto – Canada Codice Temu 100 $ di sconto – Regno Unito Codice Temu 100 $ di sconto – Giappone Codice Temu 40% di sconto – Messico Codice Temu 40% di sconto – Brasile Come Massimizzare i Tuoi Risparmi su Temu Per ottenere il massimo dai tuoi acquisti, segui questi consigli utili: Combina le offerte: Usa il codice Temu (acu639380) insieme ad altri sconti del sito Acquista durante le promozioni: Approfitta di vendite flash e offerte limitate Utilizza il pacchetto da 100 $: Ottieni sconti extra su più ordini Richiedi i regali: Non dimenticare di riscattare i tuoi omaggi esclusivi Iscriviti alle novità: Ricevi aggiornamenti su nuove offerte e codici sconto Conclusione Temu continua a rivoluzionare lo shopping online offrendo sconti incredibili e offerte esclusive. Con il codice sconto Temu (acu639380) puoi ottenere 100 $ di sconto, 40% di sconto extra e accedere al pacchetto coupon da 100 $. Non perdere questa opportunità. Applica subito il codice (acu639380) e rendi il tuo shopping di giugno 2025 ancora più conveniente. Buono shopping!      
    • Temu Promo Code [acu639380] $100 Off For Existing Customers Unlock Massive Savings with Temu Coupon Codes: Save Big with $100 OFF and More! Temu is a revolutionary online marketplace that offers a huge collection of trending items at unbeatable prices. Whether you're looking for gadgets, home décor, fashion, or beauty products, Temu has something for everyone. By using the Temu coupon code $100 OFF → [acu639380] for existing customers, you can unlock incredible discounts, save up to 90%, and even enjoy free shipping to over 67 countries. In this blog, we will explore the latest Temu coupon code offerings, including $100 off for new and existing users, a special 40% discount on select items, and the incredible Temu coupon bundle. Read on to discover how you can make the most of these discounts and enjoy amazing deals with Temu this June! What is Temu and Why Should You Shop There? Temu is a one-stop online shopping destination that offers a vast selection of products at prices that are hard to beat. Whether you're purchasing for yourself or looking for gifts, Temu delivers a wide variety of high-quality products across different categories. From clothing to electronics, home essentials, beauty products, and much more, Temu has something for everyone. With its fast delivery, free shipping in over 67 countries, and discounts of up to 90% off, it’s no wonder why shoppers worldwide love this platform. Not only does Temu offer competitive prices, but their frequent promotions and coupon codes make shopping even more affordable. In this blog, we’ll focus on how you can save even more with Temu coupon codes, including the highly sought-after $100 OFF and 40% OFF codes. The Power of Temu Coupon Code $100 OFF → [acu639380] for Existing Customers If you're a Temu existing customer, you can unlock a fantastic $100 OFF by using the code [acu639380]. This coupon code provides a generous discount, allowing you to save big on your next purchase, whether it’s electronics, fashion, or home décor. Here’s why you should take advantage of this offer: Flat $100 off: This code gives you a flat $100 discount on your order. Available for Existing Users: If you've shopped with Temu before, this coupon code is for you! Unbeatable Deals: Use this coupon in combination with other ongoing sales for even bigger savings. Huge Selection: Apply the code across Temu ’s massive inventory, from tech gadgets to everyday essentials. Temu Coupon Code $100 OFF → [acu639380] for New Users Are you new to Temu ? You’re in luck! Temu has a special $100 off coupon code just for you. By using [acu639380], new users can enjoy a $100 discount on their first purchase. This is an excellent way to try out the platform without breaking the bank. Here’s how to make the most of your Temu coupon code as a new user: $100 Off Your First Order: If you’ve never shopped with Temu before, the [acu639380] code gets you $100 off your first purchase. Great for First-Time Shoppers: Explore Temu 's range of trending items while saving money right from the start. Free Gifts: As a new user, you June also receive a special gift with your order as part of the ongoing promotions. Temu Coupon Code 40% Off → [acu639380] for Extra Savings Looking for even more savings? The 40% off coupon is an amazing deal that’s available for a limited time. By using the code [acu639380], you can enjoy an extra 40% off on selected items. Whether you're shopping for electronics, home goods, or fashion, this coupon code allows you to grab even better deals on top of existing discounts. 40% Extra Off: This discount can be applied to select categories and items, giving you incredible savings. Stack with Other Offers: Combine it with other promotions for unbeatable prices. Popular Items: Use the 40% off code to save on some of Temu ’s hottest items of the season. Temu Coupon Bundle: Unlock Even More Savings When you use the Temu coupon bundle, you get even more benefits. Temu offers a $100 coupon bundle, which allows both new and existing users to save even more on a variety of products. Whether you're shopping for yourself or buying gifts for others, this bundle can help you save big. $100 Coupon Bundle: The Temu coupon bundle lets you apply multiple discounts at once, ensuring maximum savings. Available to All Users: Whether you’re a first-time shopper or a returning customer, the bundle is available for you to enjoy. Stacked Savings: When combined with other codes like the 40% off or the $100 off, you can save up to 90%. Temu Coupon Code June 2025: New Offers and Promotions If you're shopping in June 2025, you're in for a treat! Temu is offering a range of new offers and discount codes for the month. Whether you're shopping for electronics, clothing, or home décor, you’ll find discounts that will help you save a ton. Don’t miss out on the Temu promo code and Temu discount code that are available only for a limited time this month. Temu New User Coupon: New users can save up to $100 off their first order with the [acu639380] code. Temu Existing User Coupon: Existing users can unlock $100 off using the [acu639380] code. Temu Coupon Code for June 2025: Get discounts on select items with up to 40% off this June. Temu Coupon Code for Different Countries No matter where you live, Temu has something special for you! You can use Temu coupon codes tailored to your country to unlock great savings. Here’s a breakdown of how you can apply the [acu639380] coupon code in different regions: Temu Coupon Code $100 Off for USA: Use the [acu639380] code in the USA to save $100 off your order. Temu Coupon Code $100 Off for Canada: Canadians can enjoy $100 off using the [acu639380] code. Temu Coupon Code $100 Off for UK: British shoppers can save $100 with the [acu639380] code. Temu Coupon Code $100 Off for Japan: If you’re in Japan, apply the [acu639380] code to get $100 off. Temu Coupon Code 40% Off for Mexico: Mexican shoppers can get 40% off with the [acu639380] code. Temu Coupon Code 40% Off for Brazil: Brazil residents can save 40% by using the [acu639380] code. Why Shop with Temu ? Temu isn’t just about the discounts; it’s about providing you with an exceptional shopping experience. Here’s why you should choose Temu for your next shopping spree: Huge Selection of Trending Items: From the latest tech gadgets to fashion and home essentials, Temu offers everything you need at amazing prices. Unbeatable Prices: With Temu , you can shop for quality items at prices that are hard to match elsewhere. Fast Delivery: Enjoy fast and reliable delivery on all your orders. Free Shipping in Over 67 Countries: No matter where you are, Temu ensures you get your products without any extra shipping fees. Up to 90% Off: Take advantage of massive discounts on selected products, so you can get more for less. Conclusion: Maximize Your Savings with Temu Coupon Codes If you're looking for incredible deals, there’s no better time to shop at Temu . With Temu coupon code $100 OFF for existing and new users, an extra 40% off, and amazing coupon bundles, there are plenty of ways to save big. Don’t forget to check out the Temu promo code for June 2025 and other exciting offers throughout the month. By using [acu639380], you can make the most of your shopping experience and enjoy unbeatable prices on all your favorite products. So, what are you waiting for? Start shopping with Temu today, and enjoy massive savings with the $100 off and 40% off coupon codes. Happy shopping! Temu Coupon Code Summary: Temu Coupon Code $100 Off → [acu639380]: Save $100 on your purchase. Temu Coupon Code $100 Off for New Users → [acu639380]: New users can get $100 off. Temu Coupon Code $100 Off for Existing Users → [acu639380]: Existing users can save $100. Temu Coupon Code 40% Off → [acu639380]: Enjoy 40% off select items. Temu Coupon Bundle: Access a $100 coupon bundle for even more savings. Temu Promo Code for June 2025: Latest deals for June 2025.  
    • Maximize Savings With [acu639380] Temu Coupon Code $200 Off Temu is revolutionizing online shopping with unbeatable prices, fast delivery, and an extensive range of trending products. To make your shopping experience even better, Temu is offering an exclusive Temu coupon code (acu639380) that provides massive discounts. Whether you’re a new user or a loyal customer, this June 2025 promotion is packed with savings, including a flat $200 discount, an extra 40% off, a $200 coupon bundle, and free gifts. Take advantage of this incredible deal while it lasts! Unlock the Best Deals with Temu Coupon Code (acu639380) By using the Temu coupon code (acu639380) at checkout, you can enjoy a variety of amazing discounts: $200 Off for New Users – First-time shoppers can use Temu coupon code (acu639380) $200 off for new users to save instantly. $200 Off for Existing Users – Regular customers can also take advantage of Temu coupon code (acu639380) $200 off for existing users to maximize their savings. 40% Extra Off – Get an additional 40% discount on select items with Temu coupon code (acu639380) 40% off. $200 Coupon Bundle – Grab a Temu $200 coupon bundle that provides extra discounts across multiple purchases. Free Gift for New Users – Use the Temu first time user coupon to receive a surprise gift with your first order. How to Apply Your Temu Coupon Code (acu639380) Applying your Temu discount code (acu639380) for June 2025 is quick and easy: Sign Up or Log In – Create a new account or sign in to your existing Temu account. Shop for Your Favorite Items – Browse through a vast selection of products at discounted rates. Enter the Coupon Code – Apply Temu promo code (acu639380) for June 2025 at checkout. Enjoy the Savings – Watch your total drop significantly and complete your purchase! Why Choose Temu ? Temu stands out in the online shopping space for many reasons: Vast Collection of Trending Items – Shop from a huge variety of products, from electronics to fashion and home essentials. Unbeatable Prices – Enjoy competitive rates on top-quality items. Fast Delivery – Get your orders delivered promptly to your doorstep. Free Shipping – Temu offers free shipping in 67 countries, making it an attractive shopping platform for international buyers. Up to 90% Off – Some items come with discounts of up to 90% off, ensuring you always get the best deals. Exclusive Temu Offers for June 2025 This month brings incredible savings with new promotions and deals: Temu Coupon for June 2025 – Special discounts available this month with Temu coupon code (acu639380). Temu Discount Code (acu639380) for June 2025 – Apply this code to unlock extra savings across multiple categories. Temu New Offers in June 2025 – Stay updated with fresh deals throughout the month to maximize your savings. Country-Specific Temu Coupon Codes Temu is extending exclusive offers to shoppers in North America, South America, and Europe: North America: Temu Coupon Code $200 Off for USA – Enjoy a flat $200 discount on your purchase in the United States. Temu Coupon Code $200 Off for Canada – Shoppers in Canada can save big with this exclusive offer. South America: Temu Coupon Code 40% Off for Mexico – Use this to get 40% off select items. Temu Coupon Code 40% Off for Brazil – Brazilian shoppers can maximize savings with this discount. Europe: Temu Coupon Code $200 Off for UK – British customers can apply this code for instant savings. Temu Coupon Code $200 Off for Germany – Shoppers in Germany can enjoy a $200 discount on their orders. Final Thoughts: Maximize Your Savings with Temu  Shopping on Temu has never been more rewarding! Whether you’re a new or existing user, the Temu coupon code (acu639380) provides massive discounts and incredible savings. With free shipping, fast delivery, and unbeatable prices, there’s no reason to miss out. Take advantage of the Temu promo code (acu639380) for June 2025 before it expires, and make the most of your shopping experience. Happy shopping!  
    • Temu Coupon Code £100 Off United States [acu639380] For 2025 Unlock Exceptional Value: Temu Coupon Code (acu639380) £100 Off in the United States for June 2025 Temu is redefining online shopping in 2025 with unbeatable prices, fast delivery, and a huge variety of trending items. With global shipping to 67 countries, more shoppers than ever are turning to Temu for quality and savings. If you're in the United States or elsewhere, the Temu coupon code (acu639380) brings exceptional value this June. Why Use the Temu Coupon Code (acu639380) in 2025? June 2025 is packed with exclusive offers and coupon bundles for both new and returning users. The Temu coupon code (acu639380) £100 off isn’t just promotional fluff—it’s a genuine opportunity to save big on the items you love. Key Benefits of the Temu Coupon Code (acu639380) £100 off for new users: Enjoy a flat £100 discount on your first order. £100 off for existing users: Returning customers are eligible for the same great savings. 40% extra off: Apply the Temu coupon code (acu639380) 40% off for select item categories. £100 coupon bundle: Receive a group of high-value coupons for use across departments. Free gift for new users: First-time buyers are also eligible for a welcome gift. Global Savings: Geographic Breakdown of Temu Coupons These coupons aren't limited to the United States—shoppers around the world can benefit: Temu coupon code (acu639380) £100 off – USA: Great for tech, home, and fashion. Temu coupon code (acu639380) £100 off – Canada: Save big on appliances and electronics. Temu coupon code (acu639380) £100 off – UK: Use it on gardening, fashion, and more. Temu coupon code (acu639380) 40% off – Mexico: Ideal for seasonal clothing and party gear. Temu coupon code (acu639380) 40% off – Brazil: Excellent for beauty and lifestyle items. Temu coupon code (acu639380) £100 off – Japan: Perfect for storage solutions and home decor. Why Temu Stands Out Temu is more than just deals—it’s a complete shopping experience: Massive selection of popular and trending items. Discounts up to 90% off retail prices. Free shipping in 67 countries. Real-time order tracking and fast delivery. Regularly updated promotions and seasonal deals. Temu Coupon Codes Explained Take advantage of these targeted deals with ease: Temu coupon code (acu639380) £100 off for new users: Use this on your first purchase. Temu coupon code (acu639380) £100 off for existing users: Loyal users qualify too. Temu coupon code (acu639380) 40% off: Extra savings on featured categories. Temu £100 coupon bundle: Redeem a set of valuable discounts. Temu new user coupon: Exclusive offers for first-time buyers. Temu discount code (acu639380) for June 2025: Valid throughout June for rotating deals. A Personalized Shopping Experience Speaking from experience, using the Temu coupon code (acu639380) changed how I shop. I was able to explore products I once passed over because they were suddenly within budget. You can turn a regular shopping session into something far more rewarding. What’s New at Temu in June 2025? June’s highlights include: Weekly-updated seasonal offers. Early access to limited-time flash sales using the Temu promo code (acu639380). Expanded inventory in high-demand categories like electronics, home décor, and pet supplies. Final Thoughts This is the time to make your money go further. Whether you're a new shopper or a seasoned buyer, the Temu coupon code (acu639380) can unlock amazing deals. Use it to get £100 off, enjoy 40% discounts, claim bundled savings, and even receive free gifts. Smart shopping means making use of smart discounts. Temu has made that easier than ever in 2025—and with the right code, so can you.
  • Topics

  • Who's Online (See full list)

    • There are no registered users currently online
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.