diff --git a/Minecraft.World/AI/Attributes/Attribute.cpp b/Minecraft.World/AI/Attributes/Attribute.cpp new file mode 100644 index 000000000..50fe7d1bf --- /dev/null +++ b/Minecraft.World/AI/Attributes/Attribute.cpp @@ -0,0 +1,14 @@ +#include "../../Platform/stdafx.h" +#include "Attribute.h" + +const int Attribute::AttributeNames[] = { + IDS_ATTRIBUTE_NAME_GENERIC_MAXHEALTH, + IDS_ATTRIBUTE_NAME_GENERIC_FOLLOWRANGE, + IDS_ATTRIBUTE_NAME_GENERIC_KNOCKBACKRESISTANCE, + IDS_ATTRIBUTE_NAME_GENERIC_MOVEMENTSPEED, + IDS_ATTRIBUTE_NAME_GENERIC_ATTACKDAMAGE, + IDS_ATTRIBUTE_NAME_HORSE_JUMPSTRENGTH, + IDS_ATTRIBUTE_NAME_ZOMBIE_SPAWNREINFORCEMENTS, +}; + +int Attribute::getName(eATTRIBUTE_ID id) { return AttributeNames[id]; } \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/Attribute.h b/Minecraft.World/AI/Attributes/Attribute.h new file mode 100644 index 000000000..3087fdd92 --- /dev/null +++ b/Minecraft.World/AI/Attributes/Attribute.h @@ -0,0 +1,73 @@ +#pragma once +class AttributeModifier; + +// 4J: This ID is serialised into save data so new attributes must always be +// added after existing ones +enum eATTRIBUTE_ID { + // 1.6.4 + eAttributeId_GENERIC_MAXHEALTH, + eAttributeId_GENERIC_FOLLOWRANGE, + eAttributeId_GENERIC_KNOCKBACKRESISTANCE, + eAttributeId_GENERIC_MOVEMENTSPEED, + eAttributeId_GENERIC_ATTACKDAMAGE, + eAttributeId_HORSE_JUMPSTRENGTH, + eAttributeId_ZOMBIE_SPAWNREINFORCEMENTS, + + // 1.8+ + // New attributes go here + + eAttributeId_COUNT +}; + +class Attribute { +public: + static const int MAX_NAME_LENGTH = 64; + + /** + * 4J: Changed this from a std::string name to an ID + * Gets the ID of this attribute, for serialization. + * + * @return Name of this attribute. + */ + virtual eATTRIBUTE_ID getId() = 0; + + /** + * Sanitizes an attribute value, making sure it's not out of range and is an + * acceptable amount. + * + * + * @param value Value to sanitize. + * @return Sanitized value, safe for use. + */ + virtual double sanitizeValue(double value) = 0; + + /** + * Get the default value of this attribute, to be used upon creation. + * + * @return Default value. + */ + virtual double getDefaultValue() = 0; + + /** + * Checks if this attribute should be synced to the client. + * + * Attributes should be serverside only unless the client needs to know + * about it. + * + * @return True if the client should know about this attribute. + */ + virtual bool isClientSyncable() = 0; + + // 4J: Added to retrieve std::string ID for attribute + static int getName(eATTRIBUTE_ID id); + +protected: + static const int AttributeNames[]; +}; + +#ifdef __ORBIS__ +typedef std::unordered_map> + attrAttrModMap; +#else +typedef std::unordered_map attrAttrModMap; +#endif \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/AttributeInstance.h b/Minecraft.World/AI/Attributes/AttributeInstance.h new file mode 100644 index 000000000..d99a43a86 --- /dev/null +++ b/Minecraft.World/AI/Attributes/AttributeInstance.h @@ -0,0 +1,24 @@ +#pragma once +#include "AttributeModifier.h" + +class AttributeInstance { +public: + virtual ~AttributeInstance() {} + + virtual Attribute* getAttribute() = 0; + virtual double getBaseValue() = 0; + virtual void setBaseValue(double baseValue) = 0; + virtual double getValue() = 0; + + virtual std::unordered_set* getModifiers( + int operation) = 0; + virtual void getModifiers( + std::unordered_set& result) = 0; + virtual AttributeModifier* getModifier(eMODIFIER_ID id) = 0; + virtual void addModifiers( + std::unordered_set* modifiers) = 0; + virtual void addModifier(AttributeModifier* modifier) = 0; + virtual void removeModifier(AttributeModifier* modifier) = 0; + virtual void removeModifier(eMODIFIER_ID id) = 0; + virtual void removeModifiers() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/AttributeModifier.cpp b/Minecraft.World/AI/Attributes/AttributeModifier.cpp new file mode 100644 index 000000000..854e24c90 --- /dev/null +++ b/Minecraft.World/AI/Attributes/AttributeModifier.cpp @@ -0,0 +1,107 @@ +#include "../../Platform/stdafx.h" + +#include "AttributeModifier.h" +#include "../../Util/HtmlString.h" + +void AttributeModifier::_init(eMODIFIER_ID id, const std::wstring name, + double amount, int operation) { + assert(operation < TOTAL_OPERATIONS); + this->amount = amount; + this->operation = operation; + this->name = name; + this->id = id; + this->serialize = true; +} + +AttributeModifier::AttributeModifier(double amount, int operation) { + // Create an anonymous attribute + _init(eModifierId_ANONYMOUS, name, amount, operation); +} + +AttributeModifier::AttributeModifier(eMODIFIER_ID id, double amount, + int operation) { + _init(id, name, amount, operation); + + // Validate.notEmpty(name, "Modifier name cannot be empty"); + // Validate.inclusiveBetween(0, TOTAL_OPERATIONS - 1, operation, "Invalid + // operation"); +} + +eMODIFIER_ID AttributeModifier::getId() { return id; } + +std::wstring AttributeModifier::getName() { return name; } + +int AttributeModifier::getOperation() { return operation; } + +double AttributeModifier::getAmount() { return amount; } + +bool AttributeModifier::isSerializable() { return serialize; } + +AttributeModifier* AttributeModifier::setSerialize(bool serialize) { + this->serialize = serialize; + return this; +} + +bool AttributeModifier::equals(AttributeModifier* modifier) { + if (this == modifier) return true; + if (modifier == NULL) + return false; //|| getClass() != o.getClass()) return false; + + if (id != modifier->id) return false; + + return true; +} + +std::wstring AttributeModifier::toString() { + return L""; + + /*return L"AttributeModifier{" + + L"amount=" + amount + + L", operation=" + operation + + L", name='" + name + '\'' + + L", id=" + id + + L", serialize=" + serialize + + L'}';*/ +} + +HtmlString AttributeModifier::getHoverText(eATTRIBUTE_ID attribute) { + double amount = getAmount(); + double displayAmount; + + if (getOperation() == AttributeModifier::OPERATION_MULTIPLY_BASE || + getOperation() == AttributeModifier::OPERATION_MULTIPLY_TOTAL) { + displayAmount = getAmount() * 100.0f; + } else { + displayAmount = getAmount(); + } + + eMinecraftColour color; + + if (amount > 0) { + color = eHTMLColor_9; + } else if (amount < 0) { + displayAmount *= -1; + color = eHTMLColor_c; + } + + bool percentage = false; + switch (getOperation()) { + case AttributeModifier::OPERATION_ADDITION: + percentage = false; + break; + case AttributeModifier::OPERATION_MULTIPLY_BASE: + case AttributeModifier::OPERATION_MULTIPLY_TOTAL: + percentage = true; + break; + default: + // No other operations + assert(0); + } + + wchar_t formatted[256]; + swprintf(formatted, 256, L"%ls%d%ls %ls", (amount > 0 ? L"+" : L"-"), + (int)displayAmount, (percentage ? L"%" : L""), + app.GetString(Attribute::getName(attribute))); + + return HtmlString(formatted, color); +} \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/AttributeModifier.h b/Minecraft.World/AI/Attributes/AttributeModifier.h new file mode 100644 index 000000000..3db3edcc5 --- /dev/null +++ b/Minecraft.World/AI/Attributes/AttributeModifier.h @@ -0,0 +1,74 @@ +#pragma once + +/* +4J - Both modifier uuid and name have been replaced by an id enum. Note that we +have special value "eModifierId_ANONYMOUS" for attribute modifiers that +previously didn't have a fixed UUID and are never removed. + +To all intents and purposes anonymous modifiers don't have an ID and so are +handled differently in some cases, for instance: + 1. You can have multiple modifiers with the anonymous ID on a single +attribute instance + 2. Anonymous modifiers can't be removed from attribute instance by ID + +IMPORTANT: Saved out to file so don't change order. All new values should be +added at the end. +*/ + +class HtmlString; + +enum eMODIFIER_ID { + eModifierId_ANONYMOUS = 0, + + eModifierId_ITEM_BASEDAMAGE, + + eModifierId_MOB_FLEEING, + eModifierId_MOB_SPRINTING, + + eModifierId_MOB_ENDERMAN_ATTACKSPEED, + eModifierId_MOB_PIG_ATTACKSPEED, + eModifierId_MOB_WITCH_DRINKSPEED, + eModifierId_MOB_ZOMBIE_BABYSPEED, + + eModifierId_POTION_DAMAGEBOOST, + eModifierId_POTION_HEALTHBOOST, + eModifierId_POTION_MOVESPEED, + eModifierId_POTION_MOVESLOWDOWN, + eModifierId_POTION_WEAKNESS, + + eModifierId_COUNT, +}; + +class AttributeModifier { +public: + static const int OPERATION_ADDITION = 0; + static const int OPERATION_MULTIPLY_BASE = 1; + static const int OPERATION_MULTIPLY_TOTAL = 2; + static const int TOTAL_OPERATIONS = 3; + +private: + double amount; + int operation; + std::wstring name; + eMODIFIER_ID id; + bool serialize; + + void _init(eMODIFIER_ID id, const std::wstring name, double amount, + int operation); + +public: + AttributeModifier(double amount, int operation); + AttributeModifier(eMODIFIER_ID id, double amount, int operation); + + eMODIFIER_ID getId(); + std::wstring getName(); + int getOperation(); + double getAmount(); + bool isSerializable(); + AttributeModifier* setSerialize(bool serialize); + bool equals(AttributeModifier* modifier); + std::wstring toString(); + HtmlString getHoverText( + eATTRIBUTE_ID attribute); // 4J: Added to keep modifier readable + // std::string creation in one place +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/BaseAttribute.cpp b/Minecraft.World/AI/Attributes/BaseAttribute.cpp new file mode 100644 index 000000000..4e80e8054 --- /dev/null +++ b/Minecraft.World/AI/Attributes/BaseAttribute.cpp @@ -0,0 +1,20 @@ +#include "../../Platform/stdafx.h" + +#include "BaseAttribute.h" + +BaseAttribute::BaseAttribute(eATTRIBUTE_ID id, double defaultValue) { + this->id = id; + this->defaultValue = defaultValue; + syncable = false; +} + +eATTRIBUTE_ID BaseAttribute::getId() { return id; } + +double BaseAttribute::getDefaultValue() { return defaultValue; } + +bool BaseAttribute::isClientSyncable() { return syncable; } + +BaseAttribute* BaseAttribute::setSyncable(bool syncable) { + this->syncable = syncable; + return this; +} \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/BaseAttribute.h b/Minecraft.World/AI/Attributes/BaseAttribute.h new file mode 100644 index 000000000..7fa53f5ab --- /dev/null +++ b/Minecraft.World/AI/Attributes/BaseAttribute.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Attribute.h" + +class BaseAttribute : public Attribute { +private: + eATTRIBUTE_ID id; + double defaultValue; + bool syncable; + +protected: + BaseAttribute(eATTRIBUTE_ID id, double defaultValue); + +public: + virtual eATTRIBUTE_ID getId(); + virtual double getDefaultValue(); + virtual bool isClientSyncable(); + virtual BaseAttribute* setSyncable(bool syncable); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/BaseAttributeMap.cpp b/Minecraft.World/AI/Attributes/BaseAttributeMap.cpp new file mode 100644 index 000000000..71e3384d5 --- /dev/null +++ b/Minecraft.World/AI/Attributes/BaseAttributeMap.cpp @@ -0,0 +1,68 @@ +#include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.entity.ai.attributes.h" +#include "BaseAttributeMap.h" + +BaseAttributeMap::~BaseAttributeMap() { + for (AUTO_VAR(it, attributesById.begin()); it != attributesById.end(); + ++it) { + delete it->second; + } +} + +AttributeInstance* BaseAttributeMap::getInstance(Attribute* attribute) { + return getInstance(attribute->getId()); +} + +AttributeInstance* BaseAttributeMap::getInstance(eATTRIBUTE_ID id) { + AUTO_VAR(it, attributesById.find(id)); + if (it != attributesById.end()) { + return it->second; + } else { + return NULL; + } +} + +void BaseAttributeMap::getAttributes(std::vector& atts) { + for (AUTO_VAR(it, attributesById.begin()); it != attributesById.end(); + ++it) { + atts.push_back(it->second); + } +} + +void BaseAttributeMap::onAttributeModified( + ModifiableAttributeInstance* attributeInstance) {} + +void BaseAttributeMap::removeItemModifiers(std::shared_ptr item) { + attrAttrModMap* modifiers = item->getAttributeModifiers(); + + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + AttributeInstance* attribute = getInstance(it->first); + AttributeModifier* modifier = it->second; + + if (attribute != NULL) { + attribute->removeModifier(modifier); + } + + delete modifier; + } + + delete modifiers; +} + +void BaseAttributeMap::addItemModifiers(std::shared_ptr item) { + attrAttrModMap* modifiers = item->getAttributeModifiers(); + + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + AttributeInstance* attribute = getInstance(it->first); + AttributeModifier* modifier = it->second; + + if (attribute != NULL) { + attribute->removeModifier(modifier); + attribute->addModifier(new AttributeModifier(*modifier)); + } + + delete modifier; + } + + delete modifiers; +} diff --git a/Minecraft.World/AI/Attributes/BaseAttributeMap.h b/Minecraft.World/AI/Attributes/BaseAttributeMap.h new file mode 100644 index 000000000..a10501aae --- /dev/null +++ b/Minecraft.World/AI/Attributes/BaseAttributeMap.h @@ -0,0 +1,31 @@ +#pragma once + +class ModifiableAttributeInstance; + +class BaseAttributeMap { +protected: + // unordered_map attributesByObject; +#ifdef __ORBIS__ + std::unordered_map > + attributesById; +#else + std::unordered_map attributesById; +#endif + +public: + virtual ~BaseAttributeMap(); + + virtual AttributeInstance* getInstance(Attribute* attribute); + virtual AttributeInstance* getInstance(eATTRIBUTE_ID name); + + virtual AttributeInstance* registerAttribute(Attribute* attribute) = 0; + + virtual void getAttributes(std::vector& atts); + virtual void onAttributeModified( + ModifiableAttributeInstance* attributeInstance); + + // 4J: Changed these into specialised functions for adding/removing the + // modifiers of an item (it's cleaner) + virtual void removeItemModifiers(std::shared_ptr item); + virtual void addItemModifiers(std::shared_ptr item); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.cpp b/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.cpp new file mode 100644 index 000000000..8abb926c8 --- /dev/null +++ b/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.cpp @@ -0,0 +1,160 @@ +#include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.entity.ai.attributes.h" +#include "ModifiableAttributeInstance.h" + +ModifiableAttributeInstance::ModifiableAttributeInstance( + BaseAttributeMap* attributeMap, Attribute* attribute) { + this->attributeMap = attributeMap; + this->attribute = attribute; + + dirty = true; + cachedValue = 0.0; + + baseValue = attribute->getDefaultValue(); +} + +ModifiableAttributeInstance::~ModifiableAttributeInstance() { + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) { + for (AUTO_VAR(it, modifiers[i].begin()); it != modifiers[i].end(); + ++it) { + // Delete all modifiers + delete *it; + } + } +} + +Attribute* ModifiableAttributeInstance::getAttribute() { return attribute; } + +double ModifiableAttributeInstance::getBaseValue() { return baseValue; } + +void ModifiableAttributeInstance::setBaseValue(double baseValue) { + if (baseValue == this->getBaseValue()) return; + this->baseValue = baseValue; + setDirty(); +} + +// Returns a pointer to an internally managed vector of modifers by operation +std::unordered_set* +ModifiableAttributeInstance::getModifiers(int operation) { + return &modifiers[operation]; +} + +// Returns a pointer to a new vector of all modifiers +void ModifiableAttributeInstance::getModifiers( + std::unordered_set& result) { + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) { + std::unordered_set* opModifiers = &modifiers[i]; + + for (AUTO_VAR(it, opModifiers->begin()); it != opModifiers->end(); + ++it) { + result.insert(*it); + } + } +} + +AttributeModifier* ModifiableAttributeInstance::getModifier(eMODIFIER_ID id) { + AttributeModifier* modifier = NULL; + + AUTO_VAR(it, modifierById.find(id)); + if (it != modifierById.end()) { + modifier = it->second; + } + + return modifier; +} + +void ModifiableAttributeInstance::addModifiers( + std::unordered_set* modifiers) { + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + addModifier(*it); + } +} + +// Add new modifier to attribute instance (takes ownership of modifier) +void ModifiableAttributeInstance::addModifier(AttributeModifier* modifier) { + // Can't add modifiers with the same ID (unless the modifier is anonymous) + if (modifier->getId() != eModifierId_ANONYMOUS && + getModifier(modifier->getId()) != NULL) { + assert(0); + // throw new IllegalArgumentException("Modifier is already applied on + // this attribute!"); + return; + } + + modifiers[modifier->getOperation()].insert(modifier); + modifierById[modifier->getId()] = modifier; + + setDirty(); +} + +void ModifiableAttributeInstance::setDirty() { + dirty = true; + attributeMap->onAttributeModified(this); +} + +void ModifiableAttributeInstance::removeModifier(AttributeModifier* modifier) { + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) { + for (AUTO_VAR(it, modifiers[i].begin()); it != modifiers[i].end(); + ++it) { + if (modifier->equals(*it)) { + modifiers[i].erase(it); + break; + } + } + } + + modifierById.erase(modifier->getId()); + + setDirty(); +} + +void ModifiableAttributeInstance::removeModifier(eMODIFIER_ID id) { + AttributeModifier* modifier = getModifier(id); + if (modifier != NULL) removeModifier(modifier); +} + +void ModifiableAttributeInstance::removeModifiers() { + std::unordered_set removingModifiers; + getModifiers(removingModifiers); + + for (AUTO_VAR(it, removingModifiers.begin()); it != removingModifiers.end(); + ++it) { + removeModifier(*it); + } +} + +double ModifiableAttributeInstance::getValue() { + if (dirty) { + cachedValue = calculateValue(); + dirty = false; + } + + return cachedValue; +} + +double ModifiableAttributeInstance::calculateValue() { + double base = getBaseValue(); + std::unordered_set* modifiers; + + modifiers = getModifiers(AttributeModifier::OPERATION_ADDITION); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + AttributeModifier* modifier = *it; + base += modifier->getAmount(); + } + + double result = base; + + modifiers = getModifiers(AttributeModifier::OPERATION_MULTIPLY_BASE); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + AttributeModifier* modifier = *it; + result += base * modifier->getAmount(); + } + + modifiers = getModifiers(AttributeModifier::OPERATION_MULTIPLY_TOTAL); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) { + AttributeModifier* modifier = *it; + result *= 1 + modifier->getAmount(); + } + + return attribute->sanitizeValue(result); +} \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.h b/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.h new file mode 100644 index 000000000..2ed250607 --- /dev/null +++ b/Minecraft.World/AI/Attributes/ModifiableAttributeInstance.h @@ -0,0 +1,41 @@ +#pragma once + +#include "AttributeInstance.h" + +class ModifiableAttributeInstance : public AttributeInstance { +private: + BaseAttributeMap* attributeMap; + Attribute* attribute; + std::unordered_set + modifiers[AttributeModifier::TOTAL_OPERATIONS]; + std::unordered_map modifierById; + double baseValue; + bool dirty; + double cachedValue; + +public: + ModifiableAttributeInstance(BaseAttributeMap* attributeMap, + Attribute* attribute); + ~ModifiableAttributeInstance(); + + Attribute* getAttribute(); + double getBaseValue(); + void setBaseValue(double baseValue); + std::unordered_set* getModifiers(int operation); + void getModifiers(std::unordered_set& result); + AttributeModifier* getModifier(eMODIFIER_ID id); + void addModifiers(std::unordered_set* modifiers); + void addModifier(AttributeModifier* modifier); + +private: + void setDirty(); + +public: + void removeModifier(AttributeModifier* modifier); + void removeModifier(eMODIFIER_ID id); + void removeModifiers(); + double getValue(); + +private: + double calculateValue(); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/RangedAttribute.cpp b/Minecraft.World/AI/Attributes/RangedAttribute.cpp new file mode 100644 index 000000000..ccbdaaad6 --- /dev/null +++ b/Minecraft.World/AI/Attributes/RangedAttribute.cpp @@ -0,0 +1,28 @@ +#include "../../Platform/stdafx.h" + +#include "RangedAttribute.h" + +RangedAttribute::RangedAttribute(eATTRIBUTE_ID id, double defaultValue, + double minValue, double maxValue) + : BaseAttribute(id, defaultValue) { + this->minValue = minValue; + this->maxValue = maxValue; + + // if (minValue > maxValue) throw new IllegalArgumentException("Minimum + // value cannot be bigger than maximum value!"); if (defaultValue < + // minValue) throw new IllegalArgumentException("Default value cannot be + // lower than minimum value!"); if (defaultValue > maxValue) throw new + // IllegalArgumentException("Default value cannot be bigger than maximum + // value!"); +} + +double RangedAttribute::getMinValue() { return minValue; } + +double RangedAttribute::getMaxValue() { return maxValue; } + +double RangedAttribute::sanitizeValue(double value) { + if (value < minValue) value = minValue; + if (value > maxValue) value = maxValue; + + return value; +} \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/RangedAttribute.h b/Minecraft.World/AI/Attributes/RangedAttribute.h new file mode 100644 index 000000000..03c3a330f --- /dev/null +++ b/Minecraft.World/AI/Attributes/RangedAttribute.h @@ -0,0 +1,21 @@ +#pragma once + +#include "BaseAttribute.h" + +class RangedAttribute : public BaseAttribute { +private: + double minValue; + double maxValue; + +public: + RangedAttribute(eATTRIBUTE_ID id, double defaultValue, double minValue, + double maxValue); + + double getMinValue(); + double getMaxValue(); + double sanitizeValue(double value); + + // 4J: Removed legacy name + // RangedAttribute *importLegacyName(const std::wstring &name); + // std::wstring getImportLegacyName(); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/ServersideAttributeMap.cpp b/Minecraft.World/AI/Attributes/ServersideAttributeMap.cpp new file mode 100644 index 000000000..9bbd1f02d --- /dev/null +++ b/Minecraft.World/AI/Attributes/ServersideAttributeMap.cpp @@ -0,0 +1,82 @@ +#include "../../Platform/stdafx.h" + +#include "Attribute.h" +#include "RangedAttribute.h" +#include "AttributeInstance.h" +#include "ModifiableAttributeInstance.h" +#include "ServersideAttributeMap.h" + +AttributeInstance* ServersideAttributeMap::getInstance(Attribute* attribute) { + return BaseAttributeMap::getInstance(attribute); +} + +AttributeInstance* ServersideAttributeMap::getInstance(eATTRIBUTE_ID id) { + AttributeInstance* result = BaseAttributeMap::getInstance(id); + + // 4J: Removed legacy name + // If we didn't find it, search by legacy name + /*if (result == NULL) + { + AUTO_VAR(it, attributesByLegacy.find(name)); + if(it != attributesByLegacy.end()) + { + result = it->second; + } + }*/ + + return result; +} + +AttributeInstance* ServersideAttributeMap::registerAttribute( + Attribute* attribute) { + AUTO_VAR(it, attributesById.find(attribute->getId())); + if (it != attributesById.end()) { + return it->second; + } + + AttributeInstance* instance = + new ModifiableAttributeInstance(this, attribute); + attributesById.insert(std::pair( + attribute->getId(), instance)); + + // 4J: Removed legacy name + // If this is a ranged attribute also add to legacy name map + /*RangedAttribute *rangedAttribute = + dynamic_cast(attribute); if (rangedAttribute != NULL && + rangedAttribute->getImportLegacyName() != L"") + { + attributesByLegacy.insert(std::pair(rangedAttribute->getImportLegacyName(), instance)); + }*/ + + return instance; +} + +void ServersideAttributeMap::onAttributeModified( + ModifiableAttributeInstance* attributeInstance) { + if (attributeInstance->getAttribute()->isClientSyncable()) { + dirtyAttributes.insert(attributeInstance); + } +} + +std::unordered_set* +ServersideAttributeMap::getDirtyAttributes() { + return &dirtyAttributes; +} + +std::unordered_set* +ServersideAttributeMap::getSyncableAttributes() { + std::unordered_set* result = + new std::unordered_set(); + std::vector atts; + getAttributes(atts); + for (int i = 0; i < atts.size(); i++) { + AttributeInstance* instance = atts.at(i); + + if (instance->getAttribute()->isClientSyncable()) { + result->insert(instance); + } + } + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/AI/Attributes/ServersideAttributeMap.h b/Minecraft.World/AI/Attributes/ServersideAttributeMap.h new file mode 100644 index 000000000..8a2706ef0 --- /dev/null +++ b/Minecraft.World/AI/Attributes/ServersideAttributeMap.h @@ -0,0 +1,24 @@ +#pragma once + +#include "BaseAttributeMap.h" + +class ServersideAttributeMap : public BaseAttributeMap { +private: + std::unordered_set dirtyAttributes; + +protected: + // 4J: Remove legacy name + // unordered_map attributesByLegacy; + +public: + // 4J-JEV: Changed from ModifiableAttributeInstance to AttributeInstance as + // they are not 'covariant' on PS4. + virtual AttributeInstance* getInstance(Attribute* attribute); + virtual AttributeInstance* getInstance(eATTRIBUTE_ID id); + + virtual AttributeInstance* registerAttribute(Attribute* attribute); + virtual void onAttributeModified( + ModifiableAttributeInstance* attributeInstance); + virtual std::unordered_set* getDirtyAttributes(); + virtual std::unordered_set* getSyncableAttributes(); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Control/BodyControl.cpp b/Minecraft.World/AI/Control/BodyControl.cpp index cfdec453f..787951c75 100644 --- a/Minecraft.World/AI/Control/BodyControl.cpp +++ b/Minecraft.World/AI/Control/BodyControl.cpp @@ -5,7 +5,7 @@ const float BodyControl::maxClampAngle = 75.0f; -BodyControl::BodyControl(Mob* mob) { +BodyControl::BodyControl(LivingEntity* mob) { this->mob = mob; timeStill = 0; diff --git a/Minecraft.World/AI/Control/BodyControl.h b/Minecraft.World/AI/Control/BodyControl.h index b9e92dd12..35981d719 100644 --- a/Minecraft.World/AI/Control/BodyControl.h +++ b/Minecraft.World/AI/Control/BodyControl.h @@ -4,13 +4,13 @@ class BodyControl : public Control { private: - Mob* mob; + LivingEntity* mob; static const float maxClampAngle; int timeStill; float lastHeadY; public: - BodyControl(Mob* mob); + BodyControl(LivingEntity* mob); void clientTick(); diff --git a/Minecraft.World/AI/Control/LookControl.cpp b/Minecraft.World/AI/Control/LookControl.cpp index e4c4e55b9..f5b7519b1 100644 --- a/Minecraft.World/AI/Control/LookControl.cpp +++ b/Minecraft.World/AI/Control/LookControl.cpp @@ -14,13 +14,14 @@ LookControl::LookControl(Mob* mob) { void LookControl::setLookAt(std::shared_ptr target, float yMax, float xMax) { - this->wantedX = target->x; - std::shared_ptr targetMob = std::dynamic_pointer_cast(target); - if (targetMob != NULL) - this->wantedY = target->y + targetMob->getHeadHeight(); + wantedX = target->x; + if (target->instanceof(eTYPE_LIVINGENTITY)) + wantedY = + target->y + + std::dynamic_pointer_cast(target)->getHeadHeight(); else - this->wantedY = (target->bb->y0 + target->bb->y1) / 2; - this->wantedZ = target->z; + wantedY = (target->bb->y0 + target->bb->y1) / 2; + wantedZ = target->z; this->yMax = yMax; this->xMax = xMax; hasWanted = true; @@ -28,9 +29,9 @@ void LookControl::setLookAt(std::shared_ptr target, float yMax, void LookControl::setLookAt(double x, double y, double z, float yMax, float xMax) { - this->wantedX = x; - this->wantedY = y; - this->wantedZ = z; + wantedX = x; + wantedY = y; + wantedZ = z; this->yMax = yMax; this->xMax = xMax; hasWanted = true; diff --git a/Minecraft.World/AI/Control/MoveControl.cpp b/Minecraft.World/AI/Control/MoveControl.cpp index 363d19eb0..3834ed6a4 100644 --- a/Minecraft.World/AI/Control/MoveControl.cpp +++ b/Minecraft.World/AI/Control/MoveControl.cpp @@ -1,6 +1,8 @@ #include "../../Platform/stdafx.h" -#include "../../Headers/net.minecraft.world.entity.ai.control.h" #include "../../Headers/net.minecraft.world.entity.h" +#include "../../Headers/net.minecraft.world.entity.ai.attributes.h" +#include "../../Headers/net.minecraft.world.entity.ai.control.h" +#include "../../Headers/net.minecraft.world.entity.monster.h" #include "../../Headers/net.minecraft.world.phys.h" #include "MoveControl.h" @@ -13,20 +15,21 @@ MoveControl::MoveControl(Mob* mob) { wantedY = mob->y; wantedZ = mob->z; - speed = 0.0f; + speedModifier = 0.0; _hasWanted = false; } bool MoveControl::hasWanted() { return _hasWanted; } -float MoveControl::getSpeed() { return speed; } +double MoveControl::getSpeedModifier() { return speedModifier; } -void MoveControl::setWantedPosition(double x, double y, double z, float speed) { +void MoveControl::setWantedPosition(double x, double y, double z, + double speedModifier) { wantedX = x; wantedY = y; wantedZ = z; - this->speed = speed; + this->speedModifier = speedModifier; _hasWanted = true; } @@ -46,7 +49,10 @@ void MoveControl::tick() { float yRotD = (float)(atan2(zd, xd) * 180 / PI) - 90; mob->yRot = rotlerp(mob->yRot, yRotD, MAX_TURN); - mob->setSpeed(speed * mob->getWalkingSpeedModifier()); + mob->setSpeed( + (float)(speedModifier * + mob->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED) + ->getValue())); if (yd > 0 && xd * xd + zd * zd < 1) mob->getJumpControl()->jump(); } diff --git a/Minecraft.World/AI/Control/MoveControl.h b/Minecraft.World/AI/Control/MoveControl.h index 17e36ff45..b497105b9 100644 --- a/Minecraft.World/AI/Control/MoveControl.h +++ b/Minecraft.World/AI/Control/MoveControl.h @@ -16,19 +16,18 @@ private: double wantedX; double wantedY; double wantedZ; - float speed; + double speedModifier; bool _hasWanted; public: MoveControl(Mob* mob); - virtual ~MoveControl() {} bool hasWanted(); - float getSpeed(); - void setWantedPosition(double x, double y, double z, float speed); + double getSpeedModifier(); + void setWantedPosition(double x, double y, double z, double speedModifier); void setSpeed(float speed); virtual void tick(); private: float rotlerp(float a, float b, float max); -}; +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/ArrowAttackGoal.cpp b/Minecraft.World/AI/Goals/ArrowAttackGoal.cpp deleted file mode 100644 index d7e2e1ecb..000000000 --- a/Minecraft.World/AI/Goals/ArrowAttackGoal.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "../../Platform/stdafx.h" -#include "../../Headers/net.minecraft.world.entity.ai.control.h" -#include "../../Headers/net.minecraft.world.entity.ai.navigation.h" -#include "../../Headers/net.minecraft.world.entity.ai.sensing.h" -#include "../../Headers/net.minecraft.world.entity.projectile.h" -#include "../../Headers/net.minecraft.world.entity.h" -#include "../../Headers/net.minecraft.world.level.h" -#include "../../Headers/net.minecraft.world.phys.h" -#include "../../Util/SoundTypes.h" -#include "ArrowAttackGoal.h" - -ArrowAttackGoal::ArrowAttackGoal(Mob* mob, float speed, int projectileType, - int attackInterval) { - // 4J Init - target = std::weak_ptr(); - attackTime = 0; - seeTime = 0; - - this->mob = mob; - this->level = mob->level; - this->speed = speed; - this->projectileType = projectileType; - this->attackInterval = attackInterval; - setRequiredControlFlags(Control::MoveControlFlag | - Control::LookControlFlag); -} - -bool ArrowAttackGoal::canUse() { - std::shared_ptr bestTarget = mob->getTarget(); - if (bestTarget == NULL) return false; - target = std::weak_ptr(bestTarget); - return true; -} - -bool ArrowAttackGoal::canContinueToUse() { - return target.lock() != NULL && - (canUse() || !mob->getNavigation()->isDone()); -} - -void ArrowAttackGoal::stop() { target = std::weak_ptr(); } - -void ArrowAttackGoal::tick() { - double attackRadiusSqr = 10 * 10; - std::shared_ptr tar = target.lock(); - double targetDistSqr = mob->distanceToSqr(tar->x, tar->bb->y0, tar->z); - bool canSee = mob->getSensing()->canSee(tar); - - if (canSee) { - ++seeTime; - } else - seeTime = 0; - - if (targetDistSqr > attackRadiusSqr || seeTime < 20) - mob->getNavigation()->moveTo(tar, speed); - else - mob->getNavigation()->stop(); - - mob->getLookControl()->setLookAt(tar, 30, 30); - - attackTime = std::max(attackTime - 1, 0); - if (attackTime > 0) return; - if (targetDistSqr > attackRadiusSqr || !canSee) return; - fireAtTarget(); - attackTime = attackInterval; -} - -void ArrowAttackGoal::fireAtTarget() { - std::shared_ptr tar = target.lock(); - if (projectileType == ArrowType) { - std::shared_ptr arrow = std::shared_ptr(new Arrow( - level, std::dynamic_pointer_cast(mob->shared_from_this()), tar, - 1.60f, 12)); - level->playSound(mob->shared_from_this(), eSoundType_RANDOM_BOW, 1.0f, - 1 / (mob->getRandom()->nextFloat() * 0.4f + 0.8f)); - level->addEntity(arrow); - } else if (projectileType == SnowballType) { - std::shared_ptr snowball = std::shared_ptr( - new Snowball(level, std::dynamic_pointer_cast( - mob->shared_from_this()))); - double xd = tar->x - mob->x; - double yd = (tar->y + tar->getHeadHeight() - 1.1f) - snowball->y; - double zd = tar->z - mob->z; - float yo = sqrt(xd * xd + zd * zd) * 0.2f; - snowball->shoot(xd, yd + yo, zd, 1.60f, 12); - - level->playSound(mob->shared_from_this(), eSoundType_RANDOM_BOW, 1.0f, - 1 / (mob->getRandom()->nextFloat() * 0.4f + 0.8f)); - level->addEntity(snowball); - } -} \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/ArrowAttackGoal.h b/Minecraft.World/AI/Goals/ArrowAttackGoal.h deleted file mode 100644 index 039447f28..000000000 --- a/Minecraft.World/AI/Goals/ArrowAttackGoal.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "Goal.h" - -class ArrowAttackGoal : public Goal { -public: - static const int ArrowType = 1; - static const int SnowballType = 2; - - Level* level; - Mob* mob; // Owner of this goal - std::weak_ptr target; - int attackTime; - float speed; - int seeTime; - int projectileType; - int attackInterval; - - ArrowAttackGoal(Mob* mob, float speed, int projectileType, - int attackInterval); - - virtual bool canUse(); - virtual bool canContinueToUse(); - virtual void stop(); - virtual void tick(); - -private: - void fireAtTarget(); - -public: - // 4J Added override to update ai elements when loading entity from - // schematics - virtual void setLevel(Level* level) { this->level = level; } -}; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/AvoidPlayerGoal.cpp b/Minecraft.World/AI/Goals/AvoidPlayerGoal.cpp index 66b3fde4f..1e2d3cb1d 100644 --- a/Minecraft.World/AI/Goals/AvoidPlayerGoal.cpp +++ b/Minecraft.World/AI/Goals/AvoidPlayerGoal.cpp @@ -10,24 +10,38 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "AvoidPlayerGoal.h" +AvoidPlayerGoalEntitySelector::AvoidPlayerGoalEntitySelector( + AvoidPlayerGoal* parent) { + m_parent = parent; +} + +bool AvoidPlayerGoalEntitySelector::matches( + std::shared_ptr entity) const { + return entity->isAlive() && m_parent->mob->getSensing()->canSee(entity); +} + AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob* mob, const std::type_info& avoidType, float maxDist, - float walkSpeed, float sprintSpeed) + double walkSpeedModifier, + double sprintSpeedModifier) : avoidType(avoidType) { this->mob = mob; // this->avoidType = avoidType; this->maxDist = maxDist; - this->walkSpeed = walkSpeed; - this->sprintSpeed = sprintSpeed; + this->walkSpeedModifier = walkSpeedModifier; + this->sprintSpeedModifier = sprintSpeedModifier; this->pathNav = mob->getNavigation(); setRequiredControlFlags(Control::MoveControlFlag); + entitySelector = new AvoidPlayerGoalEntitySelector(this); + toAvoid = std::weak_ptr(); path = NULL; } AvoidPlayerGoal::~AvoidPlayerGoal() { if (path != NULL) delete path; + delete entitySelector; } bool AvoidPlayerGoal::canUse() { @@ -40,8 +54,8 @@ bool AvoidPlayerGoal::canUse() { if (toAvoid.lock() == NULL) return false; } else { std::vector >* entities = - mob->level->getEntitiesOfClass(avoidType, - mob->bb->grow(maxDist, 3, maxDist)); + mob->level->getEntitiesOfClass( + avoidType, mob->bb->grow(maxDist, 3, maxDist), entitySelector); if (entities->empty()) { delete entities; return false; @@ -50,8 +64,6 @@ bool AvoidPlayerGoal::canUse() { delete entities; } - if (!mob->getSensing()->canSee(toAvoid.lock())) return false; - Vec3* pos = RandomPos::getPosAvoid( std::dynamic_pointer_cast(mob->shared_from_this()), 16, 7, @@ -72,7 +84,7 @@ bool AvoidPlayerGoal::canContinueToUse() { } void AvoidPlayerGoal::start() { - pathNav->moveTo(path, walkSpeed); + pathNav->moveTo(path, walkSpeedModifier); path = NULL; } @@ -80,7 +92,7 @@ void AvoidPlayerGoal::stop() { toAvoid = std::weak_ptr(); } void AvoidPlayerGoal::tick() { if (mob->distanceToSqr(toAvoid.lock()) < 7 * 7) - mob->getNavigation()->setSpeed(sprintSpeed); + mob->getNavigation()->setSpeedModifier(sprintSpeedModifier); else - mob->getNavigation()->setSpeed(walkSpeed); + mob->getNavigation()->setSpeedModifier(walkSpeedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/AvoidPlayerGoal.h b/Minecraft.World/AI/Goals/AvoidPlayerGoal.h index a790eada9..9376dd750 100644 --- a/Minecraft.World/AI/Goals/AvoidPlayerGoal.h +++ b/Minecraft.World/AI/Goals/AvoidPlayerGoal.h @@ -1,24 +1,39 @@ #pragma once #include "Goal.h" +#include "../../Entities/EntitySelector.h" class PathNavigation; class PathfinderMob; class Path; +class AvoidPlayerGoal; + +class AvoidPlayerGoalEntitySelector : public EntitySelector { +private: + AvoidPlayerGoal* m_parent; + +public: + AvoidPlayerGoalEntitySelector(AvoidPlayerGoal* parent); + bool matches(std::shared_ptr entity) const; +}; class AvoidPlayerGoal : public Goal { + friend class AvoidPlayerGoalEntitySelector; + private: PathfinderMob* mob; // Owner of this goal - float walkSpeed, sprintSpeed; + double walkSpeedModifier, sprintSpeedModifier; std::weak_ptr toAvoid; float maxDist; Path* path; PathNavigation* pathNav; const std::type_info& avoidType; + EntitySelector* entitySelector; public: AvoidPlayerGoal(PathfinderMob* mob, const std::type_info& avoidType, - float maxDist, float walkSpeed, float sprintSpeed); + float maxDist, double walkSpeedModifier, + double sprintSpeedModifier); ~AvoidPlayerGoal(); virtual bool canUse(); diff --git a/Minecraft.World/AI/Goals/BreakDoorGoal.cpp b/Minecraft.World/AI/Goals/BreakDoorGoal.cpp index 90ddd441b..26e210e86 100644 --- a/Minecraft.World/AI/Goals/BreakDoorGoal.cpp +++ b/Minecraft.World/AI/Goals/BreakDoorGoal.cpp @@ -13,6 +13,8 @@ BreakDoorGoal::BreakDoorGoal(Mob* mob) : DoorInteractGoal(mob) { bool BreakDoorGoal::canUse() { if (!DoorInteractGoal::canUse()) return false; + if (!mob->level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) + return false; return !doorTile->isOpen(mob->level, doorX, doorY, doorZ); } @@ -50,7 +52,7 @@ void BreakDoorGoal::tick() { if (breakTime == DOOR_BREAK_TIME) { if (mob->level->difficulty == Difficulty::HARD) { - mob->level->setTile(doorX, doorY, doorZ, 0); + mob->level->removeTile(doorX, doorY, doorZ); mob->level->levelEvent(LevelEvent::SOUND_ZOMBIE_DOOR_CRASH, doorX, doorY, doorZ, 0); mob->level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, doorX, diff --git a/Minecraft.World/AI/Goals/BreedGoal.cpp b/Minecraft.World/AI/Goals/BreedGoal.cpp index 24e033c81..5281598d9 100644 --- a/Minecraft.World/AI/Goals/BreedGoal.cpp +++ b/Minecraft.World/AI/Goals/BreedGoal.cpp @@ -4,18 +4,19 @@ #include "../../Headers/net.minecraft.world.entity.animal.h" #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.phys.h" +#include "../../Util/BasicTypeContainers.h" #include "BreedGoal.h" #include "../../Entities/Mobs/ExperienceOrb.h" #include "../../Stats/GenericStats.h" -BreedGoal::BreedGoal(Animal* animal, float speed) { +BreedGoal::BreedGoal(Animal* animal, double speedModifier) { partner = std::weak_ptr(); loveTime = 0; this->animal = animal; this->level = animal->level; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); } @@ -39,24 +40,27 @@ void BreedGoal::stop() { void BreedGoal::tick() { animal->getLookControl()->setLookAt(partner.lock(), 10, animal->getMaxHeadXRot()); - animal->getNavigation()->moveTo(partner.lock(), speed); + animal->getNavigation()->moveTo(partner.lock(), speedModifier); ++loveTime; - if (loveTime == 20 * 3) breed(); + if (loveTime >= 20 * 3 && animal->distanceToSqr(partner.lock()) < 3 * 3) + breed(); } std::shared_ptr BreedGoal::getFreePartner() { float r = 8; std::vector >* others = level->getEntitiesOfClass(typeid(*animal), animal->bb->grow(r, r, r)); + double dist = Double::MAX_VALUE; + std::shared_ptr partner = nullptr; for (AUTO_VAR(it, others->begin()); it != others->end(); ++it) { std::shared_ptr p = std::dynamic_pointer_cast(*it); - if (animal->canMate(p)) { - delete others; - return p; + if (animal->canMate(p) && animal->distanceToSqr(p) < dist) { + partner = p; + dist = animal->distanceToSqr(p); } } delete others; - return nullptr; + return partner; } void BreedGoal::breed() { @@ -93,7 +97,7 @@ void BreedGoal::breed() { partner.lock()->setAge(5 * 60 * 20); animal->resetLove(); partner.lock()->resetLove(); - offspring->setAge(-20 * 60 * 20); + offspring->setAge(AgableMob::BABY_START_AGE); offspring->moveTo(animal->x, animal->y, animal->z, 0, 0); offspring->setDespawnProtected(); level->addEntity(offspring); diff --git a/Minecraft.World/AI/Goals/BreedGoal.h b/Minecraft.World/AI/Goals/BreedGoal.h index 960252970..2cc5436de 100644 --- a/Minecraft.World/AI/Goals/BreedGoal.h +++ b/Minecraft.World/AI/Goals/BreedGoal.h @@ -11,10 +11,10 @@ private: Level* level; std::weak_ptr partner; int loveTime; - float speed; + double speedModifier; public: - BreedGoal(Animal* animal, float speed); + BreedGoal(Animal* animal, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/ControlledByPlayerGoal.cpp b/Minecraft.World/AI/Goals/ControlledByPlayerGoal.cpp index 0e79f23c1..8ccfee86e 100644 --- a/Minecraft.World/AI/Goals/ControlledByPlayerGoal.cpp +++ b/Minecraft.World/AI/Goals/ControlledByPlayerGoal.cpp @@ -36,9 +36,8 @@ void ControlledByPlayerGoal::stop() { } bool ControlledByPlayerGoal::canUse() { - std::shared_ptr player = - std::dynamic_pointer_cast(mob->rider.lock()); - return mob->isAlive() && player && + return mob->isAlive() && mob->rider.lock() != NULL && + mob->rider.lock()->instanceof(eTYPE_PLAYER) && (boosting || mob->canBeControlledByRider()); } @@ -119,7 +118,7 @@ void ControlledByPlayerGoal::tick() { std::shared_ptr carriedItem = player->getCarriedItem(); if (carriedItem != NULL && carriedItem->id == Item::carrotOnAStick_Id) { - carriedItem->hurt(1, player); + carriedItem->hurtAndBreak(1, player); if (carriedItem->count == 0) { std::shared_ptr replacement = @@ -135,6 +134,12 @@ void ControlledByPlayerGoal::tick() { mob->travel(0, moveSpeed); } +bool ControlledByPlayerGoal::isNoJumpTile(int tile) { + return Tile::tiles[tile] != NULL && + (Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_STAIRS || + (dynamic_cast(Tile::tiles[tile]) != NULL)); +} + bool ControlledByPlayerGoal::isBoosting() { return boosting; } void ControlledByPlayerGoal::boost() { diff --git a/Minecraft.World/AI/Goals/ControlledByPlayerGoal.h b/Minecraft.World/AI/Goals/ControlledByPlayerGoal.h index 707ec0c3f..3d4bf4865 100644 --- a/Minecraft.World/AI/Goals/ControlledByPlayerGoal.h +++ b/Minecraft.World/AI/Goals/ControlledByPlayerGoal.h @@ -1,7 +1,7 @@ #pragma once #include "Goal.h" -#include "../../Util/SharedConstants.h" +#include "../Minecraft.World/SharedConstants.h" class Mob; @@ -26,7 +26,12 @@ public: void stop(); bool canUse(); void tick(); + +private: + bool isNoJumpTile(int tile); + +public: bool isBoosting(); void boost(); bool canBoost(); -}; +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/DefendVillageTargetGoal.cpp b/Minecraft.World/AI/Goals/DefendVillageTargetGoal.cpp index d7ebc3c3b..3c7c7180b 100644 --- a/Minecraft.World/AI/Goals/DefendVillageTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/DefendVillageTargetGoal.cpp @@ -4,7 +4,7 @@ #include "DefendVillageTargetGoal.h" DefendVillageTargetGoal::DefendVillageTargetGoal(VillagerGolem* golem) - : TargetGoal(golem, 16, false, true) { + : TargetGoal(golem, false, true) { this->golem = golem; setRequiredControlFlags(TargetGoal::TargetFlag); } @@ -12,9 +12,21 @@ DefendVillageTargetGoal::DefendVillageTargetGoal(VillagerGolem* golem) bool DefendVillageTargetGoal::canUse() { std::shared_ptr village = golem->getVillage(); if (village == NULL) return false; - potentialTarget = std::weak_ptr(village->getClosestAggressor( - std::dynamic_pointer_cast(golem->shared_from_this()))); - return canAttack(potentialTarget.lock(), false); + potentialTarget = std::weak_ptr(village->getClosestAggressor( + std::dynamic_pointer_cast(golem->shared_from_this()))); + std::shared_ptr potTarget = potentialTarget.lock(); + if (!canAttack(potTarget, false)) { + // look for bad players + if (mob->getRandom()->nextInt(20) == 0) { + potentialTarget = village->getClosestBadStandingPlayer( + std::dynamic_pointer_cast( + golem->shared_from_this())); + return canAttack(potTarget, false); + } + return false; + } else { + return true; + } } void DefendVillageTargetGoal::start() { diff --git a/Minecraft.World/AI/Goals/DefendVillageTargetGoal.h b/Minecraft.World/AI/Goals/DefendVillageTargetGoal.h index c20257cc3..ac0b4758a 100644 --- a/Minecraft.World/AI/Goals/DefendVillageTargetGoal.h +++ b/Minecraft.World/AI/Goals/DefendVillageTargetGoal.h @@ -7,7 +7,7 @@ class VillagerGolem; class DefendVillageTargetGoal : public TargetGoal { private: VillagerGolem* golem; // Owner of this goal - std::weak_ptr potentialTarget; + std::weak_ptr potentialTarget; public: DefendVillageTargetGoal(VillagerGolem* golem); diff --git a/Minecraft.World/AI/Goals/EatTileGoal.cpp b/Minecraft.World/AI/Goals/EatTileGoal.cpp index ceebd3706..3354ee702 100644 --- a/Minecraft.World/AI/Goals/EatTileGoal.cpp +++ b/Minecraft.World/AI/Goals/EatTileGoal.cpp @@ -10,7 +10,7 @@ EatTileGoal::EatTileGoal(Mob* mob) { eatAnimationTick = 0; this->mob = mob; - this->level = mob->level; + level = mob->level; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag | Control::JumpControlFlag); @@ -51,15 +51,13 @@ void EatTileGoal::tick() { int zz = Mth::floor(mob->z); if (level->getTile(xx, yy, zz) == Tile::tallgrass_Id) { - level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy, zz, - Tile::tallgrass_Id + - (TallGrass::TALL_GRASS << Tile::TILE_NUM_SHIFT)); - level->setTile(xx, yy, zz, 0); + level->destroyTile(xx, yy, zz, false); mob->ate(); } else if (level->getTile(xx, yy - 1, zz) == Tile::grass_Id) { level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy - 1, zz, Tile::grass_Id); - level->setTile(xx, yy - 1, zz, Tile::dirt_Id); + level->setTileAndData(xx, yy - 1, zz, Tile::dirt_Id, 0, + Tile::UPDATE_CLIENTS); mob->ate(); } } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/FleeSunGoal.cpp b/Minecraft.World/AI/Goals/FleeSunGoal.cpp index 4fb2eedce..70a77fe77 100644 --- a/Minecraft.World/AI/Goals/FleeSunGoal.cpp +++ b/Minecraft.World/AI/Goals/FleeSunGoal.cpp @@ -6,9 +6,9 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "FleeSunGoal.h" -FleeSunGoal::FleeSunGoal(PathfinderMob* mob, float speed) { +FleeSunGoal::FleeSunGoal(PathfinderMob* mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->level = mob->level; setRequiredControlFlags(Control::MoveControlFlag); } @@ -31,7 +31,7 @@ bool FleeSunGoal::canUse() { bool FleeSunGoal::canContinueToUse() { return !mob->getNavigation()->isDone(); } void FleeSunGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } Vec3* FleeSunGoal::getHidePos() { diff --git a/Minecraft.World/AI/Goals/FleeSunGoal.h b/Minecraft.World/AI/Goals/FleeSunGoal.h index cfec75fe9..cdd6f8612 100644 --- a/Minecraft.World/AI/Goals/FleeSunGoal.h +++ b/Minecraft.World/AI/Goals/FleeSunGoal.h @@ -6,11 +6,11 @@ class FleeSunGoal : public Goal { private: PathfinderMob* mob; // Owner of this goal double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; Level* level; public: - FleeSunGoal(PathfinderMob* mob, float speed); + FleeSunGoal(PathfinderMob* mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/FollowOwnerGoal.cpp b/Minecraft.World/AI/Goals/FollowOwnerGoal.cpp index 1bfd657c4..928f7e8ef 100644 --- a/Minecraft.World/AI/Goals/FollowOwnerGoal.cpp +++ b/Minecraft.World/AI/Goals/FollowOwnerGoal.cpp @@ -7,16 +7,16 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "FollowOwnerGoal.h" -FollowOwnerGoal::FollowOwnerGoal(TamableAnimal* tamable, float speed, +FollowOwnerGoal::FollowOwnerGoal(TamableAnimal* tamable, double speedModifier, float startDistance, float stopDistance) { owner = std::weak_ptr(); timeToRecalcPath = 0; oldAvoidWater = false; this->tamable = tamable; - this->level = tamable->level; - this->speed = speed; - this->navigation = tamable->getNavigation(); + level = tamable->level; + this->speedModifier = speedModifier; + navigation = tamable->getNavigation(); this->startDistance = startDistance; this->stopDistance = stopDistance; setRequiredControlFlags(Control::MoveControlFlag | @@ -24,12 +24,13 @@ FollowOwnerGoal::FollowOwnerGoal(TamableAnimal* tamable, float speed, } bool FollowOwnerGoal::canUse() { - std::shared_ptr owner = tamable->getOwner(); + std::shared_ptr owner = + std::dynamic_pointer_cast(tamable->getOwner()); if (owner == NULL) return false; if (tamable->isSitting()) return false; if (tamable->distanceToSqr(owner) < startDistance * startDistance) return false; - this->owner = std::weak_ptr(owner); + this->owner = std::weak_ptr(owner); return true; } @@ -59,7 +60,8 @@ void FollowOwnerGoal::tick() { if (--timeToRecalcPath > 0) return; timeToRecalcPath = 10; - if (navigation->moveTo(owner.lock(), speed)) return; + if (navigation->moveTo(owner.lock(), speedModifier)) return; + if (tamable->isLeashed()) return; if (tamable->distanceToSqr(owner.lock()) < TeleportDistance * TeleportDistance) return; diff --git a/Minecraft.World/AI/Goals/FollowOwnerGoal.h b/Minecraft.World/AI/Goals/FollowOwnerGoal.h index 5ec293492..4ae89fabf 100644 --- a/Minecraft.World/AI/Goals/FollowOwnerGoal.h +++ b/Minecraft.World/AI/Goals/FollowOwnerGoal.h @@ -11,17 +11,17 @@ public: private: TamableAnimal* tamable; // Owner of this goal - std::weak_ptr owner; + std::weak_ptr owner; Level* level; - float speed; + double speedModifier; PathNavigation* navigation; int timeToRecalcPath; float stopDistance, startDistance; bool oldAvoidWater; public: - FollowOwnerGoal(TamableAnimal* tamable, float speed, float startDistance, - float stopDistance); + FollowOwnerGoal(TamableAnimal* tamable, double speedModifier, + float startDistance, float stopDistance); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/FollowParentGoal.cpp b/Minecraft.World/AI/Goals/FollowParentGoal.cpp index 56aab1871..1bbe808a6 100644 --- a/Minecraft.World/AI/Goals/FollowParentGoal.cpp +++ b/Minecraft.World/AI/Goals/FollowParentGoal.cpp @@ -6,11 +6,11 @@ #include "../../Util/BasicTypeContainers.h" #include "FollowParentGoal.h" -FollowParentGoal::FollowParentGoal(Animal* animal, float speed) { +FollowParentGoal::FollowParentGoal(Animal* animal, double speedModifier) { timeToRecalcPath = 0; this->animal = animal; - this->speed = speed; + this->speedModifier = speedModifier; } bool FollowParentGoal::canUse() { @@ -52,5 +52,5 @@ void FollowParentGoal::stop() { parent = std::weak_ptr(); } void FollowParentGoal::tick() { if (--timeToRecalcPath > 0) return; timeToRecalcPath = 10; - animal->getNavigation()->moveTo(parent.lock(), speed); + animal->getNavigation()->moveTo(parent.lock(), speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/FollowParentGoal.h b/Minecraft.World/AI/Goals/FollowParentGoal.h index 3295fc070..e2a0700e9 100644 --- a/Minecraft.World/AI/Goals/FollowParentGoal.h +++ b/Minecraft.World/AI/Goals/FollowParentGoal.h @@ -8,11 +8,11 @@ class FollowParentGoal : public Goal { private: Animal* animal; // Owner of this goal std::weak_ptr parent; - float speed; + double speedModifier; int timeToRecalcPath; public: - FollowParentGoal(Animal* animal, float speed); + FollowParentGoal(Animal* animal, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/GoalSelector.cpp b/Minecraft.World/AI/Goals/GoalSelector.cpp index 738227020..ac5141b38 100644 --- a/Minecraft.World/AI/Goals/GoalSelector.cpp +++ b/Minecraft.World/AI/Goals/GoalSelector.cpp @@ -28,6 +28,27 @@ void GoalSelector::addGoal( goals.push_back(new InternalGoal(prio, goal, canDeletePointer)); } +void GoalSelector::removeGoal(Goal* toRemove) { + for (AUTO_VAR(it, goals.begin()); it != goals.end();) { + InternalGoal* ig = *it; + Goal* goal = ig->goal; + + if (goal == toRemove) { + AUTO_VAR(it2, find(usingGoals.begin(), usingGoals.end(), ig)); + if (it2 != usingGoals.end()) { + goal->stop(); + usingGoals.erase(it2); + } + + if (ig->canDeletePointer) delete ig->goal; + delete ig; + it = goals.erase(it); + } else { + ++it; + } + } +} + void GoalSelector::tick() { std::vector toStart; diff --git a/Minecraft.World/AI/Goals/GoalSelector.h b/Minecraft.World/AI/Goals/GoalSelector.h index aeefe1a70..cfb21355d 100644 --- a/Minecraft.World/AI/Goals/GoalSelector.h +++ b/Minecraft.World/AI/Goals/GoalSelector.h @@ -26,6 +26,7 @@ public: // 4J Added canDelete param void addGoal(int prio, Goal* goal, bool canDeletePointer = true); + void removeGoal(Goal* toRemove); void tick(); std::vector* getRunningGoals(); diff --git a/Minecraft.World/AI/Goals/HurtByTargetGoal.cpp b/Minecraft.World/AI/Goals/HurtByTargetGoal.cpp index 2f0d3b05d..7bee32298 100644 --- a/Minecraft.World/AI/Goals/HurtByTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/HurtByTargetGoal.cpp @@ -4,41 +4,40 @@ #include "../../Headers/net.minecraft.world.level.h" #include "HurtByTargetGoal.h" -HurtByTargetGoal::HurtByTargetGoal(Mob* mob, bool alertSameType) - : TargetGoal(mob, 16, false) { +HurtByTargetGoal::HurtByTargetGoal(PathfinderMob* mob, bool alertSameType) + : TargetGoal(mob, false) { this->alertSameType = alertSameType; setRequiredControlFlags(TargetGoal::TargetFlag); + timestamp = 0; } bool HurtByTargetGoal::canUse() { - return canAttack(mob->getLastHurtByMob(), false); + int ts = mob->getLastHurtByMobTimestamp(); + return ts != timestamp && canAttack(mob->getLastHurtByMob(), false); } void HurtByTargetGoal::start() { mob->setTarget(mob->getLastHurtByMob()); - oldHurtByMob = mob->getLastHurtByMob(); + timestamp = mob->getLastHurtByMobTimestamp(); if (alertSameType) { + double within = getFollowDistance(); std::vector >* nearby = mob->level->getEntitiesOfClass( typeid(*mob), AABB::newTemp(mob->x, mob->y, mob->z, mob->x + 1, mob->y + 1, mob->z + 1) ->grow(within, 4, within)); for (AUTO_VAR(it, nearby->begin()); it != nearby->end(); ++it) { - std::shared_ptr other = std::dynamic_pointer_cast(*it); + std::shared_ptr other = + std::dynamic_pointer_cast(*it); if (this->mob->shared_from_this() == other) continue; if (other->getTarget() != NULL) continue; + if (other->isAlliedTo(mob->getLastHurtByMob())) + continue; // don't target allies other->setTarget(mob->getLastHurtByMob()); } delete nearby; } TargetGoal::start(); -} - -void HurtByTargetGoal::tick() { - if (mob->getLastHurtByMob() != NULL && - mob->getLastHurtByMob() != oldHurtByMob) { - this->start(); - } -} +} \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/HurtByTargetGoal.h b/Minecraft.World/AI/Goals/HurtByTargetGoal.h index 9560728bc..a58baa11f 100644 --- a/Minecraft.World/AI/Goals/HurtByTargetGoal.h +++ b/Minecraft.World/AI/Goals/HurtByTargetGoal.h @@ -5,12 +5,11 @@ class HurtByTargetGoal : public TargetGoal { private: bool alertSameType; - std::shared_ptr oldHurtByMob; + int timestamp; public: - HurtByTargetGoal(Mob* mob, bool alertSameType); + HurtByTargetGoal(PathfinderMob* mob, bool alertSameType); bool canUse(); void start(); - void tick(); }; diff --git a/Minecraft.World/AI/Goals/LeapAtTargetGoal.cpp b/Minecraft.World/AI/Goals/LeapAtTargetGoal.cpp index f8b96ae35..9779984dd 100644 --- a/Minecraft.World/AI/Goals/LeapAtTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/LeapAtTargetGoal.cpp @@ -4,7 +4,7 @@ #include "LeapAtTargetGoal.h" LeapAtTargetGoal::LeapAtTargetGoal(Mob* mob, float yd) { - target = std::weak_ptr(); + target = std::weak_ptr(); this->mob = mob; this->yd = yd; @@ -13,7 +13,7 @@ LeapAtTargetGoal::LeapAtTargetGoal(Mob* mob, float yd) { } bool LeapAtTargetGoal::canUse() { - target = std::weak_ptr(mob->getTarget()); + target = std::weak_ptr(mob->getTarget()); if (target.lock() == NULL) return false; double d = mob->distanceToSqr(target.lock()); if (d < 2 * 2 || d > 4 * 4) return false; diff --git a/Minecraft.World/AI/Goals/LeapAtTargetGoal.h b/Minecraft.World/AI/Goals/LeapAtTargetGoal.h index 3f5c49f61..88bdeddc2 100644 --- a/Minecraft.World/AI/Goals/LeapAtTargetGoal.h +++ b/Minecraft.World/AI/Goals/LeapAtTargetGoal.h @@ -5,7 +5,7 @@ class LeapAtTargetGoal : public Goal { private: Mob* mob; // Owner of this goal - std::weak_ptr target; + std::weak_ptr target; float yd; public: diff --git a/Minecraft.World/AI/Goals/LookAtPlayerGoal.cpp b/Minecraft.World/AI/Goals/LookAtPlayerGoal.cpp index d6d1b4d0f..631362809 100644 --- a/Minecraft.World/AI/Goals/LookAtPlayerGoal.cpp +++ b/Minecraft.World/AI/Goals/LookAtPlayerGoal.cpp @@ -10,7 +10,7 @@ LookAtPlayerGoal::LookAtPlayerGoal(Mob* mob, const std::type_info& lookAtType, : lookAtType(lookAtType) { this->mob = mob; this->lookDistance = lookDistance; - this->probability = 0.02f; + probability = 0.02f; setRequiredControlFlags(Control::LookControlFlag); lookTime = 0; @@ -29,13 +29,18 @@ LookAtPlayerGoal::LookAtPlayerGoal(Mob* mob, const std::type_info& lookAtType, bool LookAtPlayerGoal::canUse() { if (mob->getRandom()->nextFloat() >= probability) return false; - if (lookAtType == typeid(Player)) + + if (mob->getTarget() != NULL) { + lookAt = mob->getTarget(); + } + if (lookAtType == typeid(Player)) { lookAt = mob->level->getNearestPlayer(mob->shared_from_this(), lookDistance); - else + } else { lookAt = std::weak_ptr(mob->level->getClosestEntityOfClass( lookAtType, mob->bb->grow(lookDistance, 3, lookDistance), mob->shared_from_this())); + } return lookAt.lock() != NULL; } diff --git a/Minecraft.World/AI/Goals/MakeLoveGoal.cpp b/Minecraft.World/AI/Goals/MakeLoveGoal.cpp index afc7c40c5..733036801 100644 --- a/Minecraft.World/AI/Goals/MakeLoveGoal.cpp +++ b/Minecraft.World/AI/Goals/MakeLoveGoal.cpp @@ -76,6 +76,10 @@ bool MakeLoveGoal::villageNeedsMoreVillagers() { std::shared_ptr _village = village.lock(); if (_village == NULL) return false; + if (!_village->isBreedTimerOk()) { + return false; + } + int idealSize = (int)((float)_village->getDoorCount() * 0.35); // System.out.println("idealSize: " + idealSize + " pop: " + // village.getPopulationSize()); @@ -90,11 +94,9 @@ void MakeLoveGoal::breed() { villager->setAge(5 * 60 * 20); // 4J - added limit to number of animals that can be bred if (level->canCreateMore(eTYPE_VILLAGER, Level::eSpawnType_Breed)) { - std::shared_ptr child = - std::shared_ptr(new Villager(level)); + std::shared_ptr child = std::dynamic_pointer_cast( + villager->getBreedOffspring(partner.lock())); child->setAge(-20 * 60 * 20); - child->setProfession( - villager->getRandom()->nextInt(Villager::PROFESSION_MAX)); child->moveTo(villager->x, villager->y, villager->z, 0, 0); level->addEntity(child); level->broadcastEntityEvent(child, EntityEvent::LOVE_HEARTS); diff --git a/Minecraft.World/AI/Goals/MeleeAttackGoal.cpp b/Minecraft.World/AI/Goals/MeleeAttackGoal.cpp index 93b7d0fe4..306cf4c89 100644 --- a/Minecraft.World/AI/Goals/MeleeAttackGoal.cpp +++ b/Minecraft.World/AI/Goals/MeleeAttackGoal.cpp @@ -7,13 +7,13 @@ #include "../../Headers/net.minecraft.world.entity.ai.sensing.h" #include "../../Headers/net.minecraft.world.phys.h" #include "MeleeAttackGoal.h" -#include "../Navigation/Path.h" -void MeleeAttackGoal::_init(Mob* mob, float speed, bool trackTarget) { +void MeleeAttackGoal::_init(PathfinderMob* mob, double speedModifier, + bool trackTarget) { this->attackType = eTYPE_NOTSET; this->mob = mob; - this->level = mob->level; - this->speed = speed; + level = mob->level; + this->speedModifier = speedModifier; this->trackTarget = trackTarget; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); @@ -23,14 +23,15 @@ void MeleeAttackGoal::_init(Mob* mob, float speed, bool trackTarget) { timeToRecalcPath = 0; } -MeleeAttackGoal::MeleeAttackGoal(Mob* mob, eINSTANCEOF attackType, float speed, - bool trackTarget) { - _init(mob, speed, trackTarget); +MeleeAttackGoal::MeleeAttackGoal(PathfinderMob* mob, eINSTANCEOF attackType, + double speedModifier, bool trackTarget) { + _init(mob, speedModifier, trackTarget); this->attackType = attackType; } -MeleeAttackGoal::MeleeAttackGoal(Mob* mob, float speed, bool trackTarget) { - _init(mob, speed, trackTarget); +MeleeAttackGoal::MeleeAttackGoal(PathfinderMob* mob, double speedModifier, + bool trackTarget) { + _init(mob, speedModifier, trackTarget); } MeleeAttackGoal::~MeleeAttackGoal() { @@ -38,57 +39,53 @@ MeleeAttackGoal::~MeleeAttackGoal() { } bool MeleeAttackGoal::canUse() { - std::shared_ptr bestTarget = mob->getTarget(); - if (bestTarget == NULL) return false; - if (!bestTarget->isAlive()) return false; - if (attackType != eTYPE_NOTSET && - (attackType & bestTarget->GetType()) != attackType) - return false; - target = std::weak_ptr(bestTarget); + std::shared_ptr target = mob->getTarget(); + if (target == NULL) return false; + if (!target->isAlive()) return false; + if (attackType != NULL && !target->instanceof(attackType)) return false; delete path; - path = mob->getNavigation()->createPath(target.lock()); + path = mob->getNavigation()->createPath(target); return path != NULL; } bool MeleeAttackGoal::canContinueToUse() { - std::shared_ptr bestTarget = mob->getTarget(); - if (bestTarget == NULL) return false; - if (target.lock() == NULL || !target.lock()->isAlive()) return false; + std::shared_ptr target = mob->getTarget(); + if (target == NULL) return false; + if (!target->isAlive()) return false; if (!trackTarget) return !mob->getNavigation()->isDone(); - if (!mob->isWithinRestriction(Mth::floor(target.lock()->x), - Mth::floor(target.lock()->y), - Mth::floor(target.lock()->z))) + if (!mob->isWithinRestriction(Mth::floor(target->x), Mth::floor(target->y), + Mth::floor(target->z))) return false; return true; } void MeleeAttackGoal::start() { - mob->getNavigation()->moveTo(path, speed); + mob->getNavigation()->moveTo(path, speedModifier); path = NULL; timeToRecalcPath = 0; } -void MeleeAttackGoal::stop() { - target = std::weak_ptr(); - mob->getNavigation()->stop(); -} +void MeleeAttackGoal::stop() { mob->getNavigation()->stop(); } void MeleeAttackGoal::tick() { - mob->getLookControl()->setLookAt(target.lock(), 30, 30); - if (trackTarget || mob->getSensing()->canSee(target.lock())) { + std::shared_ptr target = mob->getTarget(); + mob->getLookControl()->setLookAt(target, 30, 30); + if (trackTarget || mob->getSensing()->canSee(target)) { if (--timeToRecalcPath <= 0) { timeToRecalcPath = 4 + mob->getRandom()->nextInt(7); - mob->getNavigation()->moveTo(target.lock(), speed); + mob->getNavigation()->moveTo(target, speedModifier); } } attackTime = std::max(attackTime - 1, 0); - double meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2); - if (mob->distanceToSqr(target.lock()->x, target.lock()->bb->y0, - target.lock()->z) > meleeRadiusSqr) + double meleeRadiusSqr = + (mob->bbWidth * 2) * (mob->bbWidth * 2) + target->bbWidth; + if (mob->distanceToSqr(target->x, target->bb->y0, target->z) > + meleeRadiusSqr) return; if (attackTime > 0) return; attackTime = 20; - mob->doHurtTarget(target.lock()); + if (mob->getCarriedItem() != NULL) mob->swing(); + mob->doHurtTarget(target); } diff --git a/Minecraft.World/AI/Goals/MeleeAttackGoal.h b/Minecraft.World/AI/Goals/MeleeAttackGoal.h index ed97ecacb..8a5a4a0c6 100644 --- a/Minecraft.World/AI/Goals/MeleeAttackGoal.h +++ b/Minecraft.World/AI/Goals/MeleeAttackGoal.h @@ -3,28 +3,26 @@ #include "Goal.h" class Level; -class Mob; +class PathfinderMob; class Path; class MeleeAttackGoal : public Goal { private: Level* level; - Mob* mob; // Owner of this goal - std::weak_ptr target; - + PathfinderMob* mob; // Owner of this goal int attackTime; - float speed; + double speedModifier; bool trackTarget; Path* path; eINSTANCEOF attackType; int timeToRecalcPath; - void _init(Mob* mob, float speed, bool trackTarget); + void _init(PathfinderMob* mob, double speedModifier, bool trackTarget); public: - MeleeAttackGoal(Mob* mob, eINSTANCEOF attackType, float speed, - bool trackTarget); - MeleeAttackGoal(Mob* mob, float speed, bool trackTarget); + MeleeAttackGoal(PathfinderMob* mob, eINSTANCEOF attackType, + double speedModifier, bool trackTarget); + MeleeAttackGoal(PathfinderMob* mob, double speedModifier, bool trackTarget); ~MeleeAttackGoal(); virtual bool canUse(); diff --git a/Minecraft.World/AI/Goals/MoveIndoorsGoal.cpp b/Minecraft.World/AI/Goals/MoveIndoorsGoal.cpp index b0f83e6d2..db570665d 100644 --- a/Minecraft.World/AI/Goals/MoveIndoorsGoal.cpp +++ b/Minecraft.World/AI/Goals/MoveIndoorsGoal.cpp @@ -51,11 +51,11 @@ void MoveIndoorsGoal::start() { _doorInfo->getIndoorY(), _doorInfo->getIndoorZ() + 0.5)); if (pos != NULL) - mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, 0.3f); + mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, 1.0f); } else mob->getNavigation()->moveTo(_doorInfo->getIndoorX() + 0.5, _doorInfo->getIndoorY(), - _doorInfo->getIndoorZ() + 0.5, 0.3f); + _doorInfo->getIndoorZ() + 0.5, 1.0f); } void MoveIndoorsGoal::stop() { diff --git a/Minecraft.World/AI/Goals/MoveThroughVillageGoal.cpp b/Minecraft.World/AI/Goals/MoveThroughVillageGoal.cpp index 1539287e5..1ef14e1ed 100644 --- a/Minecraft.World/AI/Goals/MoveThroughVillageGoal.cpp +++ b/Minecraft.World/AI/Goals/MoveThroughVillageGoal.cpp @@ -9,13 +9,14 @@ #include "MoveThroughVillageGoal.h" #include "../Navigation/Path.h" -MoveThroughVillageGoal::MoveThroughVillageGoal(PathfinderMob* mob, float speed, +MoveThroughVillageGoal::MoveThroughVillageGoal(PathfinderMob* mob, + double speedModifier, bool onlyAtNight) { path = NULL; doorInfo = std::weak_ptr(); this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->onlyAtNight = onlyAtNight; setRequiredControlFlags(Control::MoveControlFlag); } @@ -68,7 +69,7 @@ bool MoveThroughVillageGoal::canContinueToUse() { } void MoveThroughVillageGoal::start() { - mob->getNavigation()->moveTo(path, speed); + mob->getNavigation()->moveTo(path, speedModifier); path = NULL; } diff --git a/Minecraft.World/AI/Goals/MoveThroughVillageGoal.h b/Minecraft.World/AI/Goals/MoveThroughVillageGoal.h index 315af343c..aaa946cf6 100644 --- a/Minecraft.World/AI/Goals/MoveThroughVillageGoal.h +++ b/Minecraft.World/AI/Goals/MoveThroughVillageGoal.h @@ -9,14 +9,15 @@ class DoorInfo; class MoveThroughVillageGoal : public Goal { private: PathfinderMob* mob; - float speed; + double speedModifier; Path* path; std::weak_ptr doorInfo; bool onlyAtNight; std::vector > visited; public: - MoveThroughVillageGoal(PathfinderMob* mob, float speed, bool onlyAtNight); + MoveThroughVillageGoal(PathfinderMob* mob, double speedModifier, + bool onlyAtNight); ~MoveThroughVillageGoal(); virtual bool canUse(); diff --git a/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.cpp b/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.cpp index 2f9e99bfe..b8c2f9de6 100644 --- a/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.cpp +++ b/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.cpp @@ -7,11 +7,11 @@ #include "MoveTowardsRestrictionGoal.h" MoveTowardsRestrictionGoal::MoveTowardsRestrictionGoal(PathfinderMob* mob, - float speed) { + double speedModifier) { wantedX = wantedY = wantedZ = 0.0; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } @@ -33,5 +33,5 @@ bool MoveTowardsRestrictionGoal::canContinueToUse() { } void MoveTowardsRestrictionGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.h b/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.h index f1a8d39cb..c1922f491 100644 --- a/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.h +++ b/Minecraft.World/AI/Goals/MoveTowardsRestrictionGoal.h @@ -6,10 +6,10 @@ class MoveTowardsRestrictionGoal : public Goal { private: PathfinderMob* mob; double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; public: - MoveTowardsRestrictionGoal(PathfinderMob* mob, float speed); + MoveTowardsRestrictionGoal(PathfinderMob* mob, double speedModifier); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.cpp b/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.cpp index c5a180300..d00147b38 100644 --- a/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.cpp @@ -6,16 +6,17 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "MoveTowardsTargetGoal.h" -MoveTowardsTargetGoal::MoveTowardsTargetGoal(PathfinderMob* mob, float speed, +MoveTowardsTargetGoal::MoveTowardsTargetGoal(PathfinderMob* mob, + double speedModifier, float within) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->within = within; setRequiredControlFlags(Control::MoveControlFlag); } bool MoveTowardsTargetGoal::canUse() { - target = std::weak_ptr(mob->getTarget()); + target = std::weak_ptr(mob->getTarget()); if (target.lock() == NULL) return false; if (target.lock()->distanceToSqr(mob->shared_from_this()) > within * within) return false; @@ -39,5 +40,5 @@ bool MoveTowardsTargetGoal::canContinueToUse() { void MoveTowardsTargetGoal::stop() { target = std::weak_ptr(); } void MoveTowardsTargetGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.h b/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.h index f2d00c80d..7f08cfdaf 100644 --- a/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.h +++ b/Minecraft.World/AI/Goals/MoveTowardsTargetGoal.h @@ -5,12 +5,14 @@ class MoveTowardsTargetGoal : public Goal { private: PathfinderMob* mob; - std::weak_ptr target; + std::weak_ptr target; double wantedX, wantedY, wantedZ; - float speed, within; + double speedModifier; + float within; public: - MoveTowardsTargetGoal(PathfinderMob* mob, float speed, float within); + MoveTowardsTargetGoal(PathfinderMob* mob, double speedModifier, + float within); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.cpp b/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.cpp index 06bc41b98..bdb2d72e2 100644 --- a/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.cpp @@ -4,6 +4,21 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "NearestAttackableTargetGoal.h" +SubselectEntitySelector::SubselectEntitySelector( + NearestAttackableTargetGoal* parent, EntitySelector* subselector) { + m_parent = parent; + m_subselector = subselector; +} + +SubselectEntitySelector::~SubselectEntitySelector() { delete m_subselector; } + +bool SubselectEntitySelector::matches(std::shared_ptr entity) const { + if (!entity->instanceof(eTYPE_LIVINGENTITY)) return false; + if (m_subselector != NULL && !m_subselector->matches(entity)) return false; + return m_parent->canAttack(std::dynamic_pointer_cast(entity), + false); +} + NearestAttackableTargetGoal::DistComp::DistComp(Entity* source) { this->source = source; } @@ -19,46 +34,41 @@ bool NearestAttackableTargetGoal::DistComp::operator()( } NearestAttackableTargetGoal::NearestAttackableTargetGoal( - Mob* mob, const std::type_info& targetType, float within, - int randomInterval, bool mustSee, bool mustReach /*= false*/) - : TargetGoal(mob, within, mustSee, mustReach), targetType(targetType) { - // this->targetType = targetType; - this->within = within; + PathfinderMob* mob, const std::type_info& targetType, int randomInterval, + bool mustSee, bool mustReach /*= false*/, + EntitySelector* entitySelector /* =NULL */) + : TargetGoal(mob, mustSee, mustReach), targetType(targetType) { this->randomInterval = randomInterval; this->distComp = new DistComp(mob); setRequiredControlFlags(TargetGoal::TargetFlag); + + this->selector = new SubselectEntitySelector(this, entitySelector); } -NearestAttackableTargetGoal::~NearestAttackableTargetGoal() { delete distComp; } +NearestAttackableTargetGoal::~NearestAttackableTargetGoal() { + delete distComp; + delete selector; +} bool NearestAttackableTargetGoal::canUse() { if (randomInterval > 0 && mob->getRandom()->nextInt(randomInterval) != 0) return false; - if (targetType == typeid(Player)) { - std::shared_ptr potentialTarget = - mob->level->getNearestAttackablePlayer(mob->shared_from_this(), - within); - if (canAttack(potentialTarget, false)) { - target = std::weak_ptr(potentialTarget); - return true; - } - } else { - std::vector >* entities = - mob->level->getEntitiesOfClass(targetType, - mob->bb->grow(within, 4, within)); - // Collections.sort(entities, distComp); + double within = getFollowDistance(); + + std::vector >* entities = + mob->level->getEntitiesOfClass( + targetType, mob->bb->grow(within, 4, within), selector); + + bool result = false; + if (entities != NULL && !entities->empty()) { std::sort(entities->begin(), entities->end(), *distComp); - for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { - std::shared_ptr potTarget = - std::dynamic_pointer_cast(*it); - if (canAttack(potTarget, false)) { - target = std::weak_ptr(potTarget); - return true; - } - } - delete entities; + target = std::weak_ptr( + std::dynamic_pointer_cast(entities->at(0))); + result = true; } - return false; + + delete entities; + return result; } void NearestAttackableTargetGoal::start() { diff --git a/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.h b/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.h index fec8e5569..d7e55b85c 100644 --- a/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.h +++ b/Minecraft.World/AI/Goals/NearestAttackableTargetGoal.h @@ -1,8 +1,26 @@ #pragma once #include "TargetGoal.h" +#include "../../Entities/EntitySelector.h" + +class NearestAttackableTargetGoal; + +// Anonymous class from NearestAttackableTargetGoal +class SubselectEntitySelector : public EntitySelector { +private: + EntitySelector* m_subselector; + NearestAttackableTargetGoal* m_parent; + +public: + SubselectEntitySelector(NearestAttackableTargetGoal* parent, + EntitySelector* subselector); + ~SubselectEntitySelector(); + bool matches(std::shared_ptr entity) const; +}; class NearestAttackableTargetGoal : public TargetGoal { + friend class SubselectEntitySelector; + public: class DistComp { private: @@ -15,21 +33,19 @@ public: }; private: - std::weak_ptr target; const std::type_info& targetType; int randomInterval; DistComp* distComp; + EntitySelector* selector; + std::weak_ptr target; public: - // public NearestAttackableTargetGoal(Mob mob, const std::type_info& - // targetType, float within, int randomInterval, bool mustSee) - //{ - // this(mob, targetType, within, randomInterval, mustSee, false); - // } + NearestAttackableTargetGoal(PathfinderMob* mob, + const std::type_info& targetType, + int randomInterval, bool mustSee, + bool mustReach = false, + EntitySelector* entitySelector = NULL); - NearestAttackableTargetGoal(Mob* mob, const std::type_info& targetType, - float within, int randomInterval, bool mustSee, - bool mustReach = false); virtual ~NearestAttackableTargetGoal(); virtual bool canUse(); diff --git a/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.cpp b/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.cpp index f05fb91b8..7e65d559c 100644 --- a/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.cpp @@ -3,14 +3,12 @@ #include "NonTameRandomTargetGoal.h" NonTameRandomTargetGoal::NonTameRandomTargetGoal( - TamableAnimal* mob, const std::type_info& targetType, float within, - int randomInterval, bool mustSee) - : NearestAttackableTargetGoal(mob, targetType, within, randomInterval, - mustSee) { - this->tamableMob = mob; + TamableAnimal* mob, const std::type_info& targetType, int randomInterval, + bool mustSee) + : NearestAttackableTargetGoal(mob, targetType, randomInterval, mustSee) { + tamableMob = mob; } bool NonTameRandomTargetGoal::canUse() { - if (tamableMob->isTame()) return false; - return NearestAttackableTargetGoal::canUse(); + return !tamableMob->isTame() && NearestAttackableTargetGoal::canUse(); } diff --git a/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.h b/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.h index 3aae62756..431ad7ceb 100644 --- a/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.h +++ b/Minecraft.World/AI/Goals/NonTameRandomTargetGoal.h @@ -10,7 +10,7 @@ private: public: NonTameRandomTargetGoal(TamableAnimal* mob, - const std::type_info& targetType, float within, + const std::type_info& targetType, int randomInterval, bool mustSee); bool canUse(); diff --git a/Minecraft.World/AI/Goals/OcelotAttackGoal.cpp b/Minecraft.World/AI/Goals/OcelotAttackGoal.cpp index c66993272..5f56a3712 100644 --- a/Minecraft.World/AI/Goals/OcelotAttackGoal.cpp +++ b/Minecraft.World/AI/Goals/OcelotAttackGoal.cpp @@ -6,8 +6,8 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "OcelotAttackGoal.h" -OzelotAttackGoal::OzelotAttackGoal(Mob* mob) { - target = std::weak_ptr(); +OcelotAttackGoal::OcelotAttackGoal(Mob* mob) { + target = std::weak_ptr(); attackTime = 0; speed = 0; trackTarget = false; @@ -18,38 +18,38 @@ OzelotAttackGoal::OzelotAttackGoal(Mob* mob) { Control::LookControlFlag); } -bool OzelotAttackGoal::canUse() { - std::shared_ptr bestTarget = mob->getTarget(); +bool OcelotAttackGoal::canUse() { + std::shared_ptr bestTarget = mob->getTarget(); if (bestTarget == NULL) return false; - target = std::weak_ptr(bestTarget); + target = std::weak_ptr(bestTarget); return true; } -bool OzelotAttackGoal::canContinueToUse() { +bool OcelotAttackGoal::canContinueToUse() { if (target.lock() == NULL || !target.lock()->isAlive()) return false; if (mob->distanceToSqr(target.lock()) > 15 * 15) return false; return !mob->getNavigation()->isDone() || canUse(); } -void OzelotAttackGoal::stop() { +void OcelotAttackGoal::stop() { target = std::weak_ptr(); mob->getNavigation()->stop(); } -void OzelotAttackGoal::tick() { +void OcelotAttackGoal::tick() { mob->getLookControl()->setLookAt(target.lock(), 30, 30); double meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2); double distSqr = mob->distanceToSqr(target.lock()->x, target.lock()->bb->y0, target.lock()->z); - float speed = Ozelot::WALK_SPEED; + double speedModifier = Ocelot::WALK_SPEED_MOD; if (distSqr > meleeRadiusSqr && distSqr < 4 * 4) - speed = Ozelot::SPRINT_SPEED; + speedModifier = Ocelot::SPRINT_SPEED_MOD; else if (distSqr < 15 * 15) - speed = Ozelot::SNEAK_SPEED; + speedModifier = Ocelot::SNEAK_SPEED_MOD; - mob->getNavigation()->moveTo(target.lock(), speed); + mob->getNavigation()->moveTo(target.lock(), speedModifier); attackTime = std::max(attackTime - 1, 0); diff --git a/Minecraft.World/AI/Goals/OcelotAttackGoal.h b/Minecraft.World/AI/Goals/OcelotAttackGoal.h index b0eb1f78b..e756a41db 100644 --- a/Minecraft.World/AI/Goals/OcelotAttackGoal.h +++ b/Minecraft.World/AI/Goals/OcelotAttackGoal.h @@ -2,17 +2,17 @@ #include "Goal.h" -class OzelotAttackGoal : public Goal { +class OcelotAttackGoal : public Goal { private: Level* level; Mob* mob; - std::weak_ptr target; + std::weak_ptr target; int attackTime; float speed; bool trackTarget; public: - OzelotAttackGoal(Mob* mob); + OcelotAttackGoal(Mob* mob); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.cpp b/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.cpp index fd419f6ab..134fc71fb 100644 --- a/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.cpp +++ b/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.cpp @@ -17,7 +17,7 @@ const int OcelotSitOnTileGoal::SIT_TICKS = const int OcelotSitOnTileGoal::SEARCH_RANGE = 8; const double OcelotSitOnTileGoal::SIT_CHANCE = 0.0065f; -OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ozelot* ocelot, float speed) { +OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ocelot* ocelot, double speedModifier) { _tick = 0; tryTicks = 0; maxTicks = 0; @@ -26,7 +26,7 @@ OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ozelot* ocelot, float speed) { tileZ = 0; this->ocelot = ocelot; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::JumpControlFlag); } @@ -43,16 +43,22 @@ bool OcelotSitOnTileGoal::canContinueToUse() { void OcelotSitOnTileGoal::start() { ocelot->getNavigation()->moveTo((float)tileX + 0.5, tileY + 1, - (float)tileZ + 0.5, speed); + (float)tileZ + 0.5, speedModifier); _tick = 0; tryTicks = 0; maxTicks = ocelot->getRandom()->nextInt( ocelot->getRandom()->nextInt(SIT_TICKS) + SIT_TICKS) + SIT_TICKS; ocelot->getSitGoal()->wantToSit(false); + + ocelot->setSittingOnTile(true); // 4J-Added. } -void OcelotSitOnTileGoal::stop() { ocelot->setSitting(false); } +void OcelotSitOnTileGoal::stop() { + ocelot->setSitting(false); + + ocelot->setSittingOnTile(false); // 4J-Added. +} void OcelotSitOnTileGoal::tick() { _tick++; @@ -60,7 +66,7 @@ void OcelotSitOnTileGoal::tick() { if (ocelot->distanceToSqr(tileX, tileY + 1, tileZ) > 1) { ocelot->setSitting(false); ocelot->getNavigation()->moveTo((float)tileX + 0.5, tileY + 1, - (float)tileZ + 0.5, speed); + (float)tileZ + 0.5, speedModifier); tryTicks++; } else if (!ocelot->isSitting()) { ocelot->setSitting(true); @@ -82,9 +88,9 @@ bool OcelotSitOnTileGoal::findNearestTile() { double dist = ocelot->distanceToSqr(x, y, z); if (dist < distSqr) { - this->tileX = x; - this->tileY = y; - this->tileZ = z; + tileX = x; + tileY = y; + tileZ = z; distSqr = dist; } } diff --git a/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.h b/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.h index 8b6b232d2..11d979174 100644 --- a/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.h +++ b/Minecraft.World/AI/Goals/OcelotSitOnTileGoal.h @@ -2,7 +2,7 @@ #include "Goal.h" -class Ozelot; +class Ocelot; class OcelotSitOnTileGoal : public Goal { private: @@ -12,8 +12,8 @@ private: static const double SIT_CHANCE; private: - Ozelot* ocelot; // Owner of this goal - float speed; + Ocelot* ocelot; // Owner of this goal + double speedModifier; int _tick; int tryTicks; int maxTicks; @@ -22,7 +22,7 @@ private: int tileZ; public: - OcelotSitOnTileGoal(Ozelot* ocelot, float speed); + OcelotSitOnTileGoal(Ocelot* ocelot, double speedModifier); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/OpenDoorGoal.cpp b/Minecraft.World/AI/Goals/OpenDoorGoal.cpp index 5fc170b6d..e13f88c00 100644 --- a/Minecraft.World/AI/Goals/OpenDoorGoal.cpp +++ b/Minecraft.World/AI/Goals/OpenDoorGoal.cpp @@ -6,7 +6,7 @@ OpenDoorGoal::OpenDoorGoal(Mob* mob, bool closeDoorAfter) : DoorInteractGoal(mob) { this->mob = mob; - this->closeDoor = closeDoorAfter; + closeDoor = closeDoorAfter; } bool OpenDoorGoal::canContinueToUse() { diff --git a/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.cpp b/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.cpp index 7a748cc35..3b7169126 100644 --- a/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.cpp @@ -6,18 +6,31 @@ OwnerHurtByTargetGoal::OwnerHurtByTargetGoal(TamableAnimal* tameAnimal) : TargetGoal(tameAnimal, 32, false) { this->tameAnimal = tameAnimal; + timestamp = 0; setRequiredControlFlags(TargetGoal::TargetFlag); } bool OwnerHurtByTargetGoal::canUse() { if (!tameAnimal->isTame()) return false; - std::shared_ptr owner = tameAnimal->getOwner(); + std::shared_ptr owner = + std::dynamic_pointer_cast(tameAnimal->getOwner()); if (owner == NULL) return false; - ownerLastHurtBy = std::weak_ptr(owner->getLastHurtByMob()); - return canAttack(ownerLastHurtBy.lock(), false); + ownerLastHurtBy = std::weak_ptr(owner->getLastHurtByMob()); + int ts = owner->getLastHurtByMobTimestamp(); + + std::shared_ptr locked = ownerLastHurtBy.lock(); + return ts != timestamp && canAttack(locked, false) && + tameAnimal->wantsToAttack(locked, owner); } void OwnerHurtByTargetGoal::start() { mob->setTarget(ownerLastHurtBy.lock()); + + std::shared_ptr owner = + std::dynamic_pointer_cast(tameAnimal->getOwner()); + if (owner != NULL) { + timestamp = owner->getLastHurtByMobTimestamp(); + } + TargetGoal::start(); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.h b/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.h index d80b59923..19257c3a6 100644 --- a/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.h +++ b/Minecraft.World/AI/Goals/OwnerHurtByTargetGoal.h @@ -7,7 +7,8 @@ class TamableAnimal; class OwnerHurtByTargetGoal : public TargetGoal { private: TamableAnimal* tameAnimal; // Owner of this goal - std::weak_ptr ownerLastHurtBy; + std::weak_ptr ownerLastHurtBy; + int timestamp; public: OwnerHurtByTargetGoal(TamableAnimal* tameAnimal); diff --git a/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.cpp b/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.cpp index 19c32e146..55bf6c8c3 100644 --- a/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.cpp +++ b/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.cpp @@ -7,17 +7,29 @@ OwnerHurtTargetGoal::OwnerHurtTargetGoal(TamableAnimal* tameAnimal) : TargetGoal(tameAnimal, 32, false) { this->tameAnimal = tameAnimal; setRequiredControlFlags(TargetGoal::TargetFlag); + timestamp = 0; } bool OwnerHurtTargetGoal::canUse() { if (!tameAnimal->isTame()) return false; - std::shared_ptr owner = tameAnimal->getOwner(); + std::shared_ptr owner = + std::dynamic_pointer_cast(tameAnimal->getOwner()); if (owner == NULL) return false; - ownerLastHurt = std::weak_ptr(owner->getLastHurtMob()); - return canAttack(ownerLastHurt.lock(), false); + ownerLastHurt = std::weak_ptr(owner->getLastHurtMob()); + int ts = owner->getLastHurtMobTimestamp(); + std::shared_ptr locked = ownerLastHurt.lock(); + return ts != timestamp && canAttack(locked, false) && + tameAnimal->wantsToAttack(locked, owner); } void OwnerHurtTargetGoal::start() { mob->setTarget(ownerLastHurt.lock()); - TargetGoal::start(); + + std::shared_ptr owner = + std::dynamic_pointer_cast(tameAnimal->getOwner()); + if (owner != NULL) { + timestamp = owner->getLastHurtMobTimestamp(); + + TargetGoal::start(); + } } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.h b/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.h index 46024ed98..60927d987 100644 --- a/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.h +++ b/Minecraft.World/AI/Goals/OwnerHurtTargetGoal.h @@ -7,7 +7,8 @@ class TamableAnimal; class OwnerHurtTargetGoal : public TargetGoal { private: TamableAnimal* tameAnimal; // Owner of this goal - std::weak_ptr ownerLastHurt; + std::weak_ptr ownerLastHurt; + int timestamp; public: OwnerHurtTargetGoal(TamableAnimal* tameAnimal); diff --git a/Minecraft.World/AI/Goals/PanicGoal.cpp b/Minecraft.World/AI/Goals/PanicGoal.cpp index 6133b5c20..9c32c1c6e 100644 --- a/Minecraft.World/AI/Goals/PanicGoal.cpp +++ b/Minecraft.World/AI/Goals/PanicGoal.cpp @@ -6,14 +6,14 @@ #include "../../Headers/net.minecraft.world.phys.h" #include "PanicGoal.h" -PanicGoal::PanicGoal(PathfinderMob* mob, float speed) { +PanicGoal::PanicGoal(PathfinderMob* mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } bool PanicGoal::canUse() { - if (mob->getLastHurtByMob() == NULL) return false; + if (mob->getLastHurtByMob() == NULL && !mob->isOnFire()) return false; Vec3* pos = RandomPos::getPos( std::dynamic_pointer_cast(mob->shared_from_this()), 5, 4); @@ -25,7 +25,7 @@ bool PanicGoal::canUse() { } void PanicGoal::start() { - mob->getNavigation()->moveTo(posX, posY, posZ, speed); + mob->getNavigation()->moveTo(posX, posY, posZ, speedModifier); } bool PanicGoal::canContinueToUse() { return !mob->getNavigation()->isDone(); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/PanicGoal.h b/Minecraft.World/AI/Goals/PanicGoal.h index 7e4794b4a..487bfb49a 100644 --- a/Minecraft.World/AI/Goals/PanicGoal.h +++ b/Minecraft.World/AI/Goals/PanicGoal.h @@ -7,11 +7,11 @@ class PathfinderMob; class PanicGoal : public Goal { private: PathfinderMob* mob; - float speed; + double speedModifier; double posX, posY, posZ; public: - PanicGoal(PathfinderMob* mob, float speed); + PanicGoal(PathfinderMob* mob, double speedModifier); virtual bool canUse(); virtual void start(); diff --git a/Minecraft.World/AI/Goals/PlayGoal.cpp b/Minecraft.World/AI/Goals/PlayGoal.cpp index bdeb2e835..3096e325e 100644 --- a/Minecraft.World/AI/Goals/PlayGoal.cpp +++ b/Minecraft.World/AI/Goals/PlayGoal.cpp @@ -9,13 +9,13 @@ #include "../../Util/BasicTypeContainers.h" #include "PlayGoal.h" -PlayGoal::PlayGoal(Villager* mob, float speed) { - followFriend = std::weak_ptr(); +PlayGoal::PlayGoal(Villager* mob, double speedModifier) { + followFriend = std::weak_ptr(); wantedX = wantedY = wantedZ = 0.0; playTime = 0; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } @@ -38,7 +38,7 @@ bool PlayGoal::canUse() { double distSqr = friendV->distanceToSqr(mob->shared_from_this()); if (distSqr > closestDistSqr) continue; closestDistSqr = distSqr; - followFriend = std::weak_ptr(friendV); + followFriend = std::weak_ptr(friendV); } delete children; @@ -62,14 +62,14 @@ void PlayGoal::start() { void PlayGoal::stop() { mob->setChasing(false); - followFriend = std::weak_ptr(); + followFriend = std::weak_ptr(); } void PlayGoal::tick() { --playTime; if (followFriend.lock() != NULL) { if (mob->distanceToSqr(followFriend.lock()) > 2 * 2) - mob->getNavigation()->moveTo(followFriend.lock(), speed); + mob->getNavigation()->moveTo(followFriend.lock(), speedModifier); } else { if (mob->getNavigation()->isDone()) { Vec3* pos = @@ -77,7 +77,7 @@ void PlayGoal::tick() { mob->shared_from_this()), 16, 3); if (pos == NULL) return; - mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, speed); + mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, speedModifier); } } } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/PlayGoal.h b/Minecraft.World/AI/Goals/PlayGoal.h index 758666d33..9a8142485 100644 --- a/Minecraft.World/AI/Goals/PlayGoal.h +++ b/Minecraft.World/AI/Goals/PlayGoal.h @@ -5,13 +5,13 @@ class PlayGoal : public Goal { private: Villager* mob; - std::weak_ptr followFriend; - float speed; + std::weak_ptr followFriend; + double speedModifier; double wantedX, wantedY, wantedZ; int playTime; public: - PlayGoal(Villager* mob, float speed); + PlayGoal(Villager* mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/RandomStrollGoal.cpp b/Minecraft.World/AI/Goals/RandomStrollGoal.cpp index 0dbd86fb8..ba81c5442 100644 --- a/Minecraft.World/AI/Goals/RandomStrollGoal.cpp +++ b/Minecraft.World/AI/Goals/RandomStrollGoal.cpp @@ -7,9 +7,9 @@ #include "../../Util/SharedConstants.h" #include "RandomStrollGoal.h" -RandomStrollGoal::RandomStrollGoal(PathfinderMob* mob, float speed) { +RandomStrollGoal::RandomStrollGoal(PathfinderMob* mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); } @@ -57,5 +57,5 @@ bool RandomStrollGoal::canContinueToUse() { } void RandomStrollGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/RandomStrollGoal.h b/Minecraft.World/AI/Goals/RandomStrollGoal.h index 3e7bb17cb..45c2a6650 100644 --- a/Minecraft.World/AI/Goals/RandomStrollGoal.h +++ b/Minecraft.World/AI/Goals/RandomStrollGoal.h @@ -8,10 +8,10 @@ class RandomStrollGoal : public Goal { private: PathfinderMob* mob; double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; public: - RandomStrollGoal(PathfinderMob* mob, float speed); + RandomStrollGoal(PathfinderMob* mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/AI/Goals/RangedAttackGoal.cpp b/Minecraft.World/AI/Goals/RangedAttackGoal.cpp new file mode 100644 index 000000000..e58c59d1c --- /dev/null +++ b/Minecraft.World/AI/Goals/RangedAttackGoal.cpp @@ -0,0 +1,103 @@ +#include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.entity.ai.control.h" +#include "../../Headers/net.minecraft.world.entity.ai.navigation.h" +#include "../../Headers/net.minecraft.world.entity.ai.sensing.h" +#include "../../Headers/net.minecraft.world.entity.h" +#include "../../Headers/net.minecraft.world.entity.monster.h" +#include "../../Headers/net.minecraft.world.phys.h" +#include "RangedAttackGoal.h" + +void RangedAttackGoal::_init(RangedAttackMob* rangedMob, Mob* mob, + double speedModifier, int attackIntervalMin, + int attackIntervalMax, float attackRadius) { + // if (!(mob instanceof LivingEntity)) + //{ + // throw new IllegalArgumentException("ArrowAttackGoal requires Mob + // implements RangedAttackMob"); + // } + rangedAttackMob = rangedMob; + this->mob = mob; + this->speedModifier = speedModifier; + this->attackIntervalMin = attackIntervalMin; + this->attackIntervalMax = attackIntervalMax; + this->attackRadius = attackRadius; + attackRadiusSqr = attackRadius * attackRadius; + setRequiredControlFlags(Control::MoveControlFlag | + Control::LookControlFlag); + + target = std::weak_ptr(); + attackTime = -1; + seeTime = 0; +} + +RangedAttackGoal::RangedAttackGoal(RangedAttackMob* rangedMob, Mob* mob, + double speedModifier, int attackInterval, + float attackRadius) { + _init(rangedMob, mob, speedModifier, attackInterval, attackInterval, + attackRadius); +} + +RangedAttackGoal::RangedAttackGoal(RangedAttackMob* rangedMob, Mob* mob, + double speedModifier, int attackIntervalMin, + int attackIntervalMax, float attackRadius) { + _init(rangedMob, mob, speedModifier, attackIntervalMin, attackIntervalMax, + attackRadius); +} + +bool RangedAttackGoal::canUse() { + std::shared_ptr bestTarget = mob->getTarget(); + if (bestTarget == NULL) return false; + target = std::weak_ptr(bestTarget); + return true; +} + +bool RangedAttackGoal::canContinueToUse() { + return canUse() || !mob->getNavigation()->isDone(); +} + +void RangedAttackGoal::stop() { + target = std::weak_ptr(); + seeTime = 0; + attackTime = -1; +} + +void RangedAttackGoal::tick() { + // 4J: It's possible the target has gone since canUse selected it, don't do + // tick if target is null + if (target.lock() == NULL) return; + + double targetDistSqr = mob->distanceToSqr( + target.lock()->x, target.lock()->bb->y0, target.lock()->z); + bool canSee = mob->getSensing()->canSee(target.lock()); + + if (canSee) { + seeTime++; + } else { + seeTime = 0; + } + + if (targetDistSqr > attackRadiusSqr || seeTime < 20) { + mob->getNavigation()->moveTo(target.lock(), speedModifier); + } else { + mob->getNavigation()->stop(); + } + + mob->getLookControl()->setLookAt(target.lock(), 30, 30); + + if (--attackTime == 0) { + if (targetDistSqr > attackRadiusSqr || !canSee) return; + + float dist = Mth::sqrt(targetDistSqr) / attackRadius; + float power = dist; + if (power < 0.1f) power = 0.1f; + if (power > 1) power = 1; + + rangedAttackMob->performRangedAttack(target.lock(), power); + attackTime = Mth::floor(dist * (attackIntervalMax - attackIntervalMin) + + attackIntervalMin); + } else if (attackTime < 0) { + float dist = Mth::sqrt(targetDistSqr) / attackRadius; + attackTime = Mth::floor(dist * (attackIntervalMax - attackIntervalMin) + + attackIntervalMin); + } +} \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/RangedAttackGoal.h b/Minecraft.World/AI/Goals/RangedAttackGoal.h new file mode 100644 index 000000000..04027cf63 --- /dev/null +++ b/Minecraft.World/AI/Goals/RangedAttackGoal.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Goal.h" + +class RangedAttackMob; + +class RangedAttackGoal : public Goal { +private: + Mob* mob; // Owner + RangedAttackMob* rangedAttackMob; // owner + std::weak_ptr target; + int attackTime; + double speedModifier; + int seeTime; + int attackIntervalMin; + int attackIntervalMax; + float attackRadius; + float attackRadiusSqr; + + void _init(RangedAttackMob* rangedMob, Mob* mob, double speedModifier, + int attackIntervalMin, int attackIntervalMax, + float attackRadius); + +public: + // 4J Added extra Mob param to avoid weird type conversion problems + RangedAttackGoal(RangedAttackMob* rangedMob, Mob* mob, double speedModifier, + int attackInterval, float attackRadius); + RangedAttackGoal(RangedAttackMob* rangedMob, Mob* mob, double speedModifier, + int attackIntervalMin, int attackIntervalMax, + float attackRadius); + + bool canUse(); + bool canContinueToUse(); + void stop(); + void tick(); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.cpp b/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.cpp new file mode 100644 index 000000000..84c35dd41 --- /dev/null +++ b/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.cpp @@ -0,0 +1,60 @@ +#include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.entity.h" +#include "../../Headers/net.minecraft.world.entity.ai.control.h" +#include "../../Headers/net.minecraft.world.entity.animal.h" +#include "../../Headers/net.minecraft.world.entity.ai.navigation.h" +#include "../../Headers/net.minecraft.world.entity.player.h" +#include "../../Headers/net.minecraft.world.level.h" +#include "../Navigation/RandomPos.h" +#include "RunAroundLikeCrazyGoal.h" + +RunAroundLikeCrazyGoal::RunAroundLikeCrazyGoal(EntityHorse* mob, + double speedModifier) { + horse = mob; + this->speedModifier = speedModifier; + setRequiredControlFlags(Control::MoveControlFlag); +} + +bool RunAroundLikeCrazyGoal::canUse() { + if (horse->isTamed() || horse->rider.lock() == NULL) return false; + Vec3* pos = RandomPos::getPos( + std::dynamic_pointer_cast(horse->shared_from_this()), 5, + 4); + if (pos == NULL) return false; + posX = pos->x; + posY = pos->y; + posZ = pos->z; + return true; +} + +void RunAroundLikeCrazyGoal::start() { + horse->getNavigation()->moveTo(posX, posY, posZ, speedModifier); +} + +bool RunAroundLikeCrazyGoal::canContinueToUse() { + return !horse->getNavigation()->isDone() && horse->rider.lock() != NULL; +} + +void RunAroundLikeCrazyGoal::tick() { + if (horse->getRandom()->nextInt(50) == 0) { + if (horse->rider.lock()->instanceof(eTYPE_PLAYER)) { + int temper = horse->getTemper(); + int maxTemper = horse->getMaxTemper(); + if (maxTemper > 0 && + horse->getRandom()->nextInt(maxTemper) < temper) { + horse->tameWithName( + std::dynamic_pointer_cast(horse->rider.lock())); + horse->level->broadcastEntityEvent( + horse->shared_from_this(), EntityEvent::TAMING_SUCCEEDED); + return; + } + horse->modifyTemper(5); + } + + horse->rider.lock()->ride(nullptr); + horse->rider = std::weak_ptr(); + horse->makeMad(); + horse->level->broadcastEntityEvent(horse->shared_from_this(), + EntityEvent::TAMING_FAILED); + } +} \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.h b/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.h new file mode 100644 index 000000000..c5187a6dc --- /dev/null +++ b/Minecraft.World/AI/Goals/RunAroundLikeCrazyGoal.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Goal.h" + +class EntityHorse; + +class RunAroundLikeCrazyGoal : public Goal { +private: + EntityHorse* horse; // Owner + double speedModifier; + double posX, posY, posZ; + +public: + RunAroundLikeCrazyGoal(EntityHorse* mob, double speedModifier); + + bool canUse(); + void start(); + bool canContinueToUse(); + void tick(); +}; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/SitGoal.cpp b/Minecraft.World/AI/Goals/SitGoal.cpp index e3902076a..6a7a3fa14 100644 --- a/Minecraft.World/AI/Goals/SitGoal.cpp +++ b/Minecraft.World/AI/Goals/SitGoal.cpp @@ -19,7 +19,8 @@ bool SitGoal::canUse() { if (mob->isInWater()) return false; if (!mob->onGround) return false; - std::shared_ptr owner = mob->getOwner(); + std::shared_ptr owner = + std::dynamic_pointer_cast(mob->getOwner()); if (owner == NULL) return true; // owner not on level if (mob->distanceToSqr(owner) < FollowOwnerGoal::TeleportDistance * diff --git a/Minecraft.World/AI/Goals/SwellGoal.cpp b/Minecraft.World/AI/Goals/SwellGoal.cpp index 0d64e6064..bf3db4e80 100644 --- a/Minecraft.World/AI/Goals/SwellGoal.cpp +++ b/Minecraft.World/AI/Goals/SwellGoal.cpp @@ -6,24 +6,24 @@ #include "SwellGoal.h" SwellGoal::SwellGoal(Creeper* creeper) { - target = std::weak_ptr(); + target = std::weak_ptr(); this->creeper = creeper; setRequiredControlFlags(Control::MoveControlFlag); } bool SwellGoal::canUse() { - std::shared_ptr target = creeper->getTarget(); + std::shared_ptr target = creeper->getTarget(); return creeper->getSwellDir() > 0 || (target != NULL && (creeper->distanceToSqr(target) < 3 * 3)); } void SwellGoal::start() { creeper->getNavigation()->stop(); - target = std::weak_ptr(creeper->getTarget()); + target = std::weak_ptr(creeper->getTarget()); } -void SwellGoal::stop() { target = std::weak_ptr(); } +void SwellGoal::stop() { target = std::weak_ptr(); } void SwellGoal::tick() { if (target.lock() == NULL) { diff --git a/Minecraft.World/AI/Goals/SwellGoal.h b/Minecraft.World/AI/Goals/SwellGoal.h index f6ece0f21..82fbd0a09 100644 --- a/Minecraft.World/AI/Goals/SwellGoal.h +++ b/Minecraft.World/AI/Goals/SwellGoal.h @@ -7,7 +7,7 @@ class Creeper; class SwellGoal : public Goal { private: Creeper* creeper; - std::weak_ptr target; + std::weak_ptr target; public: SwellGoal(Creeper* creeper); diff --git a/Minecraft.World/AI/Goals/TakeFlowerGoal.cpp b/Minecraft.World/AI/Goals/TakeFlowerGoal.cpp index 0a872b8a8..455c84c8b 100644 --- a/Minecraft.World/AI/Goals/TakeFlowerGoal.cpp +++ b/Minecraft.World/AI/Goals/TakeFlowerGoal.cpp @@ -62,7 +62,7 @@ void TakeFlowerGoal::stop() { void TakeFlowerGoal::tick() { villager->getLookControl()->setLookAt(golem.lock(), 30, 30); if (golem.lock()->getOfferFlowerTick() == pickupTick) { - villager->getNavigation()->moveTo(golem.lock(), 0.15f); + villager->getNavigation()->moveTo(golem.lock(), 0.5f); takeFlower = true; } diff --git a/Minecraft.World/AI/Goals/TargetGoal.cpp b/Minecraft.World/AI/Goals/TargetGoal.cpp index 7e515374c..4c424e03e 100644 --- a/Minecraft.World/AI/Goals/TargetGoal.cpp +++ b/Minecraft.World/AI/Goals/TargetGoal.cpp @@ -1,36 +1,39 @@ #include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.entity.h" +#include "../../Headers/net.minecraft.world.entity.ai.attributes.h" #include "../../Headers/net.minecraft.world.entity.ai.navigation.h" #include "../../Headers/net.minecraft.world.entity.ai.sensing.h" -#include "../../Headers/net.minecraft.world.entity.h" #include "../../Headers/net.minecraft.world.entity.animal.h" +#include "../../Headers/net.minecraft.world.entity.monster.h" #include "../../Headers/net.minecraft.world.entity.player.h" #include "../../Headers/net.minecraft.world.level.pathfinder.h" #include "../../Headers/net.minecraft.world.phys.h" #include "TargetGoal.h" -void TargetGoal::_init(Mob* mob, float within, bool mustSee, bool mustReach) { +void TargetGoal::_init(PathfinderMob* mob, bool mustSee, bool mustReach) { reachCache = EmptyReachCache; reachCacheTime = 0; unseenTicks = 0; this->mob = mob; - this->within = within; this->mustSee = mustSee; this->mustReach = mustReach; } -TargetGoal::TargetGoal(Mob* mob, float within, bool mustSee) { - _init(mob, within, mustSee, false); +TargetGoal::TargetGoal(PathfinderMob* mob, bool mustSee) { + _init(mob, mustSee, false); } -TargetGoal::TargetGoal(Mob* mob, float within, bool mustSee, bool mustReach) { - _init(mob, within, mustSee, mustReach); +TargetGoal::TargetGoal(PathfinderMob* mob, bool mustSee, bool mustReach) { + _init(mob, mustSee, mustReach); } bool TargetGoal::canContinueToUse() { - std::shared_ptr target = mob->getTarget(); + std::shared_ptr target = mob->getTarget(); if (target == NULL) return false; if (!target->isAlive()) return false; + + double within = getFollowDistance(); if (mob->distanceToSqr(target) > within * within) return false; if (mustSee) { if (mob->getSensing()->canSee(target)) { @@ -42,6 +45,12 @@ bool TargetGoal::canContinueToUse() { return true; } +double TargetGoal::getFollowDistance() { + AttributeInstance* followRange = + mob->getAttribute(SharedMonsterAttributes::FOLLOW_RANGE); + return followRange == NULL ? 16 : followRange->getValue(); +} + void TargetGoal::start() { reachCache = EmptyReachCache; reachCacheTime = 0; @@ -50,21 +59,28 @@ void TargetGoal::start() { void TargetGoal::stop() { mob->setTarget(nullptr); } -bool TargetGoal::canAttack(std::shared_ptr target, +bool TargetGoal::canAttack(std::shared_ptr target, bool allowInvulnerable) { if (target == NULL) return false; if (target == mob->shared_from_this()) return false; if (!target->isAlive()) return false; if (!mob->canAttackType(target->GetType())) return false; - std::shared_ptr tamableAnimal = - std::dynamic_pointer_cast(mob->shared_from_this()); - if (tamableAnimal != NULL && tamableAnimal->isTame()) { - std::shared_ptr tamableTarget = - std::dynamic_pointer_cast(target); - if (tamableTarget != NULL && tamableTarget->isTame()) return false; - if (target == tamableAnimal->getOwner()) return false; - } else if (std::dynamic_pointer_cast(target) != NULL) { + OwnableEntity* ownableMob = dynamic_cast(mob); + if (ownableMob != NULL && !ownableMob->getOwnerUUID().empty()) { + std::shared_ptr ownableTarget = + std::dynamic_pointer_cast(target); + if (ownableTarget != NULL && ownableMob->getOwnerUUID().compare( + ownableTarget->getOwnerUUID()) == 0) { + // We're attacking something owned by the same person... + return false; + } + + if (target == ownableMob->getOwner()) { + // We're attacking our owner + return false; + } + } else if (target->instanceof(eTYPE_PLAYER)) { if (!allowInvulnerable && (std::dynamic_pointer_cast(target))->abilities.invulnerable) return false; @@ -86,7 +102,7 @@ bool TargetGoal::canAttack(std::shared_ptr target, return true; } -bool TargetGoal::canReach(std::shared_ptr target) { +bool TargetGoal::canReach(std::shared_ptr target) { reachCacheTime = 10 + mob->getRandom()->nextInt(5); Path* path = mob->getNavigation()->createPath(target); if (path == NULL) return false; diff --git a/Minecraft.World/AI/Goals/TargetGoal.h b/Minecraft.World/AI/Goals/TargetGoal.h index 2789e02da..3039172d7 100644 --- a/Minecraft.World/AI/Goals/TargetGoal.h +++ b/Minecraft.World/AI/Goals/TargetGoal.h @@ -2,6 +2,8 @@ #include "Goal.h" +class PathfinderMob; + class TargetGoal : public Goal { public: static const int TargetFlag = 1; @@ -13,8 +15,7 @@ private: static const int UnseenMemoryTicks = 60; protected: - Mob* mob; // Owner of this goal - float within; + PathfinderMob* mob; // Owner of this goal bool mustSee; private: @@ -23,20 +24,26 @@ private: int reachCacheTime; int unseenTicks; - void _init(Mob* mob, float within, bool mustSee, bool mustReach); + void _init(PathfinderMob* mob, bool mustSee, bool mustReach); public: - TargetGoal(Mob* mob, float within, bool mustSee); - TargetGoal(Mob* mob, float within, bool mustSee, bool mustReach); + TargetGoal(PathfinderMob* mob, bool mustSee); + TargetGoal(PathfinderMob* mob, bool mustSee, bool mustReach); virtual ~TargetGoal() {} virtual bool canContinueToUse(); + +protected: + virtual double getFollowDistance(); + +public: virtual void start(); virtual void stop(); protected: - virtual bool canAttack(std::shared_ptr target, bool allowInvulnerable); + virtual bool canAttack(std::shared_ptr target, + bool allowInvulnerable); private: - bool canReach(std::shared_ptr target); + bool canReach(std::shared_ptr target); }; \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/TemptGoal.cpp b/Minecraft.World/AI/Goals/TemptGoal.cpp index 3893ee73f..82738d257 100644 --- a/Minecraft.World/AI/Goals/TemptGoal.cpp +++ b/Minecraft.World/AI/Goals/TemptGoal.cpp @@ -6,7 +6,7 @@ #include "../../Headers/net.minecraft.world.level.h" #include "TemptGoal.h" -TemptGoal::TemptGoal(PathfinderMob* mob, float speed, int itemId, +TemptGoal::TemptGoal(PathfinderMob* mob, double speedModifier, int itemId, bool canScare) { px = py = pz = pRotX = pRotY = 0.0; player = std::weak_ptr(); @@ -15,7 +15,7 @@ TemptGoal::TemptGoal(PathfinderMob* mob, float speed, int itemId, oldAvoidWater = false; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->itemId = itemId; this->canScare = canScare; setRequiredControlFlags(Control::MoveControlFlag | @@ -81,7 +81,7 @@ void TemptGoal::tick() { if (mob->distanceToSqr(player.lock()) < 2.5 * 2.5) mob->getNavigation()->stop(); else - mob->getNavigation()->moveTo(player.lock(), speed); + mob->getNavigation()->moveTo(player.lock(), speedModifier); } bool TemptGoal::isRunning() { return _isRunning; } \ No newline at end of file diff --git a/Minecraft.World/AI/Goals/TemptGoal.h b/Minecraft.World/AI/Goals/TemptGoal.h index 000415584..860d30e64 100644 --- a/Minecraft.World/AI/Goals/TemptGoal.h +++ b/Minecraft.World/AI/Goals/TemptGoal.h @@ -5,7 +5,7 @@ class TemptGoal : public Goal { private: PathfinderMob* mob; - float speed; + double speedModifier; double px, py, pz, pRotX, pRotY; std::weak_ptr player; int calmDown; @@ -15,7 +15,8 @@ private: bool oldAvoidWater; public: - TemptGoal(PathfinderMob* mob, float speed, int itemId, bool canScare); + TemptGoal(PathfinderMob* mob, double speedModifier, int itemId, + bool canScare); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/AI/Navigation/PathFinder.cpp b/Minecraft.World/AI/Navigation/PathFinder.cpp index fda237f6e..0fe650e3b 100644 --- a/Minecraft.World/AI/Navigation/PathFinder.cpp +++ b/Minecraft.World/AI/Navigation/PathFinder.cpp @@ -168,7 +168,12 @@ Node* PathFinder::getNode(Entity* entity, int x, int y, int z, Node* size, if (avoidWater && cost == TYPE_WATER) return NULL; if (cost != TYPE_OPEN) break; // fell too far? - if (++drop >= 4) return NULL; + if (++drop >= 4) + return NULL; // 4J - rolling this back to pre-java 1.6.4 + // version as we're suspicious of the performance + // implications of this + // if (drop++ >= + // entity->getMaxFallDistance()) return NULL; y--; if (y > 0) best = getNode(x, y, z); @@ -221,6 +226,24 @@ int PathFinder::isFree(Entity* entity, int x, int y, int z, Node* size, } Tile* tile = Tile::tiles[tileId]; + + // 4J Stu - Use new getTileRenderShape passing in the tileId we + // have already got + if (entity->level->getTileRenderShape(tileId) == + Tile::SHAPE_RAIL) { + int xt = Mth::floor(entity->x); + int yt = Mth::floor(entity->y); + int zt = Mth::floor(entity->z); + if (entity->level->getTileRenderShape(xt, yt, zt) == + Tile::SHAPE_RAIL || + entity->level->getTileRenderShape(xt, yt - 1, zt) == + Tile::SHAPE_RAIL) { + continue; + } else { + return TYPE_FENCE; + } + } + if (tile->isPathfindable(entity->level, xx, yy, zz)) continue; if (canOpenDoors && tileId == Tile::door_wood_Id) continue; diff --git a/Minecraft.World/AI/Navigation/PathNavigation.cpp b/Minecraft.World/AI/Navigation/PathNavigation.cpp index 9a50b9b73..a80e4d4ef 100644 --- a/Minecraft.World/AI/Navigation/PathNavigation.cpp +++ b/Minecraft.World/AI/Navigation/PathNavigation.cpp @@ -2,19 +2,21 @@ #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.level.pathfinder.h" #include "../../Headers/net.minecraft.world.entity.h" +#include "../../Headers/net.minecraft.world.entity.ai.attributes.h" #include "../../Headers/net.minecraft.world.entity.ai.control.h" +#include "../../Headers/net.minecraft.world.entity.monster.h" #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.level.tile.h" #include "../../Headers/net.minecraft.world.phys.h" #include "PathNavigation.h" -PathNavigation::PathNavigation(Mob* mob, Level* level, float maxDist) { +PathNavigation::PathNavigation(Mob* mob, Level* level) { this->mob = mob; this->level = level; - this->maxDist = maxDist; + dist = mob->getAttribute(SharedMonsterAttributes::FOLLOW_RANGE); path = NULL; - speed = 0.0f; + speedModifier = 0.0; avoidSun = false; _tick = 0; lastStuckCheck = 0; @@ -48,45 +50,51 @@ bool PathNavigation::canOpenDoors() { return _canOpenDoors; } void PathNavigation::setAvoidSun(bool avoidSun) { this->avoidSun = avoidSun; } -void PathNavigation::setSpeed(float speed) { this->speed = speed; } +void PathNavigation::setSpeedModifier(double speedModifier) { + this->speedModifier = speedModifier; +} void PathNavigation::setCanFloat(bool canFloat) { this->canFloat = canFloat; } +float PathNavigation::getMaxDist() { return (float)dist->getValue(); } + Path* PathNavigation::createPath(double x, double y, double z) { if (!canUpdatePath()) return NULL; return level->findPath(mob->shared_from_this(), Mth::floor(x), (int)y, - Mth::floor(z), maxDist, _canPassDoors, _canOpenDoors, - avoidWater, canFloat); + Mth::floor(z), getMaxDist(), _canPassDoors, + _canOpenDoors, avoidWater, canFloat); } -bool PathNavigation::moveTo(double x, double y, double z, float speed) { +bool PathNavigation::moveTo(double x, double y, double z, + double speedModifier) { MemSect(52); Path* newPath = createPath(Mth::floor(x), (int)y, Mth::floor(z)); MemSect(0); // No need to delete newPath here as this will be copied into the member // variable path and the class can assume responsibility for it - return moveTo(newPath, speed); + return moveTo(newPath, speedModifier); } -Path* PathNavigation::createPath(std::shared_ptr target) { +Path* PathNavigation::createPath(std::shared_ptr target) { if (!canUpdatePath()) return NULL; - return level->findPath(mob->shared_from_this(), target, maxDist, + return level->findPath(mob->shared_from_this(), target, getMaxDist(), _canPassDoors, _canOpenDoors, avoidWater, canFloat); } -bool PathNavigation::moveTo(std::shared_ptr target, float speed) { +bool PathNavigation::moveTo(std::shared_ptr target, + double speedModifier) { MemSect(53); Path* newPath = createPath(target); MemSect(0); // No need to delete newPath here as this will be copied into the member // variable path and the class can assume responsibility for it if (newPath != NULL) - return moveTo(newPath, speed); + return moveTo(newPath, speedModifier); else return false; } -bool PathNavigation::moveTo(Path* newPath, float speed) { +bool PathNavigation::moveTo(Path* newPath, double speedModifier) { if (newPath == NULL) { if (path != NULL) delete path; path = NULL; @@ -101,7 +109,7 @@ bool PathNavigation::moveTo(Path* newPath, float speed) { if (avoidSun) trimPathFromSun(); if (path->getSize() == 0) return false; - this->speed = speed; + this->speedModifier = speedModifier; Vec3* mobPos = getTempMobPos(); lastStuckCheck = _tick; lastStuckCheckPos->x = mobPos->x; @@ -123,7 +131,7 @@ void PathNavigation::tick() { if (target == NULL) return; mob->getMoveControl()->setWantedPosition(target->x, target->y, target->z, - speed); + speedModifier); } void PathNavigation::updatePath() { diff --git a/Minecraft.World/AI/Navigation/PathNavigation.h b/Minecraft.World/AI/Navigation/PathNavigation.h index 6c2797abb..d9d731532 100644 --- a/Minecraft.World/AI/Navigation/PathNavigation.h +++ b/Minecraft.World/AI/Navigation/PathNavigation.h @@ -9,8 +9,8 @@ private: Mob* mob; Level* level; Path* path; - float speed; - float maxDist; + double speedModifier; + AttributeInstance* dist; bool avoidSun; int _tick; int lastStuckCheck; @@ -22,7 +22,7 @@ private: bool canFloat; public: - PathNavigation(Mob* mob, Level* level, float maxDist); + PathNavigation(Mob* mob, Level* level); ~PathNavigation(); void setAvoidWater(bool avoidWater); @@ -32,13 +32,14 @@ public: void setCanPassDoors(bool canPass); bool canOpenDoors(); void setAvoidSun(bool avoidSun); - void setSpeed(float speed); + void setSpeedModifier(double speedModifier); void setCanFloat(bool canFloat); + float getMaxDist(); Path* createPath(double x, double y, double z); - bool moveTo(double x, double y, double z, float speed); - Path* createPath(std::shared_ptr target); - bool moveTo(std::shared_ptr target, float speed); - bool moveTo(Path* newPath, float speed); + bool moveTo(double x, double y, double z, double speedModifier); + Path* createPath(std::shared_ptr target); + bool moveTo(std::shared_ptr target, double speedModifier); + bool moveTo(Path* newPath, double speedModifier); Path* getPath(); void tick();