Jump to content

[1.7.10] Update any entity's scoreboard when position changes


IceMetalPunk

Recommended Posts

I've added three new scoreboard objectives (posX, posY, and posZ), which are supposed to track an entity's position. That works just fine. However, rather than update the score of every entity every tick with a tick handler, I'm hoping to do the updates more efficiently, updating only when the entity's position changes. I thought I'd be able to do this quite easily by having a LivingEntityUpdate event listener check the current posX/Y/Z values against the prevPosX/Y/Z values and updating the appropriate scoreboard value when needed. But it seems the prevPosX/Y/Z values aren't updated until immediately *after* the Forge event is fired, meaning after the first tick, every event I get has an entity with prevPosX=posX, making that comparison useless.

 

The second problem with this method is that it only works for living entities; I'd like the scoreboard to be able to track *any* entity, but I haven't found a general EntityUpdate event (EntityEvent only seems to have an event for creation, entering a chunk, and being found not to be updateable).

 

I've thought of a way to fix these problems using extended entity properties to store the previous positions and a tick handler that runs through every entity, updates the scoreboard if needed, and updates the extended property to the current position...but that seems like an inefficient overkill for this. Can anyone think of a more elegant solution?

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

I've now implemented it the way I mentioned, using extended properties to store and read the previous position and rotation values, and then updating the scoreboard when they change on a ServerTick event. But it turns out, that's even less efficient than I expected: I get 60fps without it running, and only about 30fps with it. It literally halves the FPS.

 

There must be a better way, but I still haven't thought of one. Can anyone please help me brainstorm a more efficient solution to this?

 

Below is my current code.

 

RedPlusCommonEventHandler.java:

package com.IceMetalPunk.redplus.handlers;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.IceMetalPunk.redplus.RedPlus;
import com.IceMetalPunk.redplus.properties.RedPlusEntityProperties;

import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import net.minecraft.entity.Entity;
import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;

public class RedPlusCommonEventHandler {
@SubscribeEvent
public void handleScoreboardUpdates(TickEvent.ServerTickEvent event) {
	if (event.phase == TickEvent.Phase.END) {
		return;
	}

	// Unnecessary overcautious prevention of possible null-pointer errors.
	MinecraftServer mc = MinecraftServer.getServer();
	if (mc == null) {
		return;
	}

	World world = mc.getEntityWorld();
	if (world == null) {
		return;
	}

	List entities = world.loadedEntityList;

	// Loop through all loaded entities
	Entity entity = null;
	for (Object entry : entities) {
		entity = (Entity) entry;
		world = entity.worldObj;

		// Only run on server entities; probably also over-cautious since this is in the server tick event.
		if (world.isRemote) {
			continue;
		}

		// Get the extended properties of the entity.
		RedPlusEntityProperties props = RedPlusEntityProperties.get(entity);
		if (props == null) {
			return;
		}

		// Update X-positions
		Collection collection = world.getScoreboard().func_96520_a(RedPlus.scorePosX);
		Iterator iterator = collection.iterator();

		// Rotation pitch = y, yaw = x
		if (props.lastX != entity.posX) {
			while (iterator.hasNext()) {
				ScoreObjective scoreobjective = (ScoreObjective) iterator.next();
				world.getScoreboard().func_96529_a(entity.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new Entity[] {
						entity }));
			}
		}

		// Update Y-positions
		if (props.lastY != entity.posY) {
			collection = world.getScoreboard().func_96520_a(RedPlus.scorePosY);
			iterator = collection.iterator();

			while (iterator.hasNext()) {
				ScoreObjective scoreobjective = (ScoreObjective) iterator.next();
				world.getScoreboard().func_96529_a(entity.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new Entity[] {
						entity }));
			}
		}

		// Update Z-positions
		if (props.lastZ != entity.posZ) {
			collection = world.getScoreboard().func_96520_a(RedPlus.scorePosZ);
			iterator = collection.iterator();
			while (iterator.hasNext()) {
				ScoreObjective scoreobjective = (ScoreObjective) iterator.next();
				world.getScoreboard().func_96529_a(entity.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new Entity[] {
						entity }));
			}
		}

		// Update yaw-rotations
		if (props.lastYaw != entity.rotationYaw) {
			collection = world.getScoreboard().func_96520_a(RedPlus.scoreRotationYaw);
			iterator = collection.iterator();
			while (iterator.hasNext()) {
				ScoreObjective scoreobjective = (ScoreObjective) iterator.next();
				world.getScoreboard().func_96529_a(entity.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new Entity[] {
						entity }));
			}
		}

		// Update pitch-rotations
		if (props.lastPitch != entity.rotationPitch) {
			collection = world.getScoreboard().func_96520_a(RedPlus.scoreRotationPitch);
			iterator = collection.iterator();
			while (iterator.hasNext()) {
				ScoreObjective scoreobjective = (ScoreObjective) iterator.next();
				world.getScoreboard().func_96529_a(entity.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new Entity[] {
						entity }));
			}
		}

		// Update the properties
		props.update();
	}
}
}

 

RedPlusEntityProperties.java:

package com.IceMetalPunk.redplus.properties;

import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;

public class RedPlusEntityProperties implements IExtendedEntityProperties {

public Entity myEntity;
public double lastX, lastY, lastZ;
public float lastPitch, lastYaw;

public final static String EXT_PROP_NAME = "RedPlusProps";

public RedPlusEntityProperties(Entity entity, World world) {
	this.init(entity, world);
}

@Override
public void saveNBTData(NBTTagCompound compound) {
	compound.setDouble("lastX", this.myEntity.posX);
	compound.setDouble("lastY", this.myEntity.posY);
	compound.setDouble("lastZ", this.myEntity.posZ);
	compound.setFloat("lastPitch", this.myEntity.rotationPitch);
	compound.setFloat("lastYaw", this.myEntity.rotationYaw);
}

@Override
public void loadNBTData(NBTTagCompound compound) {
	this.lastX = compound.getDouble("lastX");
	this.lastY = compound.getDouble("lasY");
	this.lastZ = compound.getDouble("lastZ");
	this.lastPitch = compound.getFloat("lastPitch");
	this.lastYaw = compound.getFloat("lastYaw");
}

@Override
public void init(Entity entity, World world) {
	this.myEntity = entity;
	this.lastX = entity.posX;
	this.lastY = entity.posY;
	this.lastZ = entity.posZ;
	this.lastPitch = entity.rotationPitch;
	this.lastYaw = entity.rotationYaw;
}

// Grab the extended properties for the given entity, aliased for shorter code elsewhere
public static final RedPlusEntityProperties get(Entity entity) {
	return (RedPlusEntityProperties) entity.getExtendedProperties(EXT_PROP_NAME);
}

// Update the "last" values to the entity's current values.
public void update() {
	this.lastX = this.myEntity.posX;
	this.lastY = this.myEntity.posY;
	this.lastZ = this.myEntity.posZ;
	this.lastPitch = this.myEntity.rotationPitch;
	this.lastYaw = this.myEntity.rotationYaw;
}

}

 

(They're both instantiated, registered, and applied per standard use of extended properties and tick event listeners.)

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

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



×
×
  • Create New...

Important Information

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