-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entity Metadata Wrapper #3
base: master
Are you sure you want to change the base?
Conversation
Nice job, but I feel extending WrappedDataWatcher would create unnecessarily clutter. I think the composition pattern is more appropriate here - just delegate all method calls to a WrappedDataWatcher. I imagine you'd then either retrieve the underlying DataWatcher with getDataWatcher(), or just use Packet14SpawnNamedEntity.setMetadata(). I wonder though, wouldn't it be better to create a different subclass for each entity type (they all share entity or living entity). Since most people merely copy classes from this resource (instead of maven shading), they should probably be inner classes, and easily castable from the superclass EntityMetadata: public class EntityMetadata {
public static class LivingEntityMetadata extends EntityMetdata {
public float getHealth();
public Color getPotionEffectColor();
public boolean isPotionEffectAmbient();
public int getStuckArrowCount();
public String getNameTag();
public boolean isNameTagDisplayed();
}
public static class AgeableMetadata extends LivingEntityMetadata {
public int getAge();
}
public static class HorseMetadata extends AgeableMetadata {
public int getHorseFlags();
// ... and so on
}
public int getFlags(); // index 0
public int getAirBubbles(); // index 1
public EntityMetadata setFlags(int flags);
public EntityMetadata setAirBubbles(int count);
// For easy casting
public HorseMetadata asHorse();
// For easy construction
public static HorseMetadata newHorse();
protected WrappedDataWatcher watcher;
} This would add a significant amount of boilerplate code, but I think it would be better to use. I also recommend "builder"-style setters, but it's not essential. As for flags, they might very well be an IntEnum, like most things in PacketWrapper. But EnumSet is certainly a possible alternative. Anyways, I'll let you finish it before I pull it. |
OK, that make alot more sense than the way I was doing it, i'll probably try to rewrite it that way tomorrow, but do you think that the EntityMetadata could be extended to work with other things too? It has many more uses past mobs and players (projectiles, minecarts, boats, fireworks) I think it could be made into a flexible interface for modifying metadata of all entities. |
I'll get back to you tomorrow; it's (really) late here and I hardly know what i'm typing XD |
And its not necessarily needed in every Packet Wrapper project, but if the developer feels like they need a better way to write entity metadata, they can copy it into their project, it's not required or anything. |
Yeah, it should work for every entity type, including non-living entities such as arrows or minecarts.
ProtocolLib supports it - you can write and read an ItemStack directly to the WrappedDataWatcher, and it will do the rest. :) |
Started work on Javadoc Started adding enums for bit masks to be nice
Still working on it, not quite finished. Ran into a couple of problems though:
|
On a second thought, its probably best not to expose the bit fields as enums. It's really just an implementation detail designed to conserve bandwidth. Doesn't look like you've mastered bitmasking quite yet, but you're not that far off: public static class HorseMetadata extends EntityMetadata {
private static final int HORSE_FLAGS = 16;
private static final int HORSE_COLORSTYLE = 20;
// You could move this to EntityMetadata too
protected boolean getFlag(int index, int mask) {
return ((Integer) getMeta(index) & mask) != 0;
}
protected void setFlag(int index, int mask, boolean value) {
setMeta(index, ((Integer) getMeta(index) & ~mask) | (value ? mask : 0));
}
public boolean isTame() {
return getFlag(HORSE_FLAGS, 0x02);
}
public void setTame(boolean value) {
setFlag(HORSE_FLAGS, 0x02, value);
}
public boolean hasSadle() {
return getFlag(HORSE_FLAGS, 0x04);
}
public void setSadle(boolean value) {
setFlag(HORSE_FLAGS, 0x04, value);
}
// etc.
public boolean isMouthOpen() {
return getFlag(HORSE_FLAGS, 0x80);
}
public void setMouthOpen(boolean value) {
setFlag(HORSE_FLAGS, 0x80, value);
}
// You need to extract the code with bit masking
public HorseColor getHorseColor() {
return HorseColor.fromId((Integer) getMeta(HORSE_COLORSTYLE) & 0xFF);
}
public void setHorseColor(HorseColor type) {
setMeta(HORSE_COLORSTYLE, (Integer)getMeta(HORSE_COLORSTYLE) & 0xFF00 | type.id);
}
// Same with the style
public HorseStyle getHorseStyle() {
return HorseStyle.fromId((Integer) getMeta(HORSE_COLORSTYLE) >> 16);
}
public void setHorseStyle(HorseStyle style) {
setMeta(HORSE_COLORSTYLE, (Integer)getMeta(HORSE_COLORSTYLE) & 0xFF | (style.id << 16));
}
public enum HorseColor {
WHITE(0),
CREAMY(1),
CHESTNUT(2),
BROWN(3),
BLACK(4),
GRAY(5),
DARK_BROWN(6);
int id;
private HorseColor(int id) {
this.id = id;
}
public static HorseColor fromId(int id) {
for (HorseColor type : values()) {
if (type.id == id)
return type;
}
throw new IllegalArgumentException("Unexpected horse type: " + id);
}
}
public enum HorseStyle {
NONE(0),
WHITE(1),
WHITEFIELD(2),
WHITE_DOTS(3),
BLACK_DOTS(4);
int id;
private HorseStyle(int id) {
this.id = id;
}
public static HorseStyle fromId(int id) {
for (HorseStyle style : values()) {
if (style.id == id)
return style;
}
throw new IllegalArgumentException("Unexpected horse style: " + id);
}
}
} Oh, and just cast the Objects. If the client sent the wrong type, the server will simply disconnect it. |
OK, I see, I needed to test if a flag had already been set and just add to that before overwriting the byte completely |
Added an easy to use wrapper for entity metadata, because it can be hard to understand normally.
The class extends WrappedDataWatcher and adds all methods to get/set the metadata.
This currently works with the SpawnMob class and the SpawnNamedEntity class, but it can be used for all entities in the future.
Users will use this class when normally using WrappedDataWatcher, so it would look like setMetadata(EntityMetadata value);
I did some sample javadoc at the beginning, but it takes so much time to write. I will finish it if you like the idea.
I am also planning to add enums for different types (villager, sheep, horse, etc) and the bit masks for mob flags (right now the class assumes the user know how to bitshift)