Initial commit

This commit is contained in:
Stillkill committed 2026-03-08 15:20:20 -05:00
commit 2dfcaaa842
5375 files changed
+978475

No files matched your search

+354
View File
@@ -0,0 +1,354 @@
//package net.minecraft.world.phys;
//import java->util.ArrayList;
//import java->util.List;
#include "stdafx.h"
#include "AABB.h"
#include "HitResult.h"
DWORD AABB::tlsIdx = 0;
AABB::ThreadStorage *AABB::tlsDefault = NULL;
AABB::ThreadStorage::ThreadStorage()
{
pool = new AABB[POOL_SIZE];
poolPointer = 0;
}
AABB::ThreadStorage::~ThreadStorage()
{
delete pool;
}
void AABB::CreateNewThreadStorage()
{
ThreadStorage *tls = new ThreadStorage();
if(tlsDefault == NULL )
{
tlsIdx = TlsAlloc();
tlsDefault = tls;
}
TlsSetValue(tlsIdx, tls);
}
void AABB::UseDefaultThreadStorage()
{
TlsSetValue(tlsIdx, tlsDefault);
}
void AABB::ReleaseThreadStorage()
{
ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
if( tls == tlsDefault ) return;
delete tls;
}
AABB *AABB::newPermanent(double x0, double y0, double z0, double x1, double y1, double z1)
{
return new AABB(x0, y0, z0, x1, y1, z1);
}
void AABB::clearPool()
{
}
void AABB::resetPool()
{
}
AABB *AABB::newTemp(double x0, double y0, double z0, double x1, double y1, double z1)
{
ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
AABB *thisAABB = &tls->pool[tls->poolPointer];
thisAABB->set(x0, y0, z0, x1, y1, z1);
tls->poolPointer = ( tls->poolPointer + 1 ) % ThreadStorage::POOL_SIZE;
return thisAABB;
}
AABB::AABB(double x0, double y0, double z0, double x1, double y1, double z1)
{
this->x0 = x0;
this->y0 = y0;
this->z0 = z0;
this->x1 = x1;
this->y1 = y1;
this->z1 = z1;
}
AABB *AABB::set(double x0, double y0, double z0, double x1, double y1, double z1)
{
this->x0 = x0;
this->y0 = y0;
this->z0 = z0;
this->x1 = x1;
this->y1 = y1;
this->z1 = z1;
return this;
}
AABB *AABB::expand(double xa, double ya, double za)
{
double _x0 = x0;
double _y0 = y0;
double _z0 = z0;
double _x1 = x1;
double _y1 = y1;
double _z1 = z1;
if (xa < 0) _x0 += xa;
if (xa > 0) _x1 += xa;
if (ya < 0) _y0 += ya;
if (ya > 0) _y1 += ya;
if (za < 0) _z0 += za;
if (za > 0) _z1 += za;
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
}
AABB *AABB::grow(double xa, double ya, double za)
{
double _x0 = x0 - xa;
double _y0 = y0 - ya;
double _z0 = z0 - za;
double _x1 = x1 + xa;
double _y1 = y1 + ya;
double _z1 = z1 + za;
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
}
AABB *AABB::minmax(AABB *other)
{
double _x0 = min(x0, other->x0);
double _y0 = min(y0, other->y0);
double _z0 = min(z0, other->z0);
double _x1 = max(x1, other->x1);
double _y1 = max(y1, other->y1);
double _z1 = max(z1, other->z1);
return newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
}
AABB *AABB::cloneMove(double xa, double ya, double za)
{
return AABB::newTemp(x0 + xa, y0 + ya, z0 + za, x1 + xa, y1 + ya, z1 + za);
}
double AABB::clipXCollide(AABB *c, double xa)
{
if (c->y1 <= y0 || c->y0 >= y1) return xa;
if (c->z1 <= z0 || c->z0 >= z1) return xa;
if (xa > 0 && c->x1 <= x0)
{
double max = x0 - c->x1;
if (max < xa) xa = max;
}
if (xa < 0 && c->x0 >= x1)
{
double max = x1 - c->x0;
if (max > xa) xa = max;
}
return xa;
}
double AABB::clipYCollide(AABB *c, double ya)
{
if (c->x1 <= x0 || c->x0 >= x1) return ya;
if (c->z1 <= z0 || c->z0 >= z1) return ya;
if (ya > 0 && c->y1 <= y0)
{
double max = y0 - c->y1;
if (max < ya) ya = max;
}
if (ya < 0 && c->y0 >= y1)
{
double max = y1 - c->y0;
if (max > ya) ya = max;
}
return ya;
}
double AABB::clipZCollide(AABB *c, double za)
{
if (c->x1 <= x0 || c->x0 >= x1) return za;
if (c->y1 <= y0 || c->y0 >= y1) return za;
if (za > 0 && c->z1 <= z0)
{
double max = z0 - c->z1;
if (max < za) za = max;
}
if (za < 0 && c->z0 >= z1)
{
double max = z1 - c->z0;
if (max > za) za = max;
}
return za;
}
bool AABB::intersects(AABB *c)
{
if (c->x1 <= x0 || c->x0 >= x1) return false;
if (c->y1 <= y0 || c->y0 >= y1) return false;
if (c->z1 <= z0 || c->z0 >= z1) return false;
return true;
}
bool AABB::intersectsInner(AABB *c)
{
if (c->x1 < x0 || c->x0 > x1) return false;
if (c->y1 < y0 || c->y0 > y1) return false;
if (c->z1 < z0 || c->z0 > z1) return false;
return true;
}
AABB *AABB::move(double xa, double ya, double za)
{
x0 += xa;
y0 += ya;
z0 += za;
x1 += xa;
y1 += ya;
z1 += za;
return this;
}
bool AABB::intersects(double x02, double y02, double z02, double x12, double y12, double z12)
{
if (x12 <= x0 || x02 >= x1) return false;
if (y12 <= y0 || y02 >= y1) return false;
if (z12 <= z0 || z02 >= z1) return false;
return true;
}
bool AABB::contains(Vec3 *p)
{
if (p->x <= x0 || p->x >= x1) return false;
if (p->y <= y0 || p->y >= y1) return false;
if (p->z <= z0 || p->z >= z1) return false;
return true;
}
// 4J Added
bool AABB::containsIncludingLowerBound(Vec3 *p)
{
if (p->x < x0 || p->x >= x1) return false;
if (p->y < y0 || p->y >= y1) return false;
if (p->z < z0 || p->z >= z1) return false;
return true;
}
double AABB::getSize()
{
double xs = x1 - x0;
double ys = y1 - y0;
double zs = z1 - z0;
return (xs + ys + zs) / 3.0f;
}
AABB *AABB::shrink(double xa, double ya, double za)
{
double _x0 = x0 + xa;
double _y0 = y0 + ya;
double _z0 = z0 + za;
double _x1 = x1 - xa;
double _y1 = y1 - ya;
double _z1 = z1 - za;
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
}
AABB *AABB::copy()
{
return AABB::newTemp(x0, y0, z0, x1, y1, z1);
}
HitResult *AABB::clip(Vec3 *a, Vec3 *b)
{
Vec3 *xh0 = a->clipX(b, x0);
Vec3 *xh1 = a->clipX(b, x1);
Vec3 *yh0 = a->clipY(b, y0);
Vec3 *yh1 = a->clipY(b, y1);
Vec3 *zh0 = a->clipZ(b, z0);
Vec3 *zh1 = a->clipZ(b, z1);
if (!containsX(xh0)) xh0 = NULL;
if (!containsX(xh1)) xh1 = NULL;
if (!containsY(yh0)) yh0 = NULL;
if (!containsY(yh1)) yh1 = NULL;
if (!containsZ(zh0)) zh0 = NULL;
if (!containsZ(zh1)) zh1 = NULL;
Vec3 *closest = NULL;
if (xh0 != NULL && (closest == NULL || a->distanceToSqr(xh0) < a->distanceToSqr(closest))) closest = xh0;
if (xh1 != NULL && (closest == NULL || a->distanceToSqr(xh1) < a->distanceToSqr(closest))) closest = xh1;
if (yh0 != NULL && (closest == NULL || a->distanceToSqr(yh0) < a->distanceToSqr(closest))) closest = yh0;
if (yh1 != NULL && (closest == NULL || a->distanceToSqr(yh1) < a->distanceToSqr(closest))) closest = yh1;
if (zh0 != NULL && (closest == NULL || a->distanceToSqr(zh0) < a->distanceToSqr(closest))) closest = zh0;
if (zh1 != NULL && (closest == NULL || a->distanceToSqr(zh1) < a->distanceToSqr(closest))) closest = zh1;
if (closest == NULL) return NULL;
int face = -1;
if (closest == xh0) face = 4;
if (closest == xh1) face = 5;
if (closest == yh0) face = 0;
if (closest == yh1) face = 1;
if (closest == zh0) face = 2;
if (closest == zh1) face = 3;
return new HitResult(0, 0, 0, face, closest);
}
bool AABB::containsX(Vec3 *v)
{
if (v == NULL) return false;
return v->y >= y0 && v->y <= y1 && v->z >= z0 && v->z <= z1;
}
bool AABB::containsY(Vec3 *v)
{
if (v == NULL) return false;
return v->x >= x0 && v->x <= x1 && v->z >= z0 && v->z <= z1;
}
bool AABB::containsZ(Vec3 *v)
{
if (v == NULL) return false;
return v->x >= x0 && v->x <= x1 && v->y >= y0 && v->y <= y1;
}
void AABB::set(AABB *b)
{
x0 = b->x0;
y0 = b->y0;
z0 = b->z0;
x1 = b->x1;
y1 = b->y1;
z1 = b->z1;
}
wstring AABB::toString()
{
return L"box[" + _toString<double>(x0) + L", " + _toString<double>(y0) + L", " + _toString<double>(z0) + L" -> " +
_toString<double>(x1) + L", " + _toString<double>(y1) + L", " + _toString<double>(z1) + L"]";
}
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include "Vec3.h"
#include "Definitions.h"
class HitResult;
using namespace std;
class AABB
{
// 4J added so we can have separate pools for different threads
class ThreadStorage
{
public:
static const int POOL_SIZE = 1024;
AABB *pool;
unsigned int poolPointer;
ThreadStorage();
~ThreadStorage();
};
static DWORD tlsIdx;
static ThreadStorage *tlsDefault;
public:
// Each new thread that needs to use Vec3 pools will need to call one of the following 2 functions, to either create its own
// local storage, or share the default storage already allocated by the main thread
static void CreateNewThreadStorage();
static void UseDefaultThreadStorage();
static void ReleaseThreadStorage();
static AABB *newPermanent(double x0, double y0, double z0, double x1, double y1, double z1);
static void clearPool();
static void resetPool();
static AABB *newTemp(double x0, double y0, double z0, double x1, double y1, double z1);
double x0, y0, z0;
double x1, y1, z1;
private:
AABB(double x0, double y0, double z0, double x1, double y1, double z1);
AABB() {}
public:
AABB *set(double x0, double y0, double z0, double x1, double y1, double z1);
AABB *expand(double xa, double ya, double za);
AABB *grow(double xa, double ya, double za);
AABB *minmax(AABB *other);
AABB *cloneMove(double xa, double ya, double za);
double clipXCollide(AABB *c, double xa);
double clipYCollide(AABB *c, double ya);
double clipZCollide(AABB *c, double za);
bool intersects(AABB *c);
bool intersectsInner(AABB *c);
AABB *move(double xa, double ya, double za);
bool intersects(double x02, double y02, double z02, double x12, double y12, double z12);
bool contains(Vec3 *p);
bool containsIncludingLowerBound(Vec3 *p); // 4J Added
double getSize();
AABB *shrink(double xa, double ya, double za);
AABB *copy();
HitResult *clip(Vec3 *a, Vec3 *b);
bool containsX(Vec3 *v);
bool containsY(Vec3 *v);
bool containsZ(Vec3 *v);
void set(AABB *b);
wstring toString();
};
+77
View File
@@ -0,0 +1,77 @@
#include "stdafx.h"
#include "com.mojang.nbt.h"
#include "Abilities.h"
Abilities::Abilities()
{
invulnerable = false;
flying = false;
mayfly = false;
instabuild = false;
mayBuild = true;
flyingSpeed = 0.05f;
walkingSpeed = 0.1f;
#ifdef _DEBUG_MENUS_ENABLED
debugflying = false;
#endif
}
void Abilities::addSaveData(CompoundTag *parentTag)
{
CompoundTag *tag = new CompoundTag();
tag->putBoolean(L"invulnerable", invulnerable);
tag->putBoolean(L"flying", flying);
tag->putBoolean(L"mayfly", mayfly);
tag->putBoolean(L"instabuild", instabuild);
tag->putBoolean(L"mayBuild", mayBuild);
tag->putFloat(L"flySpeed", flyingSpeed);
tag->putFloat(L"walkSpeed", walkingSpeed);
parentTag->put(L"abilities", tag);
}
void Abilities::loadSaveData(CompoundTag *parentTag)
{
if (parentTag->contains(L"abilities"))
{
CompoundTag *tag = parentTag->getCompound(L"abilities");
invulnerable = tag->getBoolean(L"invulnerable");
flying = tag->getBoolean(L"flying");
mayfly = tag->getBoolean(L"mayfly");
instabuild = tag->getBoolean(L"instabuild");
if (tag->contains(L"flySpeed"))
{
flyingSpeed = tag->getFloat(L"flySpeed");
walkingSpeed = tag->getFloat(L"walkSpeed");
}
if (tag->contains(L"mayBuild"))
{
mayBuild = tag->getBoolean(L"mayBuild");
}
}
}
float Abilities::getFlyingSpeed()
{
return flyingSpeed;
}
void Abilities::setFlyingSpeed(float value)
{
flyingSpeed = value;
}
float Abilities::getWalkingSpeed()
{
return walkingSpeed;
}
void Abilities::setWalkingSpeed(float value)
{
walkingSpeed = value;
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
class CompoundTag;
class Abilities
{
public:
bool invulnerable;
bool flying;
bool mayfly;
bool instabuild;
bool mayBuild;
private:
float flyingSpeed;
float walkingSpeed;
public:
#ifdef _DEBUG_MENUS_ENABLED
bool debugflying;
#endif
Abilities();
void addSaveData(CompoundTag *parentTag);
void loadSaveData(CompoundTag *parentTag);
float getFlyingSpeed();
void setFlyingSpeed(float value);
float getWalkingSpeed();
void setWalkingSpeed(float value);
};
+20
View File
@@ -0,0 +1,20 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.effect.h"
#include "AbsoptionMobEffect.h"
AbsoptionMobEffect::AbsoptionMobEffect(int id, bool isHarmful, eMinecraftColour color) : MobEffect(id, isHarmful, color)
{
}
void AbsoptionMobEffect::removeAttributeModifiers(shared_ptr<LivingEntity> entity, BaseAttributeMap *attributes, int amplifier)
{
entity->setAbsorptionAmount(entity->getAbsorptionAmount() - 4 * (amplifier + 1));
MobEffect::removeAttributeModifiers(entity, attributes, amplifier);
}
void AbsoptionMobEffect::addAttributeModifiers(shared_ptr<LivingEntity> entity, BaseAttributeMap *attributes, int amplifier)
{
entity->setAbsorptionAmount(entity->getAbsorptionAmount() + 4 * (amplifier + 1));
MobEffect::addAttributeModifiers(entity, attributes, amplifier);
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
class LivingEntity;
#include "MobEffect.h"
class AbsoptionMobEffect : public MobEffect
{
public:
AbsoptionMobEffect(int id, bool isHarmful, eMinecraftColour color);
void removeAttributeModifiers(shared_ptr<LivingEntity> entity, BaseAttributeMap *attributes, int amplifier);
void addAttributeModifiers(shared_ptr<LivingEntity> entity, BaseAttributeMap *attributes, int amplifier);
};
+771
View File
@@ -0,0 +1,771 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.level.redstone.h"
#include "Slot.h"
#include "AbstractContainerMenu.h"
// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables
// TODO Make sure all derived classes also call this
AbstractContainerMenu::AbstractContainerMenu()
{
containerId = 0;
changeUid = 0;
quickcraftType = -1;
quickcraftStatus = 0;
m_bNeedsRendered = false;
}
AbstractContainerMenu::~AbstractContainerMenu()
{
for( unsigned int i = 0; i < slots.size(); i++ )
{
delete slots.at(i);
}
}
Slot *AbstractContainerMenu::addSlot(Slot *slot)
{
slot->index = (int)slots.size();
slots.push_back(slot);
lastSlots.push_back(nullptr);
return slot;
}
void AbstractContainerMenu::addSlotListener(ContainerListener *listener)
{
containerListeners.push_back(listener);
vector<shared_ptr<ItemInstance> > *items = getItems();
listener->refreshContainer(this, items);
delete items;
broadcastChanges();
}
void AbstractContainerMenu::removeSlotListener(ContainerListener *listener)
{
AUTO_VAR(it, std::find(containerListeners.begin(), containerListeners.end(), listener) );
if(it != containerListeners.end()) containerListeners.erase(it);
}
vector<shared_ptr<ItemInstance> > *AbstractContainerMenu::getItems()
{
vector<shared_ptr<ItemInstance> > *items = new vector<shared_ptr<ItemInstance> >();
AUTO_VAR(itEnd, slots.end());
for (AUTO_VAR(it, slots.begin()); it != itEnd; it++)
{
items->push_back((*it)->getItem());
}
return items;
}
void AbstractContainerMenu::sendData(int id, int value)
{
AUTO_VAR(itEnd, containerListeners.end());
for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++)
{
(*it)->setContainerData(this, id, value);
}
}
void AbstractContainerMenu::broadcastChanges()
{
for (unsigned int i = 0; i < slots.size(); i++)
{
shared_ptr<ItemInstance> current = slots.at(i)->getItem();
shared_ptr<ItemInstance> expected = lastSlots.at(i);
if (!ItemInstance::matches(expected, current))
{
// 4J Stu - Added 0 count check. There is a bug in the Java with anvils that means this broadcast
// happens while we are in the middle of quickmoving, and before the slot properly gets set to null
expected = (current == NULL || current->count == 0) ? nullptr : current->copy();
lastSlots[i] = expected;
m_bNeedsRendered = true;
AUTO_VAR(itEnd, containerListeners.end());
for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++)
{
(*it)->slotChanged(this, i, expected);
}
}
}
}
bool AbstractContainerMenu::needsRendered()
{
bool needsRendered = m_bNeedsRendered;
m_bNeedsRendered = false;
for (unsigned int i = 0; i < slots.size(); i++)
{
shared_ptr<ItemInstance> current = slots.at(i)->getItem();
shared_ptr<ItemInstance> expected = lastSlots.at(i);
if (!ItemInstance::matches(expected, current))
{
expected = current == NULL ? nullptr : current->copy();
lastSlots[i] = expected;
needsRendered = true;
}
}
return needsRendered;
}
bool AbstractContainerMenu::clickMenuButton(shared_ptr<Player> player, int buttonId)
{
return false;
}
Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index)
{
AUTO_VAR(itEnd, slots.end());
for (AUTO_VAR(it, slots.begin()); it != itEnd; it++)
{
Slot *slot = *it; //slots->at(i);
if (slot->isAt(c, index))
{
return slot;
}
}
return NULL;
}
Slot *AbstractContainerMenu::getSlot(int index)
{
return slots.at(index);
}
shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex)
{
Slot *slot = slots.at(slotIndex);
if (slot != NULL)
{
return slot->getItem();
}
return nullptr;
}
shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player, bool looped) // 4J Added looped param
{
shared_ptr<ItemInstance> clickedEntity = nullptr;
shared_ptr<Inventory> inventory = player->inventory;
if (clickType == CLICK_QUICK_CRAFT)
{
int expectedStatus = quickcraftStatus;
quickcraftStatus = getQuickcraftHeader(buttonNum);
if ((expectedStatus != QUICKCRAFT_HEADER_CONTINUE || quickcraftStatus != QUICKCRAFT_HEADER_END) && expectedStatus != quickcraftStatus)
{
resetQuickCraft();
}
else if (inventory->getCarried() == NULL)
{
resetQuickCraft();
}
else if (quickcraftStatus == QUICKCRAFT_HEADER_START)
{
quickcraftType = getQuickcraftType(buttonNum);
if (isValidQuickcraftType(quickcraftType))
{
quickcraftStatus = QUICKCRAFT_HEADER_CONTINUE;
quickcraftSlots.clear();
}
else
{
resetQuickCraft();
}
}
else if (quickcraftStatus == QUICKCRAFT_HEADER_CONTINUE)
{
Slot *slot = slots.at(slotIndex);
if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count > quickcraftSlots.size() && canDragTo(slot))
{
quickcraftSlots.insert(slot);
}
}
else if (quickcraftStatus == QUICKCRAFT_HEADER_END)
{
if (!quickcraftSlots.empty())
{
shared_ptr<ItemInstance> source = inventory->getCarried()->copy();
int remaining = inventory->getCarried()->count;
for(AUTO_VAR(it, quickcraftSlots.begin()); it != quickcraftSlots.end(); ++it)
{
Slot *slot = *it;
if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count >= quickcraftSlots.size() && canDragTo(slot))
{
shared_ptr<ItemInstance> copy = source->copy();
int carry = slot->hasItem() ? slot->getItem()->count : 0;
getQuickCraftSlotCount(&quickcraftSlots, quickcraftType, copy, carry);
if (copy->count > copy->getMaxStackSize()) copy->count = copy->getMaxStackSize();
if (copy->count > slot->getMaxStackSize()) copy->count = slot->getMaxStackSize();
remaining -= copy->count - carry;
slot->set(copy);
}
}
source->count = remaining;
if (source->count <= 0)
{
source = nullptr;
}
inventory->setCarried(source);
}
resetQuickCraft();
}
else
{
resetQuickCraft();
}
}
else if (quickcraftStatus != QUICKCRAFT_HEADER_START)
{
resetQuickCraft();
}
else if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1))
{
if (slotIndex == SLOT_CLICKED_OUTSIDE)
{
if (inventory->getCarried() != NULL)
{
if (slotIndex == SLOT_CLICKED_OUTSIDE)
{
if (buttonNum == 0)
{
player->drop(inventory->getCarried());
inventory->setCarried(nullptr);
}
if (buttonNum == 1)
{
player->drop(inventory->getCarried()->remove(1));
if (inventory->getCarried()->count == 0) inventory->setCarried(nullptr);
}
}
}
}
else if (clickType == CLICK_QUICK_MOVE)
{
if (slotIndex < 0) return nullptr;
Slot *slot = slots.at(slotIndex);
if(slot != NULL && slot->mayPickup(player))
{
shared_ptr<ItemInstance> piiClicked = quickMoveStack(player, slotIndex);
if (piiClicked != NULL)
{
int oldType = piiClicked->id;
// 4J Stu - We ignore the return value for loopClicks, so don't make a copy
if(!looped)
{
clickedEntity = piiClicked->copy();
}
// 4J Stu - Remove the reference to this before we start a recursive loop
piiClicked = nullptr;
if (slot != NULL)
{
if (slot->getItem() != NULL && slot->getItem()->id == oldType)
{
if(looped)
{
// Return a non-null value to indicate that we want to loop more
clickedEntity = shared_ptr<ItemInstance>(new ItemInstance(0,1,0));
}
else
{
// 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative
loopClick(slotIndex, buttonNum, true, player);
}
}
}
}
}
}
else
{
if (slotIndex < 0) return nullptr;
Slot *slot = slots.at(slotIndex);
if (slot != NULL)
{
shared_ptr<ItemInstance> clicked = slot->getItem();
shared_ptr<ItemInstance> carried = inventory->getCarried();
if (clicked != NULL)
{
clickedEntity = clicked->copy();
}
if (clicked == NULL)
{
if (carried != NULL && slot->mayPlace(carried))
{
int c = buttonNum == 0 ? carried->count : 1;
if (c > slot->getMaxStackSize())
{
c = slot->getMaxStackSize();
}
if (carried->count >= c)
{
slot->set(carried->remove(c));
}
if (carried->count == 0)
{
inventory->setCarried(nullptr);
}
}
}
// 4J Added for dyable armour and combinining damaged items
else if (buttonNum == 1 && mayCombine(slot, carried))
{
shared_ptr<ItemInstance> combined = slot->combine(carried);
if(combined != NULL)
{
slot->set(combined);
if(!player->abilities.instabuild) carried->remove(1);
if (carried->count == 0)
{
inventory->setCarried(nullptr);
}
}
}
else if (slot->mayPickup(player))
{
if (carried == NULL)
{
// pick up to empty hand
int c = buttonNum == 0 ? clicked->count : (clicked->count + 1) / 2;
shared_ptr<ItemInstance> removed = slot->remove(c);
inventory->setCarried(removed);
if (clicked->count == 0)
{
slot->set(nullptr);
}
slot->onTake(player, inventory->getCarried());
}
else if (slot->mayPlace(carried))
{
// put down and/or pick up
if (clicked->id != carried->id || clicked->getAuxValue() != carried->getAuxValue() || !ItemInstance::tagMatches(clicked, carried))
{
// no match, replace
if (carried->count <= slot->getMaxStackSize())
{
slot->set(carried);
inventory->setCarried(clicked);
}
}
else
{
// match, attempt to fill slot
int c = buttonNum == 0 ? carried->count : 1;
if (c > slot->getMaxStackSize() - clicked->count)
{
c = slot->getMaxStackSize() - clicked->count;
}
if (c > carried->getMaxStackSize() - clicked->count)
{
c = carried->getMaxStackSize() - clicked->count;
}
carried->remove(c);
if (carried->count == 0)
{
inventory->setCarried(nullptr);
}
clicked->count += c;
}
}
else
{
// pick up to non-empty hand
if (clicked->id == carried->id && carried->getMaxStackSize() > 1 && (!clicked->isStackedByData() || clicked->getAuxValue() == carried->getAuxValue())
&& ItemInstance::tagMatches(clicked, carried))
{
int c = clicked->count;
if (c > 0 && c + carried->count <= carried->getMaxStackSize())
{
carried->count += c;
clicked = slot->remove(c);
if (clicked->count == 0) slot->set(nullptr);
slot->onTake(player, inventory->getCarried());
}
}
}
}
slot->setChanged();
}
}
}
else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9)
{
Slot *slot = slots.at(slotIndex);
if (slot->mayPickup(player))
{
shared_ptr<ItemInstance> current = inventory->getItem(buttonNum);
bool canMove = current == NULL || (slot->container == inventory && slot->mayPlace(current));
int freeSlot = -1;
if (!canMove)
{
freeSlot = inventory->getFreeSlot();
canMove |= freeSlot > -1;
}
if (slot->hasItem() && canMove)
{
shared_ptr<ItemInstance> taking = slot->getItem();
inventory->setItem(buttonNum, taking);
if ((slot->container == inventory && slot->mayPlace(current)) || current == NULL)
{
slot->remove(taking->count);
slot->set(current);
slot->onTake(player, taking);
}
else if (freeSlot > -1)
{
inventory->add(current);
slot->remove(taking->count);
slot->set(nullptr);
slot->onTake(player, taking);
}
}
else if (!slot->hasItem() && current != NULL && slot->mayPlace(current))
{
inventory->setItem(buttonNum, nullptr);
slot->set(current);
}
}
}
else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0)
{
Slot *slot = slots.at(slotIndex);
if (slot != NULL && slot->hasItem())
{
shared_ptr<ItemInstance> copy = slot->getItem()->copy();
copy->count = copy->getMaxStackSize();
inventory->setCarried(copy);
}
}
else if (clickType == CLICK_THROW && inventory->getCarried() == NULL && slotIndex >= 0)
{
Slot *slot = slots.at(slotIndex);
if (slot != NULL && slot->hasItem() && slot->mayPickup(player))
{
shared_ptr<ItemInstance> item = slot->remove(buttonNum == 0 ? 1 : slot->getItem()->count);
slot->onTake(player, item);
player->drop(item);
}
}
else if (clickType == CLICK_PICKUP_ALL && slotIndex >= 0)
{
Slot *slot = slots.at(slotIndex);
shared_ptr<ItemInstance> carried = inventory->getCarried();
if (carried != NULL && (slot == NULL || !slot->hasItem() || !slot->mayPickup(player)))
{
int start = buttonNum == 0 ? 0 : slots.size() - 1;
int step = buttonNum == 0 ? 1 : -1;
for (int pass = 0; pass < 2; pass++ )
{
// In the first pass, we only get partial stacks.
for (int i = start; i >= 0 && i < slots.size() && carried->count < carried->getMaxStackSize(); i += step)
{
Slot *target = slots.at(i);
if (target->hasItem() && canItemQuickReplace(target, carried, true) && target->mayPickup(player) && canTakeItemForPickAll(carried, target))
{
if (pass == 0 && target->getItem()->count == target->getItem()->getMaxStackSize()) continue;
int count = min(carried->getMaxStackSize() - carried->count, target->getItem()->count);
shared_ptr<ItemInstance> removed = target->remove(count);
carried->count += count;
if (removed->count <= 0)
{
target->set(nullptr);
}
target->onTake(player, removed);
}
}
}
}
broadcastChanges();
}
return clickedEntity;
}
bool AbstractContainerMenu::canTakeItemForPickAll(shared_ptr<ItemInstance> carried, Slot *target)
{
return true;
}
// 4J Stu - Brought forward from 1.2 to fix infinite recursion bug in creative
void AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player)
{
while( clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player, true) != NULL)
{
}
}
bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr<ItemInstance> item)
{
return false;
}
void AbstractContainerMenu::removed(shared_ptr<Player> player)
{
shared_ptr<Inventory> inventory = player->inventory;
if (inventory->getCarried() != NULL)
{
player->drop(inventory->getCarried());
inventory->setCarried(nullptr);
}
}
void AbstractContainerMenu::slotsChanged()// 4J used to take a shared_ptr<Container> but wasn't using it, so removed to simplify things
{
broadcastChanges();
}
bool AbstractContainerMenu::isPauseScreen()
{
return false;
}
void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
{
getSlot(slot)->set(item);
}
void AbstractContainerMenu::setAll(ItemInstanceArray *items)
{
for (unsigned int i = 0; i < items->length; i++)
{
getSlot(i)->set( (*items)[i] );
}
}
void AbstractContainerMenu::setData(int id, int value)
{
}
short AbstractContainerMenu::backup(shared_ptr<Inventory> inventory)
{
changeUid++;
return changeUid;
}
bool AbstractContainerMenu::isSynched(shared_ptr<Player> player)
{
return !(unSynchedPlayers.find(player) != unSynchedPlayers.end());
}
void AbstractContainerMenu::setSynched(shared_ptr<Player> player, bool synched)
{
if (synched)
{
AUTO_VAR(it, unSynchedPlayers.find(player));
if(it != unSynchedPlayers.end()) unSynchedPlayers.erase( it );
}
else
{
unSynchedPlayers.insert(player);
}
}
// 4J Stu - Brought a few changes in this function forward from 1.2 to make it return a bool
bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards)
{
bool anythingChanged = false;
int destSlot = startSlot;
if (backwards)
{
destSlot = endSlot - 1;
}
// find stackable slots first
if (itemStack->isStackable())
{
while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)))
{
Slot *slot = slots.at(destSlot);
shared_ptr<ItemInstance> target = slot->getItem();
if (target != NULL && target->id == itemStack->id && (!itemStack->isStackedByData() || itemStack->getAuxValue() == target->getAuxValue())
&& ItemInstance::tagMatches(itemStack, target) )
{
int totalStack = target->count + itemStack->count;
if (totalStack <= itemStack->getMaxStackSize())
{
itemStack->count = 0;
target->count = totalStack;
slot->setChanged();
anythingChanged = true;
}
else if (target->count < itemStack->getMaxStackSize())
{
itemStack->count -= (itemStack->getMaxStackSize() - target->count);
target->count = itemStack->getMaxStackSize();
slot->setChanged();
anythingChanged = true;
}
}
if (backwards)
{
destSlot--;
}
else
{
destSlot++;
}
}
}
// find empty slot
if (itemStack->count > 0)
{
if (backwards)
{
destSlot = endSlot - 1;
}
else
{
destSlot = startSlot;
}
while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))
{
Slot *slot = slots.at(destSlot);
shared_ptr<ItemInstance> target = slot->getItem();
if (target == NULL)
{
slot->set(itemStack->copy());
slot->setChanged();
itemStack->count = 0;
anythingChanged = true;
break;
}
if (backwards)
{
destSlot--;
}
else
{
destSlot++;
}
}
}
return anythingChanged;
}
bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum)
{
return false;
}
int AbstractContainerMenu::getQuickcraftType(int mask)
{
return (mask >> 2) & 0x3;
}
int AbstractContainerMenu::getQuickcraftHeader(int mask)
{
return mask & 0x3;
}
int AbstractContainerMenu::getQuickcraftMask(int header, int type)
{
return (header & 0x3) | ((type & 0x3) << 2);
}
bool AbstractContainerMenu::isValidQuickcraftType(int type)
{
return type == QUICKCRAFT_TYPE_CHARITABLE || type == QUICKCRAFT_TYPE_GREEDY;
}
void AbstractContainerMenu::resetQuickCraft()
{
quickcraftStatus = QUICKCRAFT_HEADER_START;
quickcraftSlots.clear();
}
bool AbstractContainerMenu::canItemQuickReplace(Slot *slot, shared_ptr<ItemInstance> item, bool ignoreSize)
{
bool canReplace = slot == NULL || !slot->hasItem();
if (slot != NULL && slot->hasItem() && item != NULL && item->sameItem(slot->getItem()) && ItemInstance::tagMatches(slot->getItem(), item))
{
canReplace |= slot->getItem()->count + (ignoreSize ? 0 : item->count) <= item->getMaxStackSize();
}
return canReplace;
}
void AbstractContainerMenu::getQuickCraftSlotCount(unordered_set<Slot *> *quickCraftSlots, int quickCraftingType, shared_ptr<ItemInstance> item, int carry)
{
switch (quickCraftingType)
{
case QUICKCRAFT_TYPE_CHARITABLE:
item->count = Mth::floor(item->count / (float) quickCraftSlots->size());
break;
case QUICKCRAFT_TYPE_GREEDY:
item->count = 1;
break;
}
item->count += carry;
}
bool AbstractContainerMenu::canDragTo(Slot *slot)
{
return true;
}
int AbstractContainerMenu::getRedstoneSignalFromContainer(shared_ptr<Container> container)
{
if (container == NULL) return 0;
int count = 0;
float totalPct = 0;
for (int i = 0; i < container->getContainerSize(); i++)
{
shared_ptr<ItemInstance> item = container->getItem(i);
if (item != NULL)
{
totalPct += item->count / (float) min(container->getMaxStackSize(), item->getMaxStackSize());
count++;
}
}
totalPct /= container->getContainerSize();
return Mth::floor(totalPct * (Redstone::SIGNAL_MAX - 1)) + (count > 0 ? 1 : 0);
}
// 4J Added
bool AbstractContainerMenu::isValidIngredient(shared_ptr<ItemInstance> item, int slotId)
{
return true;
}
+124
View File
@@ -0,0 +1,124 @@
#pragma once
using namespace std;
#include "Player.h"
#include "net.minecraft.world.inventory.ContainerListener.h"
using net_minecraft_world_inventory::ContainerListener;
class Inventory;
class Slot;
class Item;
class ItemInstance;
class Container;
class AbstractContainerMenu
{
public:
static const int SLOT_CLICKED_OUTSIDE = -999;
static const int CLICK_PICKUP = 0;
static const int CLICK_QUICK_MOVE = 1;
static const int CLICK_SWAP = 2;
static const int CLICK_CLONE = 3;
static const int CLICK_THROW = 4;
static const int CLICK_QUICK_CRAFT = 5;
static const int CLICK_PICKUP_ALL = 6;
static const int QUICKCRAFT_TYPE_CHARITABLE = 0;
static const int QUICKCRAFT_TYPE_GREEDY = 1;
static const int QUICKCRAFT_HEADER_START = 0;
static const int QUICKCRAFT_HEADER_CONTINUE = 1;
static const int QUICKCRAFT_HEADER_END = 2;
// 4J Stu - Added these to fix problem with items picked up while in the creative menu replacing slots in the creative menu
static const int CONTAINER_ID_CARRIED = -1;
static const int CONTAINER_ID_INVENTORY = 0;
static const int CONTAINER_ID_CREATIVE = -2;
vector<shared_ptr<ItemInstance> > lastSlots;
vector<Slot *> slots;
int containerId;
private:
short changeUid;
int quickcraftType;
int quickcraftStatus;
unordered_set<Slot *> quickcraftSlots;
private:
bool m_bNeedsRendered; // 4J added
protected:
vector<ContainerListener *> containerListeners;
// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables
// TODO Make sure all derived classes also call this
AbstractContainerMenu();
Slot *addSlot(Slot *slot);
public:
virtual ~AbstractContainerMenu();
virtual void addSlotListener(ContainerListener *listener);
virtual void removeSlotListener(ContainerListener *listener);
virtual vector<shared_ptr<ItemInstance> > *getItems();
virtual void sendData(int id, int value);
virtual void broadcastChanges();
virtual bool needsRendered();
virtual bool clickMenuButton(shared_ptr<Player> player, int buttonId);
virtual Slot *getSlotFor(shared_ptr<Container> c, int index);
virtual Slot *getSlot(int index);
virtual shared_ptr<ItemInstance> quickMoveStack(shared_ptr<Player> player, int slotIndex);
virtual shared_ptr<ItemInstance> clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player, bool looped = false); // 4J added looped param
virtual bool mayCombine(Slot *slot, shared_ptr<ItemInstance> item);
virtual bool canTakeItemForPickAll(shared_ptr<ItemInstance> carried, Slot *target);
protected:
virtual void loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player);
public:
virtual void removed(shared_ptr<Player> player);
virtual void slotsChanged();// 4J used to take a shared_ptr<Container> container but wasn't using it, so removed to simplify things
bool isPauseScreen();
void setItem(unsigned int slot, shared_ptr<ItemInstance> item);
void setAll(ItemInstanceArray *items);
virtual void setData(int id, int value);
short backup(shared_ptr<Inventory> inventory);
private:
unordered_set<shared_ptr<Player> , PlayerKeyHash, PlayerKeyEq> unSynchedPlayers;
public:
bool isSynched(shared_ptr<Player> player);
void setSynched(shared_ptr<Player> player, bool synched);
virtual bool stillValid(shared_ptr<Player> player) = 0;
// 4J Stu Added for UI
unsigned int getSize() { return (unsigned int)slots.size(); }
protected:
// 4J Stu - Changes to return bool brought forward from 1.2
bool moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards);
public:
virtual bool isOverrideResultClick(int slotNum, int buttonNum);
static int getQuickcraftType(int mask);
static int getQuickcraftHeader(int mask);
static int getQuickcraftMask(int header, int type);
static bool isValidQuickcraftType(int type);
protected:
void resetQuickCraft();
public:
static bool canItemQuickReplace(Slot *slot, shared_ptr<ItemInstance> item, bool ignoreSize);
static void getQuickCraftSlotCount(unordered_set<Slot *> *quickCraftSlots, int quickCraftingType, shared_ptr<ItemInstance> item, int carry);
bool canDragTo(Slot *slot);
static int getRedstoneSignalFromContainer(shared_ptr<Container> container);
// 4J Added
virtual bool isValidIngredient(shared_ptr<ItemInstance> item, int slotId);
};
@@ -0,0 +1,48 @@
#include "stdafx.h"
#include "AbstractProjectileDispenseBehavior.h"
#include "DispenserTile.h"
#include "Projectile.h"
#include "Level.h"
#include "LevelEvent.h"
#include "ItemInstance.h"
shared_ptr<ItemInstance> AbstractProjectileDispenseBehavior::execute(BlockSource *source, shared_ptr<ItemInstance> dispensed, eOUTCOME &outcome)
{
Level *world = source->getWorld();
if ( world->countInstanceOf(eTYPE_PROJECTILE, false) >= Level::MAX_DISPENSABLE_PROJECTILES )
{
return DefaultDispenseItemBehavior::execute(source, dispensed, outcome);
}
Position *position = DispenserTile::getDispensePosition(source);
FacingEnum *facing = DispenserTile::getFacing(source->getData());
shared_ptr<Projectile> projectile = getProjectile(world, position);
delete position;
projectile->shoot(facing->getStepX(), facing->getStepY() + .1f, facing->getStepZ(), getPower(), getUncertainty());
world->addEntity(dynamic_pointer_cast<Entity>(projectile));
dispensed->remove(1);
return dispensed;
}
void AbstractProjectileDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome)
{
if (outcome != LEFT_ITEM)
{
source->getWorld()->levelEvent(LevelEvent::SOUND_LAUNCH, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0);
}
}
float AbstractProjectileDispenseBehavior::getUncertainty()
{
return 6.0f;
}
float AbstractProjectileDispenseBehavior::getPower()
{
return 1.1f;
}
@@ -0,0 +1,17 @@
#pragma once
#include "DefaultDispenseItemBehavior.h"
class Projectile;
class Position;
class AbstractProjectileDispenseBehavior : public DefaultDispenseItemBehavior
{
public:
virtual shared_ptr<ItemInstance> execute(BlockSource *source, shared_ptr<ItemInstance> dispensed, eOUTCOME &outcome);
protected:
virtual void playSound(BlockSource *source, eOUTCOME outcome);
virtual float getUncertainty();
virtual float getPower();
virtual shared_ptr<Projectile> getProjectile(Level *world, Position *position) = 0;
};
+82
View File
@@ -0,0 +1,82 @@
#include "stdafx.h"
#include "net.minecraft.locale.h"
#include "ItemInstance.h"
#include "Achievements.h"
#include "DescFormatter.h"
#include "Achievement.h"
void Achievement::_init()
{
isGoldenVar = false;
if (x < Achievements::xMin) Achievements::xMin = x;
if (y < Achievements::yMin) Achievements::yMin = y;
if (x > Achievements::xMax) Achievements::xMax = x;
if (y > Achievements::yMax) Achievements::yMax = y;
}
Achievement::Achievement(int id, const wstring& name, int x, int y, Item *icon, Achievement *requires)
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon( new ItemInstance(icon) ), x(x), y(y), requires(requires)
{
}
Achievement::Achievement(int id, const wstring& name, int x, int y, Tile *icon, Achievement *requires)
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon( new ItemInstance(icon) ), x(x), y(y), requires(requires)
{
}
Achievement::Achievement(int id, const wstring& name, int x, int y, shared_ptr<ItemInstance> icon, Achievement *requires)
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon(icon), x(x), y(y), requires(requires)
{
}
Achievement *Achievement::setAwardLocallyOnly()
{
awardLocallyOnly = true;
return this;
}
Achievement *Achievement::setGolden()
{
isGoldenVar = true;
return this;
}
Achievement *Achievement::postConstruct()
{
Stat::postConstruct();
Achievements::achievements->push_back(this);
return this;
}
bool Achievement::isAchievement()
{
return true;
}
wstring Achievement::getDescription()
{
if (descFormatter != NULL)
{
return descFormatter->format(desc);
}
return desc;
}
Achievement *Achievement::setDescFormatter(DescFormatter *descFormatter)
{
this->descFormatter = descFormatter;
return this;
}
bool Achievement::isGolden()
{
return isGoldenVar;
}
int Achievement::getAchievementID()
{
return id - Achievements::ACHIEVEMENT_OFFSET;
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
using namespace std;
#include "Stat.h"
class DescFormatter;
class Achievement : public Stat
{
public:
const int x, y;
Achievement *requires;
private:
const wstring desc;
DescFormatter *descFormatter;
public:
const shared_ptr<ItemInstance> icon;
private:
bool isGoldenVar;
void _init();
public:
Achievement(int id, const wstring& name, int x, int y, Item *icon, Achievement *requires);
Achievement(int id, const wstring& name, int x, int y, Tile *icon, Achievement *requires);
Achievement(int id, const wstring& name, int x, int y, shared_ptr<ItemInstance> icon, Achievement *requires);
Achievement *setAwardLocallyOnly();
Achievement *setGolden();
Achievement *postConstruct();
bool isAchievement();
wstring getDescription();
Achievement *setDescFormatter(DescFormatter *descFormatter);
bool isGolden();
int getAchievementID();
};
+185
View File
@@ -0,0 +1,185 @@
#include "stdafx.h"
#include "net.minecraft.stats.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.level.tile.h"
#include "Achievement.h"
#include "Achievements.h"
const int Achievements::ACHIEVEMENT_OFFSET = 0x500000;
// maximum position of achievements (min and max)
int Achievements::xMin = 4294967295; // 4J Stu Was 4294967296 which is 1 larger than maxint. Hopefully no side effects
int Achievements::yMin = 4294967295; // 4J Stu Was 4294967296 which is 1 larger than maxint. Hopefully no side effects
int Achievements::xMax = 0;
int Achievements::yMax = 0;
vector<Achievement *> *Achievements::achievements = new vector<Achievement *>;
Achievement *Achievements::openInventory = NULL;
Achievement *Achievements::mineWood = NULL;
Achievement *Achievements::buildWorkbench = NULL;
Achievement *Achievements::buildPickaxe = NULL;
Achievement *Achievements::buildFurnace = NULL;
Achievement *Achievements::acquireIron = NULL;
Achievement *Achievements::buildHoe = NULL;
Achievement *Achievements::makeBread = NULL;
Achievement *Achievements::bakeCake = NULL;
Achievement *Achievements::buildBetterPickaxe = NULL;
Achievement *Achievements::cookFish = NULL;
Achievement *Achievements::onARail = NULL;
Achievement *Achievements::buildSword = NULL;
Achievement *Achievements::killEnemy = NULL;
Achievement *Achievements::killCow = NULL;
Achievement *Achievements::flyPig = NULL;
Achievement *Achievements::snipeSkeleton = NULL;
Achievement *Achievements::diamonds = NULL;
//Achievement *Achievements::portal = NULL;
Achievement *Achievements::ghast = NULL;
Achievement *Achievements::blazeRod = NULL;
Achievement *Achievements::potion = NULL;
Achievement *Achievements::theEnd = NULL;
Achievement *Achievements::winGame = NULL;
Achievement *Achievements::enchantments = NULL;
//Achievement *Achievements::overkill = NULL;
//Achievement *Achievements::bookcase = NULL;
// 4J : WESTY : Added new acheivements.
Achievement *Achievements::leaderOfThePack = NULL;
Achievement *Achievements::MOARTools = NULL;
Achievement *Achievements::dispenseWithThis = NULL;
Achievement *Achievements::InToTheNether = NULL;
// 4J : WESTY : Added other awards.
Achievement *Achievements::socialPost = NULL;
Achievement *Achievements::eatPorkChop = NULL;
Achievement *Achievements::play100Days = NULL;
Achievement *Achievements::arrowKillCreeper = NULL;
Achievement *Achievements::mine100Blocks = NULL;
Achievement *Achievements::kill10Creepers = NULL;
#ifdef _EXTENDED_ACHIEVEMENTS
Achievement *Achievements::overkill = NULL; // Restored old achivements.
Achievement *Achievements::bookcase = NULL; // Restored old achivements.
// 4J-JEV: New Achievements for Orbis.
Achievement *Achievements::adventuringTime = NULL;
Achievement *Achievements::repopulation = NULL;
//Achievement *Achievements::porkChop = NULL;
Achievement *Achievements::diamondsToYou = NULL;
//Achievement *Achievements::passingTheTime = NULL;
//Achievement *Achievements::archer = NULL;
Achievement *Achievements::theHaggler = NULL;
Achievement *Achievements::potPlanter = NULL;
Achievement *Achievements::itsASign = NULL;
Achievement *Achievements::ironBelly = NULL;
Achievement *Achievements::haveAShearfulDay = NULL;
Achievement *Achievements::rainbowCollection = NULL;
Achievement *Achievements::stayinFrosty = NULL;
Achievement *Achievements::chestfulOfCobblestone = NULL;
Achievement *Achievements::renewableEnergy = NULL;
Achievement *Achievements::musicToMyEars = NULL;
Achievement *Achievements::bodyGuard = NULL;
Achievement *Achievements::ironMan = NULL;
Achievement *Achievements::zombieDoctor = NULL;
Achievement *Achievements::lionTamer = NULL;
#endif
void Achievements::staticCtor()
{
Achievements::openInventory = (new Achievement(eAward_TakingInventory, L"openInventory", 0, 0, Item::book, NULL))->setAwardLocallyOnly()->postConstruct();
Achievements::mineWood = (new Achievement(eAward_GettingWood, L"mineWood", 2, 1, Tile::treeTrunk, (Achievement *) openInventory))->postConstruct();
Achievements::buildWorkbench = (new Achievement(eAward_Benchmarking, L"buildWorkBench", 4, -1, Tile::workBench, (Achievement *) mineWood))->postConstruct();
Achievements::buildPickaxe = (new Achievement(eAward_TimeToMine, L"buildPickaxe", 4, 2, Item::pickAxe_wood, (Achievement *) buildWorkbench))->postConstruct();
Achievements::buildFurnace = (new Achievement(eAward_HotTopic, L"buildFurnace", 3, 4, Tile::furnace_lit, (Achievement *) buildPickaxe))->postConstruct();
Achievements::acquireIron = (new Achievement(eAward_AquireHardware, L"acquireIron", 1, 4, Item::ironIngot, (Achievement *) buildFurnace))->postConstruct();
Achievements::buildHoe = (new Achievement(eAward_TimeToFarm, L"buildHoe", 2, -3, Item::hoe_wood, (Achievement *) buildWorkbench))->postConstruct();
Achievements::makeBread = (new Achievement(eAward_BakeBread, L"makeBread", -1, -3, Item::bread, (Achievement *) buildHoe))->postConstruct();
Achievements::bakeCake = (new Achievement(eAward_TheLie, L"bakeCake", 0, -5, Item::cake, (Achievement *) buildHoe))->postConstruct();
Achievements::buildBetterPickaxe = (new Achievement(eAward_GettingAnUpgrade, L"buildBetterPickaxe", 6, 2, Item::pickAxe_stone, (Achievement *) buildPickaxe))->postConstruct();
Achievements::cookFish = (new Achievement(eAward_DeliciousFish, L"cookFish", 2, 6, Item::fish_cooked, (Achievement *) buildFurnace))->postConstruct();
Achievements::onARail = (new Achievement(eAward_OnARail, L"onARail", 2, 3, Tile::rail, (Achievement *) acquireIron))->setGolden()->postConstruct();
Achievements::buildSword = (new Achievement(eAward_TimeToStrike, L"buildSword", 6, -1, Item::sword_wood, (Achievement *) buildWorkbench))->postConstruct();
Achievements::killEnemy = (new Achievement(eAward_MonsterHunter, L"killEnemy", 8, -1, Item::bone, (Achievement *) buildSword))->postConstruct();
Achievements::killCow = (new Achievement(eAward_CowTipper, L"killCow", 7, -3, Item::leather, (Achievement *) buildSword))->postConstruct();
Achievements::flyPig = (new Achievement(eAward_WhenPigsFly, L"flyPig", 8, -4, Item::saddle, (Achievement *) killCow))->setGolden()->postConstruct();
// 4J Stu - The order of these achievemnts is very important, as they map directly to data stored in the profile data. New achievements should be added at the end.
// 4J : WESTY : Added new achievements. Note, params "x", "y", "icon" and "requires" are ignored on xbox.
Achievements::leaderOfThePack = (new Achievement(eAward_LeaderOfThePack, L"leaderOfThePack", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
Achievements::MOARTools = (new Achievement(eAward_MOARTools, L"MOARTools", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
Achievements::dispenseWithThis = (new Achievement(eAward_DispenseWithThis, L"dispenseWithThis", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
Achievements::InToTheNether = (new Achievement(eAward_InToTheNether, L"InToTheNether", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
// 4J : WESTY : Added other awards.
Achievements::mine100Blocks = (new Achievement(eAward_mine100Blocks, L"mine100Blocks", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
Achievements::kill10Creepers = (new Achievement(eAward_kill10Creepers, L"kill10Creepers", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
#ifdef _EXTENDED_ACHIEVEMENTS
Achievements::eatPorkChop = (new Achievement(eAward_eatPorkChop, L"eatPorkChop", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
#else
Achievements::eatPorkChop = (new Achievement(eAward_eatPorkChop, L"eatPorkChop", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
#endif
Achievements::play100Days = (new Achievement(eAward_play100Days, L"play100Days", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
Achievements::arrowKillCreeper = (new Achievement(eAward_arrowKillCreeper, L"arrowKillCreeper", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
Achievements::socialPost = (new Achievement(eAward_socialPost, L"socialPost", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
#ifndef _XBOX
// WARNING: NO NEW ACHIEVMENTS CAN BE ADDED HERE
// These stats (achievements) are directly followed by new stats/achievements in the profile data, so cannot be changed without migrating the profile data
// 4J Stu - All new Java achievements removed to stop them using the profile data
// 4J Stu - This achievment added in 1.8.2, but does not map to any Xbox achievements
Achievements::snipeSkeleton = (new Achievement(eAward_snipeSkeleton, L"snipeSkeleton", 7, 0, Item::bow, (Achievement *) killEnemy))->setGolden()->postConstruct();
// 4J Stu - These added in 1.0.1, but do not map to any Xbox achievements
Achievements::diamonds = (new Achievement(eAward_diamonds, L"diamonds", -1, 5, Item::diamond, (Achievement *) acquireIron) )->postConstruct();
//Achievements::portal = (new Achievement(eAward_portal, L"portal", -1, 7, Tile::obsidian, (Achievement *)diamonds) )->postConstruct();
Achievements::ghast = (new Achievement(eAward_ghast, L"ghast", -4, 8, Item::ghastTear, (Achievement *)ghast) )->setGolden()->postConstruct();
Achievements::blazeRod = (new Achievement(eAward_blazeRod, L"blazeRod", 0, 9, Item::blazeRod, (Achievement *)blazeRod) )->postConstruct();
Achievements::potion = (new Achievement(eAward_potion, L"potion", 2, 8, Item::potion, (Achievement *)potion) )->postConstruct();
Achievements::theEnd = (new Achievement(eAward_theEnd, L"theEnd", 3, 10, Item::eyeOfEnder, (Achievement *)theEnd) )->setGolden()->postConstruct();
Achievements::winGame = (new Achievement(eAward_winGame, L"theEnd2", 4, 13, Tile::dragonEgg, (Achievement *)winGame) )->setGolden()->postConstruct();
Achievements::enchantments = (new Achievement(eAward_enchantments, L"enchantments", -4, 4, Tile::enchantTable, (Achievement *)enchantments) )->postConstruct();
// Achievements::overkill = (new Achievement(eAward_overkill, L"overkill", -4, 1, Item::sword_diamond, (Achievement *)enchantments) )->setGolden()->postConstruct();
// Achievements::bookcase = (new Achievement(eAward_bookcase, L"bookcase", -3, 6, Tile::bookshelf, (Achievement *)enchantments) )->postConstruct();
#endif
#ifdef _EXTENDED_ACHIEVEMENTS
Achievements::overkill = (new Achievement(eAward_overkill, L"overkill", -4,1, Item::sword_diamond, (Achievement *)enchantments) )->setGolden()->postConstruct();
Achievements::bookcase = (new Achievement(eAward_bookcase, L"bookcase", -3,6, Tile::bookshelf, (Achievement *)enchantments) )->postConstruct();
Achievements::adventuringTime = (new Achievement(eAward_adventuringTime, L"adventuringTime", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::repopulation = (new Achievement(eAward_repopulation, L"repopulation", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
//Achievements::porkChoop // // // // // //
Achievements::diamondsToYou = (new Achievement(eAward_diamondsToYou, L"diamondsToYou", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
//Achievements::passingTheTime = (new Achievement(eAward_play100Days, L"passingTheTime", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
//Achievements::archer = (new Achievement(eAward_arrowKillCreeper, L"archer", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::theHaggler = (new Achievement(eAward_theHaggler, L"theHaggler", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::potPlanter = (new Achievement(eAward_potPlanter, L"potPlanter", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::itsASign = (new Achievement(eAward_itsASign, L"itsASign", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::ironBelly = (new Achievement(eAward_ironBelly, L"ironBelly", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::haveAShearfulDay = (new Achievement(eAward_haveAShearfulDay, L"haveAShearfulDay", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::rainbowCollection = (new Achievement(eAward_rainbowCollection, L"rainbowCollection", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::stayinFrosty = (new Achievement(eAward_stayinFrosty, L"stayingFrosty", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::chestfulOfCobblestone = (new Achievement(eAward_chestfulOfCobblestone, L"chestfulOfCobblestone", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
Achievements::renewableEnergy = (new Achievement(eAward_renewableEnergy, L"renewableEnergy", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::musicToMyEars = (new Achievement(eAward_musicToMyEars, L"musicToMyEars", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::bodyGuard = (new Achievement(eAward_bodyGuard, L"bodyGuard", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::ironMan = (new Achievement(eAward_ironMan, L"ironMan", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::zombieDoctor = (new Achievement(eAward_zombieDoctor, L"zombieDoctor", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
Achievements::lionTamer = (new Achievement(eAward_lionTamer, L"lionTamer", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
#endif
}
// Static { System.out.println(achievements.size() + " achievements"); } TODO
void Achievements::init()
{
}
+92
View File
@@ -0,0 +1,92 @@
#pragma once
using namespace std;
class Achievement;
class Achievements
{
friend class Achievement;
protected:
static const int ACHIEVEMENT_OFFSET;
// maximum position of achievements (min and max)
public:
static const int ACHIEVEMENT_WIDTH_POSITION = 12;
static const int ACHIEVEMENT_HEIGHT_POSITION = 12;
static int xMin, yMin, xMax, yMax;
static vector<Achievement *> *achievements;
static Achievement *openInventory;
static Achievement *mineWood;
static Achievement *buildWorkbench;
static Achievement *buildPickaxe;
static Achievement *buildFurnace;
static Achievement *acquireIron;
static Achievement *buildHoe;
static Achievement *makeBread;
static Achievement *bakeCake;
static Achievement *buildBetterPickaxe;
static Achievement *cookFish;
static Achievement *onARail;
static Achievement *buildSword;
static Achievement *killEnemy;
static Achievement *killCow;
static Achievement *flyPig;
// 4J-JEV: Present on the PS3.
static Achievement *snipeSkeleton;
static Achievement *diamonds;
//static Achievement *portal; //4J-JEV: Whats this?
static Achievement *ghast;
static Achievement *blazeRod;
static Achievement *potion;
static Achievement *theEnd;
static Achievement *winGame;
static Achievement *enchantments;
// 4J : WESTY : Added new acheivements.
static Achievement *leaderOfThePack;
static Achievement *MOARTools;
static Achievement *dispenseWithThis;
static Achievement *InToTheNether;
// 4J : WESTY : Added other awards.
static Achievement *socialPost;
static Achievement *eatPorkChop;
static Achievement *play100Days;
static Achievement *arrowKillCreeper;
static Achievement *mine100Blocks;
static Achievement *kill10Creepers;
#ifdef _EXTENDED_ACHIEVEMENTS
static Achievement *overkill; // Old achievements;
static Achievement *bookcase; // Old achievements;
static Achievement *adventuringTime;
static Achievement *repopulation;
static Achievement *diamondsToYou;
static Achievement *passingTheTime;
static Achievement *archer;
static Achievement *theHaggler;
static Achievement *potPlanter;
static Achievement *itsASign;
static Achievement *ironBelly;
static Achievement *haveAShearfulDay;
static Achievement *rainbowCollection;
static Achievement *stayinFrosty;
static Achievement *chestfulOfCobblestone;
static Achievement *renewableEnergy;
static Achievement *musicToMyEars;
static Achievement *bodyGuard;
static Achievement *ironMan;
static Achievement *zombieDoctor;
static Achievement *lionTamer;
#endif
static void staticCtor();
static void init();
};
+111
View File
@@ -0,0 +1,111 @@
#include "stdafx.h"
#include <exception>
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.h"
#include "PacketListener.h"
#include "AddEntityPacket.h"
void AddEntityPacket::_init(shared_ptr<Entity> e, int type, int data, int xp, int yp, int zp, int yRotp, int xRotp)
{
id = e->entityId;
// 4J Stu - We should add entities at their "last sent" position so that the relative update packets
// put them in the correct place
x = xp;//(int) floor(e->x * 32);
y = yp;//(int) floor(e->y * 32);
z = zp;//(int) floor(e->z * 32);
yRot = yRotp;
xRot = xRotp;
this->type = type;
this->data = data;
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
{
double xd = e->xd;
double yd = e->yd;
double zd = e->zd;
double m = 3.9;
if (xd < -m) xd = -m;
if (yd < -m) yd = -m;
if (zd < -m) zd = -m;
if (xd > m) xd = m;
if (yd > m) yd = m;
if (zd > m) zd = m;
xa = (int) (xd * 8000.0);
ya = (int) (yd * 8000.0);
za = (int) (zd * 8000.0);
}
}
AddEntityPacket::AddEntityPacket()
{
}
AddEntityPacket::AddEntityPacket(shared_ptr<Entity> e, int type, int yRotp, int xRotp, int xp, int yp, int zp )
{
_init(e, type, -1, xp, yp, zp, yRotp, xRotp); // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
}
AddEntityPacket::AddEntityPacket(shared_ptr<Entity> e, int type, int data, int yRotp, int xRotp, int xp, int yp, int zp )
{
_init(e, type, data, xp, yp, zp, yRotp, xRotp);
}
void AddEntityPacket::read(DataInputStream *dis) // throws IOException TODO 4J JEV add throws statement
{
id = dis->readShort();
type = dis->readByte();
#ifdef _LARGE_WORLDS
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
#else
x = dis->readShort();
y = dis->readShort();
z = dis->readShort();
#endif
yRot = dis->readByte();
xRot = dis->readByte();
data = dis->readInt();
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
{
xa = dis->readShort();
ya = dis->readShort();
za = dis->readShort();
}
}
void AddEntityPacket::write(DataOutputStream *dos) // throws IOException TODO 4J JEV add throws statement
{
dos->writeShort(id);
dos->writeByte(type);
#ifdef _LARGE_WORLDS
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
#else
dos->writeShort(x);
dos->writeShort(y);
dos->writeShort(z);
#endif
dos->writeByte(yRot);
dos->writeByte(xRot);
dos->writeInt(data);
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
{
dos->writeShort(xa);
dos->writeShort(ya);
dos->writeShort(za);
}
}
void AddEntityPacket::handle(PacketListener *listener)
{
listener->handleAddEntity(shared_from_this());
}
int AddEntityPacket::getEstimatedSize()
{
return 11 + data > -1 ? 6 : 0;
}
+57
View File
@@ -0,0 +1,57 @@
#pragma once
using namespace std;
#include "Packet.h"
class AddEntityPacket : public Packet, public enable_shared_from_this<AddEntityPacket>
{
public:
static const int BOAT = 1;
static const int ITEM = 2;
static const int MINECART = 10;
static const int PRIMED_TNT = 50;
static const int ENDER_CRYSTAL = 51;
static const int ARROW = 60;
static const int SNOWBALL = 61;
static const int EGG = 62;
static const int FIREBALL = 63;
static const int SMALL_FIREBALL = 64;
static const int THROWN_ENDERPEARL = 65;
static const int WITHER_SKULL = 66;
static const int FALLING = 70;
static const int ITEM_FRAME = 71;
static const int EYEOFENDERSIGNAL = 72;
static const int THROWN_POTION = 73;
static const int FALLING_EGG = 74;
static const int THROWN_EXPBOTTLE = 75;
static const int FIREWORKS = 76;
static const int LEASH_KNOT = 77;
static const int FISH_HOOK = 90;
// 4J Added TU9
static const int DRAGON_FIRE_BALL = 200;
int id;
int x, y, z;
int xa, ya, za;
int type;
int data;
byte yRot,xRot; // 4J added
private:
void _init(shared_ptr<Entity> e, int type, int data, int xp, int yp, int zp, int yRotp, int xRotp );
public:
AddEntityPacket();
AddEntityPacket(shared_ptr<Entity> e, int type, int yRotp, int xRotp, int xp, int yp, int zp);
AddEntityPacket(shared_ptr<Entity> e, int type, int data, int yRotp, int xRotp, int xp, int yp, int zp );
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddEntityPacket()); }
virtual int getId() { return 23; }
};
@@ -0,0 +1,51 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.h"
#include "InputOutputStream.h"
#include "PacketListener.h"
#include "AddExperienceOrbPacket.h"
AddExperienceOrbPacket::AddExperienceOrbPacket()
{
id = 0;
x = y = z = 0;
value = 0;
}
AddExperienceOrbPacket::AddExperienceOrbPacket(shared_ptr<ExperienceOrb> e)
{
id = e->entityId;
x = Mth::floor(e->x * 32);
y = Mth::floor(e->y * 32);
z = Mth::floor(e->z * 32);
value = e->getValue();
}
void AddExperienceOrbPacket::read(DataInputStream *dis)
{
id = dis->readInt();
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
value = dis->readShort();
}
void AddExperienceOrbPacket::write(DataOutputStream *dos)
{
dos->writeInt(id);
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
dos->writeShort(value);
}
void AddExperienceOrbPacket::handle(PacketListener *listener)
{
listener->handleAddExperienceOrb(shared_from_this());
}
int AddExperienceOrbPacket::getEstimatedSize()
{
return 18;
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "Packet.h"
class ExperienceOrb;
class AddExperienceOrbPacket : public Packet, public enable_shared_from_this<AddExperienceOrbPacket>
{
public:
int id;
int x, y, z;
int value;
AddExperienceOrbPacket();
AddExperienceOrbPacket(shared_ptr<ExperienceOrb> e);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddExperienceOrbPacket()); }
virtual int getId() { return 26; }
};
+65
View File
@@ -0,0 +1,65 @@
#include "stdafx.h"
#include <exception>
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.global.h"
#include "PacketListener.h"
#include "AddGlobalEntityPacket.h"
const int AddGlobalEntityPacket::LIGHTNING = 1;
AddGlobalEntityPacket::AddGlobalEntityPacket()
{
id = -1;
x = 0;
y = 0;
x = 0;
type = 0;
}
AddGlobalEntityPacket::AddGlobalEntityPacket(shared_ptr<Entity> e)
{
id = e->entityId;
x = Mth::floor(e->x * 32);
y = Mth::floor(e->y * 32);
z = Mth::floor(e->z * 32);
if ( e->instanceof(eTYPE_LIGHTNINGBOLT) )
{
type = LIGHTNING;
}
else
{
type = 0;
}
}
void AddGlobalEntityPacket::read(DataInputStream *dis) // throws IOException
{
id = dis->readInt();
type = dis->readByte();
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
}
void AddGlobalEntityPacket::write(DataOutputStream *dos) // throws IOException
{
dos->writeInt(id);
dos->writeByte(type);
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
}
void AddGlobalEntityPacket::handle(PacketListener *listener)
{
listener->handleAddGlobalEntity(shared_from_this());
}
int AddGlobalEntityPacket::getEstimatedSize()
{
return 17;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "Packet.h"
class AddGlobalEntityPacket : public Packet, public enable_shared_from_this<AddGlobalEntityPacket>
{
public:
static const int LIGHTNING;
int id;
int x, y, z;
int type;
AddGlobalEntityPacket();
AddGlobalEntityPacket(shared_ptr<Entity> e);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddGlobalEntityPacket()); }
virtual int getId() { return 71; }
};
+64
View File
@@ -0,0 +1,64 @@
#include "stdafx.h"
#include "net.minecraft.world.level.newbiome.layer.h"
#include "net.minecraft.world.level.biome.h"
AddIslandLayer::AddIslandLayer(__int64 seedMixup, shared_ptr<Layer>parent) : Layer(seedMixup)
{
this->parent = parent;
}
intArray AddIslandLayer::getArea(int xo, int yo, int w, int h)
{
int px = xo - 1;
int py = yo - 1;
int pw = w + 2;
int ph = h + 2;
intArray p = parent->getArea(px, py, pw, ph);
intArray result = IntCache::allocate(w * h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int n1 = p[(x + 0) + (y + 0) * pw];
int n2 = p[(x + 2) + (y + 0) * pw];
int n3 = p[(x + 0) + (y + 2) * pw];
int n4 = p[(x + 2) + (y + 2) * pw];
int c = p[(x + 1) + (y + 1) * pw];
initRandom(x + xo, y + yo);
if (c == 0 && (n1 != 0 || n2 != 0 || n3 != 0 || n4 != 0))
{
int odds = 1;
int swap = 1;
if (n1 != 0 && nextRandom(odds++) == 0) swap = n1;
if (n2 != 0 && nextRandom(odds++) == 0) swap = n2;
if (n3 != 0 && nextRandom(odds++) == 0) swap = n3;
if (n4 != 0 && nextRandom(odds++) == 0) swap = n4;
if (nextRandom(3) == 0)
{
result[x + y * w] = swap;
}
else
{
if (swap == Biome::iceFlats->id) result[x + y * w] = Biome::frozenOcean->id;
else result[x + y * w] = 0;
}
}
else if (c > 0 && (n1 == 0 || n2 == 0 || n3 == 0 || n4 == 0))
{
if (nextRandom(5) == 0)
{
if (c == Biome::iceFlats->id) result[x + y * w] = Biome::frozenOcean->id;
else result[x + y * w] = 0;
}
else result[x + y * w] = c;
}
else
{
result[x + y * w] = c;
}
}
}
return result;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "Layer.h"
class AddIslandLayer : public Layer
{
public:
AddIslandLayer(__int64 seedMixup, shared_ptr<Layer>parent);
intArray getArea(int xo, int yo, int w, int h);
};
+140
View File
@@ -0,0 +1,140 @@
#include "stdafx.h"
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.h"
#include "PacketListener.h"
#include "AddMobPacket.h"
AddMobPacket::AddMobPacket()
{
id = -1;
type = 0;
x = 0;
y = 0;
z = 0;
yRot = 0;
xRot = 0;
entityData = nullptr;
unpack = NULL;
}
AddMobPacket::~AddMobPacket()
{
delete unpack;
}
AddMobPacket::AddMobPacket(shared_ptr<LivingEntity> mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp)
{
id = mob->entityId;
type = (byte) EntityIO::getId(mob);
// 4J Stu - We should add entities at their "last sent" position so that the relative update packets
// put them in the correct place
x = xp;//Mth::floor(mob->x * 32);
y = yp;//Mth::floor(mob->y * 32);
z = zp;//Mth::floor(mob->z * 32);
// 4J - changed - send current "previously sent" value of rotations to put this in sync with other clients
yRot = yRotp;
xRot = xRotp;
yHeadRot = yHeadRotp;
// yRot = (byte) (mob->yRot * 256 / 360);
// xRot = (byte) (mob->xRot * 256 / 360);
// yHeadRot = (byte) (mob->yHeadRot * 256 / 360);
// From SetEntityMotionpacket
double m = 3.9;
double xd = mob->xd;
double yd = mob->yd;
double zd = mob->zd;
if (xd < -m) xd = -m;
if (yd < -m) yd = -m;
if (zd < -m) zd = -m;
if (xd > m) xd = m;
if (yd > m) yd = m;
if (zd > m) zd = m;
this->xd = (int) (xd * 8000.0);
this->yd = (int) (yd * 8000.0);
this->zd = (int) (zd * 8000.0);
// printf("%d: New add mob rot %d\n",id,yRot);
entityData = mob->getEntityData();
unpack = NULL;
}
void AddMobPacket::read(DataInputStream *dis) //throws IOException
{
id = dis->readShort();
type = dis->readByte() & 0xff;
#ifdef _LARGE_WORLDS
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
#else
x = dis->readShort();
y = dis->readShort();
z = dis->readShort();
#endif
yRot = dis->readByte();
xRot = dis->readByte();
yHeadRot = dis->readByte();
xd = dis->readShort();
yd = dis->readShort();
zd = dis->readShort();
MemSect(1);
unpack = SynchedEntityData::unpack(dis);
MemSect(0);
}
void AddMobPacket::write(DataOutputStream *dos) //throws IOException
{
dos->writeShort(id);
dos->writeByte(type & 0xff);
#ifdef _LARGE_WORLDS
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
#else
dos->writeShort(x);
dos->writeShort(y);
dos->writeShort(z);
#endif
dos->writeByte(yRot);
dos->writeByte(xRot);
dos->writeByte(yHeadRot);
dos->writeShort(xd);
dos->writeShort(yd);
dos->writeShort(zd);
entityData->packAll(dos);
}
void AddMobPacket::handle(PacketListener *listener)
{
listener->handleAddMob(shared_from_this());
}
int AddMobPacket::getEstimatedSize()
{
int size = 11;
if( entityData != NULL )
{
size += entityData->getSizeInBytes();
}
else if( unpack != NULL )
{
// 4J Stu - This is an incoming value which we aren't currently analysing
//size += unpack->get
}
return size;
}
vector<shared_ptr<SynchedEntityData::DataItem> > *AddMobPacket::getUnpackedData()
{
if (unpack == NULL)
{
unpack = entityData->getAll();
}
return unpack;
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
using namespace std;
#include "Packet.h"
#include "SynchedEntityData.h"
class LivingEntity;
class AddMobPacket : public Packet, public enable_shared_from_this<AddMobPacket>
{
public:
int id;
int type;
int x, y, z;
int xd, yd, zd;
byte yRot, xRot, yHeadRot;
private:
shared_ptr<SynchedEntityData> entityData;
vector<shared_ptr<SynchedEntityData::DataItem> > *unpack;
public:
AddMobPacket();
~AddMobPacket();
AddMobPacket(shared_ptr<LivingEntity> mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
vector<shared_ptr<SynchedEntityData::DataItem> > *getUnpackedData();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddMobPacket()); }
virtual int getId() { return 24; }
};
@@ -0,0 +1,41 @@
#include "stdafx.h"
#include "net.minecraft.world.level.newbiome.layer.h"
#include "net.minecraft.world.level.biome.h"
AddMushroomIslandLayer::AddMushroomIslandLayer(__int64 seedMixup, shared_ptr<Layer> parent) : Layer(seedMixup)
{
this->parent = parent;
}
intArray AddMushroomIslandLayer::getArea(int xo, int yo, int w, int h)
{
int px = xo - 1;
int py = yo - 1;
int pw = w + 2;
int ph = h + 2;
intArray p = parent->getArea(px, py, pw, ph);
intArray result = IntCache::allocate(w * h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int n1 = p[(x + 0) + (y + 0) * pw];
int n2 = p[(x + 2) + (y + 0) * pw];
int n3 = p[(x + 0) + (y + 2) * pw];
int n4 = p[(x + 2) + (y + 2) * pw];
int c = p[(x + 1) + (y + 1) * pw];
initRandom(x + xo, y + yo);
if (c == 0 && (n1 == 0 && n2 == 0 && n3 == 0 && n4 == 0) && nextRandom(100) == 0)
{
result[x + y * w] = Biome::mushroomIsland->id;
}
else
{
result[x + y * w] = c;
}
}
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "Layer.h"
class AddMushroomIslandLayer : public Layer
{
public:
AddMushroomIslandLayer(__int64 seedMixup, shared_ptr<Layer> parent);
virtual intArray getArea(int xo, int yo, int w, int h);
};
+58
View File
@@ -0,0 +1,58 @@
#include "stdafx.h"
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.h"
#include "PacketListener.h"
#include "AddPaintingPacket.h"
AddPaintingPacket::AddPaintingPacket()
{
id = -1;
x = 0;
y = 0;
z = 0;
dir = 0;
motive = L"";
}
AddPaintingPacket::AddPaintingPacket(shared_ptr<Painting> e)
{
id = e->entityId;
x = e->xTile;
y = e->yTile;
z = e->zTile;
dir = e->dir;
motive = e->motive->name;
}
void AddPaintingPacket::read(DataInputStream *dis) //throws IOException
{
id = dis->readInt();
motive = readUtf(dis, Painting::Motive::MAX_MOTIVE_NAME_LENGTH);
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
dir = dis->readInt();
}
void AddPaintingPacket::write(DataOutputStream *dos) //throws IOException
{
dos->writeInt(id);
writeUtf(motive, dos);
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
dos->writeInt(dir);
}
void AddPaintingPacket::handle(PacketListener *listener)
{
listener->handleAddPainting(shared_from_this());
}
int AddPaintingPacket::getEstimatedSize()
{
return 24;
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
using namespace std;
#include "Packet.h"
class Painting;
class AddPaintingPacket : public Packet, public enable_shared_from_this<AddPaintingPacket>
{
public:
int id;
int x, y, z;
int dir;
wstring motive;
public:
AddPaintingPacket();
AddPaintingPacket(shared_ptr<Painting> e);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddPaintingPacket()); }
virtual int getId() { return 25; }
};
+142
View File
@@ -0,0 +1,142 @@
#include "stdafx.h"
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.item.h"
#include "PacketListener.h"
#include "AddPlayerPacket.h"
AddPlayerPacket::AddPlayerPacket()
{
id = -1;
name = L"";
x = 0;
y = 0;
z = 0;
yRot = 0;
xRot = 0;
carriedItem = 0;
xuid = INVALID_XUID;
m_playerIndex = 0;
m_skinId = 0;
m_capeId = 0;
m_uiGamePrivileges = 0;
entityData = nullptr;
unpack = NULL;
}
AddPlayerPacket::~AddPlayerPacket()
{
if(unpack != NULL) delete unpack;
}
AddPlayerPacket::AddPlayerPacket(shared_ptr<Player> player, PlayerUID xuid, PlayerUID OnlineXuid,int xp, int yp, int zp, int yRotp, int xRotp, int yHeadRotp)
{
id = player->entityId;
name = player->getName();
// 4J Stu - Send "previously sent" value of position as well so that we stay in sync
x = xp;//Mth::floor(player->x * 32);
y = yp;//Mth::floor(player->y * 32);
z = zp;//Mth::floor(player->z * 32);
// 4J - changed - send current "previously sent" value of rotations to put this in sync with other clients
yRot = yRotp;
xRot = xRotp;
yHeadRot = yHeadRotp; // 4J Added
// yRot = (byte) (player->yRot * 256 / 360);
// xRot = (byte) (player->xRot * 256 / 360);
//printf("%d: New add player (%f,%f,%f) : (%d,%d,%d) : xRot %d, yRot %d\n",id,player->x,player->y,player->z,x,y,z,xRot,yRot);
shared_ptr<ItemInstance> itemInstance = player->inventory->getSelected();
carriedItem = itemInstance == NULL ? 0 : itemInstance->id;
this->xuid = xuid;
this->OnlineXuid = OnlineXuid;
m_playerIndex = (BYTE)player->getPlayerIndex();
m_skinId = player->getCustomSkin();
m_capeId = player->getCustomCape();
m_uiGamePrivileges = player->getAllPlayerGamePrivileges();
entityData = player->getEntityData();
unpack = NULL;
}
void AddPlayerPacket::read(DataInputStream *dis) //throws IOException
{
id = dis->readInt();
name = readUtf(dis, Player::MAX_NAME_LENGTH);
x = dis->readInt();
y = dis->readInt();
z = dis->readInt();
yRot = dis->readByte();
xRot = dis->readByte();
yHeadRot = dis->readByte(); // 4J Added
carriedItem = dis->readShort();
xuid = dis->readPlayerUID();
OnlineXuid = dis->readPlayerUID();
m_playerIndex = dis->readByte();
INT skinId = dis->readInt();
m_skinId = *(DWORD *)&skinId;
INT capeId = dis->readInt();
m_capeId = *(DWORD *)&capeId;
INT privileges = dis->readInt();
m_uiGamePrivileges = *(unsigned int *)&privileges;
MemSect(1);
unpack = SynchedEntityData::unpack(dis);
MemSect(0);
}
void AddPlayerPacket::write(DataOutputStream *dos) //throws IOException
{
dos->writeInt(id);
writeUtf(name, dos);
dos->writeInt(x);
dos->writeInt(y);
dos->writeInt(z);
dos->writeByte(yRot);
dos->writeByte(xRot);
dos->writeByte(yHeadRot); // 4J Added
dos->writeShort(carriedItem);
dos->writePlayerUID(xuid);
dos->writePlayerUID(OnlineXuid);
dos->writeByte(m_playerIndex);
dos->writeInt(m_skinId);
dos->writeInt(m_capeId);
dos->writeInt(m_uiGamePrivileges);
entityData->packAll(dos);
}
void AddPlayerPacket::handle(PacketListener *listener)
{
listener->handleAddPlayer(shared_from_this());
}
int AddPlayerPacket::getEstimatedSize()
{
int iSize= sizeof(int) + Player::MAX_NAME_LENGTH + sizeof(int) + sizeof(int) + sizeof(int) + sizeof(BYTE) + sizeof(BYTE) +sizeof(short) + sizeof(PlayerUID) + sizeof(PlayerUID) + sizeof(int) + sizeof(BYTE) + sizeof(unsigned int) + sizeof(byte);
if( entityData != NULL )
{
iSize += entityData->getSizeInBytes();
}
else if( unpack != NULL )
{
// 4J Stu - This is an incoming value which we aren't currently analysing
//iSize += unpack->get
}
return iSize;
}
vector<shared_ptr<SynchedEntityData::DataItem> > *AddPlayerPacket::getUnpackedData()
{
if (unpack == NULL)
{
unpack = entityData->getAll();
}
return unpack;
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
using namespace std;
#include "Packet.h"
#include "SynchedEntityData.h"
class Player;
class AddPlayerPacket : public Packet, public enable_shared_from_this<AddPlayerPacket>
{
private:
shared_ptr<SynchedEntityData> entityData;
vector<shared_ptr<SynchedEntityData::DataItem> > *unpack;
public:
int id;
wstring name;
int x, y, z;
char yRot, xRot;
int carriedItem;
PlayerUID xuid; // 4J Added
PlayerUID OnlineXuid; // 4J Added
BYTE m_playerIndex; // 4J Added
DWORD m_skinId; // 4J Added
DWORD m_capeId; // 4J Added
unsigned int m_uiGamePrivileges; // 4J Added
byte yHeadRot; // 4J Added
AddPlayerPacket();
~AddPlayerPacket();
AddPlayerPacket(shared_ptr<Player> player, PlayerUID xuid, PlayerUID OnlineXuid,int xp, int yp, int zp, int yRotp, int xRotp, int yHeadRotp);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
vector<shared_ptr<SynchedEntityData::DataItem> > *getUnpackedData();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddPlayerPacket()); }
virtual int getId() { return 20; }
};
+39
View File
@@ -0,0 +1,39 @@
#include "stdafx.h"
#include "net.minecraft.world.level.newbiome.layer.h"
#include "net.minecraft.world.level.biome.h"
AddSnowLayer::AddSnowLayer(__int64 seedMixup, shared_ptr<Layer> parent) : Layer(seedMixup)
{
this->parent = parent;
}
intArray AddSnowLayer::getArea(int xo, int yo, int w, int h)
{
int px = xo - 1;
int py = yo - 1;
int pw = w + 2;
int ph = h + 2;
intArray p = parent->getArea(px, py, pw, ph);
intArray result = IntCache::allocate(w * h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int c = p[(x + 1) + (y + 1) * pw];
initRandom(x + xo, y + yo);
if (c == 0)
{
result[x + y * w] = 0;
}
else
{
int r = nextRandom(5);
if (r == 0) r = Biome::iceFlats->id;
else r = 1;
result[x + y * w] = r;
}
}
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "Layer.h"
class AddSnowLayer : public Layer
{
public:
AddSnowLayer(__int64 seedMixup, shared_ptr<Layer> parent);
virtual intArray getArea(int xo, int yo, int w, int h);
};
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "ChatPacket.h"
class CommandSender;
class AdminLogCommand
{
public:
static const int LOGTYPE_DONT_SHOW_TO_SELF = 1;
virtual void logAdminCommand(shared_ptr<CommandSender> source, int type, ChatPacket::EChatPacketMessage messageType, const wstring& message = L"", int customData = -1, const wstring& additionalMessage = L"") = 0;
};
+153
View File
@@ -0,0 +1,153 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.level.h"
#include "SynchedEntityData.h"
#include "GenericStats.h"
#include "AgableMob.h"
AgableMob::AgableMob(Level *level) : PathfinderMob(level)
{
registeredBBWidth = -1;
registeredBBHeight = 0;
}
bool AgableMob::mobInteract(shared_ptr<Player> player)
{
shared_ptr<ItemInstance> item = player->inventory->getSelected();
if (item != NULL && item->id == Item::spawnEgg_Id)
{
if (!level->isClientSide)
{
eINSTANCEOF classToSpawn = EntityIO::getClass(item->getAuxValue());
if (classToSpawn != eTYPE_NOTSET && (classToSpawn & eTYPE_AGABLE_MOB) == eTYPE_AGABLE_MOB && classToSpawn == GetType() ) // 4J Added GetType() check to only spawn same type
{
int error;
shared_ptr<Entity> result = SpawnEggItem::canSpawn(item->getAuxValue(), level, &error);
if (result != NULL)
{
shared_ptr<AgableMob> offspring = getBreedOffspring(dynamic_pointer_cast<AgableMob>(shared_from_this()));
if (offspring != NULL)
{
offspring->setAge(BABY_START_AGE);
offspring->moveTo(x, y, z, 0, 0);
level->addEntity(offspring);
if (!player->abilities.instabuild)
{
item->count--;
if (item->count <= 0)
{
player->inventory->setItem(player->inventory->selected, nullptr);
}
}
}
}
else
{
SpawnEggItem::DisplaySpawnError(player, error);
}
}
}
return true;
}
return false;
}
void AgableMob::defineSynchedData()
{
PathfinderMob::defineSynchedData();
entityData->define(DATA_AGE_ID, 0);
}
int AgableMob::getAge()
{
return entityData->getInteger(DATA_AGE_ID);
}
void AgableMob::ageUp(int seconds)
{
int age = getAge();
age += seconds * SharedConstants::TICKS_PER_SECOND;
if (age > 0)
{
age = 0;
}
setAge(age);
}
void AgableMob::setAge(int age)
{
entityData->set(DATA_AGE_ID, age);
updateSize(isBaby());
}
void AgableMob::addAdditonalSaveData(CompoundTag *tag)
{
PathfinderMob::addAdditonalSaveData(tag);
tag->putInt(L"Age", getAge());
}
void AgableMob::readAdditionalSaveData(CompoundTag *tag)
{
PathfinderMob::readAdditionalSaveData(tag);
setAge(tag->getInt(L"Age"));
}
void AgableMob::aiStep()
{
PathfinderMob::aiStep();
if(level->isClientSide)
{
updateSize(isBaby());
}
else
{
int age = getAge();
if (age < 0)
{
age++;
setAge(age);
}
else if (age > 0)
{
age--;
setAge(age);
}
}
}
bool AgableMob::isBaby()
{
return getAge() < 0;
}
void AgableMob::updateSize(bool isBaby)
{
internalSetSize(isBaby ? .5f : 1.0f);
}
void AgableMob::setSize(float w, float h)
{
bool inited = registeredBBWidth > 0;
registeredBBWidth = w;
registeredBBHeight = h;
if (!inited)
{
internalSetSize(1.0f);
}
}
void AgableMob::internalSetSize(float scale)
{
PathfinderMob::setSize(registeredBBWidth * scale, registeredBBHeight * scale);
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "PathfinderMob.h"
class AgableMob : public PathfinderMob
{
private:
static const int DATA_AGE_ID = 12;
public:
static const int BABY_START_AGE = -20 * 60 * 20;
private:
float registeredBBWidth;
float registeredBBHeight;
public:
AgableMob(Level *level);
virtual bool mobInteract(shared_ptr<Player> player);
protected:
virtual void defineSynchedData();
public:
virtual shared_ptr<AgableMob> getBreedOffspring(shared_ptr<AgableMob> target) = 0;
virtual int getAge();
virtual void ageUp(int seconds);
virtual void setAge(int age);
virtual void addAdditonalSaveData(CompoundTag *tag);
virtual void readAdditionalSaveData(CompoundTag *tag);
virtual void aiStep();
virtual bool isBaby();
virtual void updateSize(bool isBaby);
protected:
virtual void setSize(float w, float h);
void internalSetSize(float scale);
};
+6
View File
@@ -0,0 +1,6 @@
#include "stdafx.h"
#include "AirTile.h"
AirTile::AirTile(int id) : Tile(id, Material::air)
{
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "Tile.h"
#include "Material.h"
class AirTile : public Tile
{
friend class Tile;
protected:
AirTile(int id);
};
+17
View File
@@ -0,0 +1,17 @@
#include "stdafx.h"
#include "AmbientCreature.h"
AmbientCreature::AmbientCreature(Level *level) : Mob(level)
{
}
bool AmbientCreature::canBeLeashed()
{
return false;
}
bool AmbientCreature::mobInteract(shared_ptr<Player> player)
{
return false;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "Mob.h"
#include "Creature.h"
class AmbientCreature : public Mob, public Creature
{
public:
AmbientCreature(Level *level);
virtual bool canBeLeashed();
protected:
virtual bool mobInteract(shared_ptr<Player> player);
};
+489
View File
@@ -0,0 +1,489 @@
#include "stdafx.h"
#include "com.mojang.nbt.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.phys.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.storage.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.projectile.h"
#include "net.minecraft.world.damagesource.h"
#include "net.minecraft.world.entity.monster.h"
#include "net.minecraft.world.entity.ai.attributes.h"
#include "Random.h"
#include "Animal.h"
Animal::Animal(Level *level) : AgableMob( level )
{
// inLove = 0; // 4J removed - now synched data
loveTime = 0;
loveCause = shared_ptr<Player>();
setDespawnProtected();
}
void Animal::defineSynchedData()
{
AgableMob::defineSynchedData();
entityData->define(DATA_IN_LOVE, (int)0); // 4J added
}
void Animal::serverAiMobStep()
{
if (getAge() != 0) setInLoveValue(0);
AgableMob::serverAiMobStep();
}
void Animal::aiStep()
{
AgableMob::aiStep();
if (getAge() != 0) setInLoveValue(0);
if (getInLoveValue() > 0)
{
setInLoveValue(getInLoveValue()-1);
if (getInLoveValue() % 10 == 0)
{
double xa = random->nextGaussian() * 0.02;
double ya = random->nextGaussian() * 0.02;
double za = random->nextGaussian() * 0.02;
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
}
}
else
{
loveTime = 0;
}
updateDespawnProtectedState(); // 4J added
}
void Animal::checkHurtTarget(shared_ptr<Entity> target, float d)
{
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
if ( target->instanceof(eTYPE_PLAYER) )
{
if (d < 3)
{
double xd = target->x - x;
double zd = target->z - z;
yRot = (float) (atan2(zd, xd) * 180 / PI) - 90;
holdGround = true;
}
shared_ptr<Player> p = dynamic_pointer_cast<Player>(target);
if (p->getSelectedItem() == NULL || !isFood(p->getSelectedItem()))
{
attackTarget = nullptr;
}
}
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
else if ( target->instanceof(eTYPE_ANIMAL) )
{
shared_ptr<Animal> a = dynamic_pointer_cast<Animal>(target);
if (getAge() > 0 && a->getAge() < 0)
{
if (d < 2.5)
{
holdGround = true;
}
}
else if (getInLoveValue() > 0 && a->getInLoveValue() > 0)
{
if (a->attackTarget == NULL) a->attackTarget = shared_from_this();
if (a->attackTarget == shared_from_this() && d < 3.5)
{
a->setInLoveValue(a->getInLoveValue()+1);
setInLoveValue(getInLoveValue()+1);
loveTime++;
if (loveTime % 4 == 0)
{
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, 0, 0, 0);
}
if (loveTime == 20 * 3) breedWith(a);
}
else loveTime = 0;
}
else
{
loveTime = 0;
attackTarget = nullptr;
}
}
}
void Animal::breedWith(shared_ptr<Animal> target)
{
shared_ptr<AgableMob> offspring = getBreedOffspring(target);
setInLoveValue(0);
loveTime = 0;
attackTarget = nullptr;
target->attackTarget = nullptr;
target->loveTime = 0;
target->setInLoveValue(0);
// 4J - we have offspring of NULL returned when we have hit our limits of spawning any particular type of animal. In these cases try and do everything we can apart from actually
// spawning the entity.
if (offspring != NULL)
{
// Only want to set the age to this +ve value if something is actually spawned, as during this period the animal will attempt to follow offspring and ignore players.
setAge(5 * 60 * 20);
target->setAge(5 * 60 * 20);
offspring->setAge(-20 * 60 * 20);
offspring->moveTo(x, y, z, yRot, xRot);
offspring->setDespawnProtected();
for (int i = 0; i < 7; i++)
{
double xa = random->nextGaussian() * 0.02;
double ya = random->nextGaussian() * 0.02;
double za = random->nextGaussian() * 0.02;
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
}
level->addEntity(offspring);
level->addEntity( shared_ptr<ExperienceOrb>( new ExperienceOrb(level, x, y, z, random->nextInt(4) + 1) ) );
}
setDespawnProtected();
}
float Animal::getWalkTargetValue(int x, int y, int z)
{
if (level->getTile(x, y - 1, z) == Tile::grass_Id) return 10;
return level->getBrightness(x, y, z) - 0.5f;
}
bool Animal::hurt(DamageSource *dmgSource, float dmg)
{
if (isInvulnerable()) return false;
if (dynamic_cast<EntityDamageSource *>(dmgSource) != NULL)
{
shared_ptr<Entity> source = dmgSource->getDirectEntity();
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
if ( source->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(source)->isAllowedToAttackAnimals() )
{
return false;
}
if ( (source != NULL) && source->instanceof(eTYPE_ARROW) )
{
shared_ptr<Arrow> arrow = dynamic_pointer_cast<Arrow>(source);
// 4J: Check that the arrow's owner can attack animals (dispenser arrows are not owned)
if (arrow->owner != NULL && arrow->owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(arrow->owner)->isAllowedToAttackAnimals() )
{
return false;
}
}
}
fleeTime = 20 * 3;
if (!useNewAi())
{
AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
if (speed->getModifier(eModifierId_MOB_FLEEING) == NULL)
{
speed->addModifier(new AttributeModifier(*Animal::SPEED_MODIFIER_FLEEING));
}
}
attackTarget = nullptr;
setInLoveValue(0);
return AgableMob::hurt(dmgSource, dmg);
}
void Animal::addAdditonalSaveData(CompoundTag *tag)
{
AgableMob::addAdditonalSaveData(tag);
tag->putInt(L"InLove", getInLoveValue());
}
void Animal::readAdditionalSaveData(CompoundTag *tag)
{
AgableMob::readAdditionalSaveData(tag);
setInLoveValue(tag->getInt(L"InLove"));
setDespawnProtected();
}
shared_ptr<Entity> Animal::findAttackTarget()
{
if (fleeTime > 0) return nullptr;
float r = 8;
if (getInLoveValue() > 0)
{
vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r));
//for (int i = 0; i < others->size(); i++)
for(AUTO_VAR(it, others->begin()); it != others->end(); ++it)
{
shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it);
if (p != shared_from_this() && p->getInLoveValue() > 0)
{
delete others;
return p;
}
}
delete others;
}
else
{
if (getAge() == 0)
{
vector<shared_ptr<Entity> > *players = level->getEntitiesOfClass(typeid(Player), bb->grow(r, r, r));
//for (int i = 0; i < players.size(); i++)
for(AUTO_VAR(it, players->begin()); it != players->end(); ++it)
{
setDespawnProtected();
shared_ptr<Player> p = dynamic_pointer_cast<Player>(*it);
if (p->getSelectedItem() != NULL && this->isFood(p->getSelectedItem()))
{
delete players;
return p;
}
}
delete players;
}
else if (getAge() > 0)
{
vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r));
//for (int i = 0; i < others.size(); i++)
for(AUTO_VAR(it, others->begin()); it != others->end(); ++it)
{
shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it);
if (p != shared_from_this() && p->getAge() < 0)
{
delete others;
return p;
}
}
delete others;
}
}
return nullptr;
}
bool Animal::canSpawn()
{
int xt = Mth::floor(x);
int yt = Mth::floor(bb->y0);
int zt = Mth::floor(z);
return level->getTile(xt, yt - 1, zt) == Tile::grass_Id && level->getDaytimeRawBrightness(xt, yt, zt) > 8 && AgableMob::canSpawn();
}
int Animal::getAmbientSoundInterval()
{
return 20 * 6;
}
bool Animal::removeWhenFarAway()
{
return !isDespawnProtected(); // 4J changed - was false
}
int Animal::getExperienceReward(shared_ptr<Player> killedBy)
{
return 1 + level->random->nextInt(3);
}
bool Animal::isFood(shared_ptr<ItemInstance> itemInstance)
{
return itemInstance->id == Item::wheat_Id;
}
bool Animal::mobInteract(shared_ptr<Player> player)
{
shared_ptr<ItemInstance> item = player->inventory->getSelected();
if (item != NULL && isFood(item) && getAge() == 0 && getInLoveValue() <= 0)
{
if (!player->abilities.instabuild)
{
item->count--;
if (item->count <= 0)
{
player->inventory->setItem(player->inventory->selected, nullptr);
}
}
// 4J-PB - If we can't produce another animal through breeding because of the spawn limits, display a message here
if(!level->isClientSide)
{
switch(GetType())
{
case eTYPE_CHICKEN:
if( !level->canCreateMore(eTYPE_CHICKEN, Level::eSpawnType_Breed) )
{
player->displayClientMessage(IDS_MAX_CHICKENS_BRED );
return false;
}
break;
case eTYPE_WOLF:
if( !level->canCreateMore(eTYPE_WOLF, Level::eSpawnType_Breed) )
{
player->displayClientMessage(IDS_MAX_WOLVES_BRED );
return false;
}
break;
case eTYPE_MUSHROOMCOW:
if( !level->canCreateMore(eTYPE_MUSHROOMCOW, Level::eSpawnType_Breed) )
{
player->displayClientMessage(IDS_MAX_MUSHROOMCOWS_BRED );
return false;
}
break;
default:
if((GetType() & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK)
{
if( !level->canCreateMore(GetType(), Level::eSpawnType_Breed) )
{
player->displayClientMessage(IDS_MAX_PIGS_SHEEP_COWS_CATS_BRED );
return false;
}
}
else if( instanceof(eTYPE_MONSTER) )
{
}
break;
}
setInLove(player);
}
setInLove();
return true;
}
return AgableMob::mobInteract(player);
}
// 4J added
int Animal::getInLoveValue()
{
return entityData->getInteger(DATA_IN_LOVE);
}
void Animal::setInLoveValue(int value)
{
entityData->set(DATA_IN_LOVE, value);
}
// 4J added
void Animal::setInLove(shared_ptr<Player> player)
{
loveCause = player;
setInLoveValue(20*30);
}
shared_ptr<Player> Animal::getLoveCause()
{
return loveCause.lock();
}
void Animal::setInLove()
{
entityData->set(DATA_IN_LOVE, 20 * 30);
attackTarget = nullptr;
level->broadcastEntityEvent(shared_from_this(), EntityEvent::IN_LOVE_HEARTS);
}
bool Animal::isInLove()
{
return entityData->getInteger(DATA_IN_LOVE) > 0;
}
void Animal::resetLove() {
entityData->set(DATA_IN_LOVE, 0);
}
bool Animal::canMate(shared_ptr<Animal> partner)
{
if (partner == shared_from_this()) return false;
if (typeid(*partner) != typeid(*this)) return false;
return isInLove() && partner->isInLove();
}
void Animal::handleEntityEvent(byte id)
{
if (id == EntityEvent::IN_LOVE_HEARTS)
{
for (int i = 0; i < 7; i++)
{
double xa = random->nextGaussian() * 0.02;
double ya = random->nextGaussian() * 0.02;
double za = random->nextGaussian() * 0.02;
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
}
}
else
{
AgableMob::handleEntityEvent(id);
}
}
void Animal::updateDespawnProtectedState()
{
if( level->isClientSide ) return;
if( m_isDespawnProtected )
{
int xt = Mth::floor(x);
int zt = Mth::floor(z);
if ( xt > m_maxWanderX ) m_maxWanderX = xt;
if ( xt < m_minWanderX ) m_minWanderX = xt;
if ( zt > m_maxWanderZ ) m_maxWanderZ = zt;
if ( zt < m_minWanderZ ) m_minWanderZ = zt;
if( ( ( m_maxWanderX - m_minWanderX ) > MAX_WANDER_DISTANCE ) ||
( ( m_maxWanderZ - m_minWanderZ ) > MAX_WANDER_DISTANCE ) )
{
// printf("Unprotecting : %d to %d, %d to %d\n", m_minWanderX, m_maxWanderX, m_minWanderZ, m_maxWanderZ );
m_isDespawnProtected = false;
}
/*
if( isExtraWanderingEnabled() )
{
printf("%d: %d %d, %d\n",entityId,m_maxWanderX - m_minWanderX, m_maxWanderZ - m_minWanderZ, getWanderingQuadrant());
}
*/
}
}
bool Animal::isDespawnProtected()
{
return m_isDespawnProtected;
}
void Animal::setDespawnProtected()
{
if( level && level->isClientSide ) return;
int xt = Mth::floor(x);
int zt = Mth::floor(z);
m_minWanderX = xt;
m_maxWanderX = xt;
m_minWanderZ = zt;
m_maxWanderZ = zt;
m_isDespawnProtected = true;
}
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#include "AgableMob.h"
#include "Creature.h"
class Level;
class CompoundTag;
class DamageSource;
class Animal : public AgableMob, public Creature
{
private:
static const int DATA_IN_LOVE = 13; // 4J added
// int inLove; // 4J removed - now synched data
int loveTime;
weak_ptr<Player> loveCause;
public:
Animal(Level *level);
protected:
virtual void defineSynchedData();
virtual void serverAiMobStep();
public:
virtual void aiStep();
protected:
virtual void checkHurtTarget(shared_ptr<Entity> target, float d);
private:
virtual void breedWith(shared_ptr<Animal> target);
public:
virtual float getWalkTargetValue(int x, int y, int z);
public:
virtual bool hurt(DamageSource *source, float dmg);
virtual void addAdditonalSaveData(CompoundTag *tag);
virtual void readAdditionalSaveData(CompoundTag *tag);
protected:
virtual shared_ptr<Entity> findAttackTarget();
public:
virtual bool canSpawn();
virtual int getAmbientSoundInterval();
protected:
virtual bool removeWhenFarAway();
virtual int getExperienceReward(shared_ptr<Player> killedBy);
public:
virtual bool isFood(shared_ptr<ItemInstance> itemInstance);
virtual bool mobInteract(shared_ptr<Player> player);
protected:
int getInLoveValue(); // 4J added
public:
void setInLoveValue(int value); // 4J added
void setInLove(shared_ptr<Player> player); // 4J added, then modified to match latest Java for XboxOne achievements
virtual void setInLove();
shared_ptr<Player> getLoveCause();
bool isInLove();
void resetLove();
virtual bool canMate(shared_ptr<Animal> partner);
virtual void handleEntityEvent(byte id);
// 4J added for determining whether animals are enclosed or not
private:
bool m_isDespawnProtected;
static const int MAX_WANDER_DISTANCE = 20; // Maximum distance that the entity can wander before being considered as not enclosed & therefore not protected (in tiles)
short m_minWanderX, m_maxWanderX; // Bounding x values that this has moved since last being set to protected ( in tiles )
short m_minWanderZ, m_maxWanderZ; // Bounding z values that this has moved since last being set to protected ( in tiles )
void updateDespawnProtectedState();
public:
virtual bool isDespawnProtected();
virtual void setDespawnProtected();
};
+11
View File
@@ -0,0 +1,11 @@
#include "stdafx.h"
#include "AnimalChest.h"
AnimalChest::AnimalChest(const wstring &name, int size) : SimpleContainer(IDS_CONTAINER_ANIMAL, name, false, size)
{
}
AnimalChest::AnimalChest(int iTitle, const wstring &name, bool hasCustomName, int size) : SimpleContainer(iTitle, name, hasCustomName, size)
{
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "SimpleContainer.h"
class AnimalChest : public SimpleContainer
{
public:
AnimalChest(const wstring &name, int size);
AnimalChest(int iTitle, const wstring &name, bool hasCustomName, int size); // 4J Added iTitle param
};
+42
View File
@@ -0,0 +1,42 @@
#include "stdafx.h"
#include <iostream>
#include "InputOutputStream.h"
#include "net.minecraft.world.entity.h"
#include "PacketListener.h"
#include "AnimatePacket.h"
AnimatePacket::AnimatePacket()
{
id = -1;
action = 0;
}
AnimatePacket::AnimatePacket(shared_ptr<Entity> e, int action)
{
id = e->entityId;
this->action = action;
}
void AnimatePacket::read(DataInputStream *dis) //throws IOException
{
id = dis->readInt();
action = dis->readByte();
}
void AnimatePacket::write(DataOutputStream *dos) //throws IOException
{
dos->writeInt(id);
dos->writeByte(action);
}
void AnimatePacket::handle(PacketListener *listener)
{
listener->handleAnimate(shared_from_this());
}
int AnimatePacket::getEstimatedSize()
{
return 5;
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
using namespace std;
#include "Packet.h"
class AnimatePacket : public Packet, public enable_shared_from_this<AnimatePacket>
{
public:
static const int SWING = 1;
static const int HURT = 2;
static const int WAKE_UP = 3;
static const int RESPAWN = 4;
static const int EAT = 5; // 1.8.2
static const int CRITICAL_HIT = 6;
static const int MAGIC_CRITICAL_HIT = 7;
int id;
int action;
AnimatePacket();
AnimatePacket(shared_ptr<Entity> e, int action);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual void handle(PacketListener *listener);
virtual int getEstimatedSize();
public:
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AnimatePacket()); }
virtual int getId() { return 18; }
};
+426
View File
@@ -0,0 +1,426 @@
#include "stdafx.h"
#include "net.minecraft.world.inventory.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.item.enchantment.h"
#include "AnvilMenu.h"
AnvilMenu::AnvilMenu(shared_ptr<Inventory> inventory, Level *level, int xt, int yt, int zt, shared_ptr<Player> player)
{
resultSlots = shared_ptr<ResultContainer>( new ResultContainer() );
repairSlots = shared_ptr<RepairContainer>( new RepairContainer(this,IDS_REPAIR_AND_NAME, true, 2) );
cost = 0;
repairItemCountCost = 0;
this->level = level;
x = xt;
y = yt;
z = zt;
this->player = player;
addSlot(new Slot(repairSlots, INPUT_SLOT, 27, 43 + 4));
addSlot(new Slot(repairSlots, ADDITIONAL_SLOT, 76, 43 + 4));
// 4J Stu - Anonymous class here is now RepairResultSlot
addSlot(new RepairResultSlot(this, xt, yt, zt, resultSlots, RESULT_SLOT, 134, 43 + 4));
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 9; x++)
{
addSlot(new Slot(inventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18));
}
}
for (int x = 0; x < 9; x++)
{
addSlot(new Slot(inventory, x, 8 + x * 18, 142));
}
}
void AnvilMenu::slotsChanged(shared_ptr<Container> container)
{
AbstractContainerMenu::slotsChanged();
if (container == repairSlots) createResult();
}
void AnvilMenu::createResult()
{
shared_ptr<ItemInstance> input = repairSlots->getItem(INPUT_SLOT);
cost = 0;
int price = 0;
int tax = 0;
int namingCost = 0;
if (DEBUG_COST) app.DebugPrintf("----");
if (input == NULL)
{
resultSlots->setItem(0, nullptr);
cost = 0;
return;
}
else
{
shared_ptr<ItemInstance> result = input->copy();
shared_ptr<ItemInstance> addition = repairSlots->getItem(ADDITIONAL_SLOT);
unordered_map<int,int> *enchantments = EnchantmentHelper::getEnchantments(result);
bool usingBook = false;
tax += input->getBaseRepairCost() + (addition == NULL ? 0 : addition->getBaseRepairCost());
if (DEBUG_COST)
{
app.DebugPrintf("Starting with base repair tax of %d (%d + %d)\n", tax, input->getBaseRepairCost(), (addition == NULL ? 0 : addition->getBaseRepairCost()));
}
repairItemCountCost = 0;
if (addition != NULL)
{
usingBook = addition->id == Item::enchantedBook_Id && Item::enchantedBook->getEnchantments(addition)->size() > 0;
if (result->isDamageableItem() && Item::items[result->id]->isValidRepairItem(input, addition))
{
int repairAmount = min(result->getDamageValue(), result->getMaxDamage() / 4);
if (repairAmount <= 0)
{
resultSlots->setItem(0, nullptr);
cost = 0;
return;
}
else
{
int count = 0;
while (repairAmount > 0 && count < addition->count)
{
int resultDamage = result->getDamageValue() - repairAmount;
result->setAuxValue(resultDamage);
price += max(1, repairAmount / 100) + enchantments->size();
repairAmount = min(result->getDamageValue(), result->getMaxDamage() / 4);
count++;
}
repairItemCountCost = count;
}
}
else if (!usingBook && (result->id != addition->id || !result->isDamageableItem()))
{
resultSlots->setItem(0, nullptr);
cost = 0;
return;
}
else
{
if (result->isDamageableItem() && !usingBook)
{
int remaining1 = input->getMaxDamage() - input->getDamageValue();
int remaining2 = addition->getMaxDamage() - addition->getDamageValue();
int additional = remaining2 + result->getMaxDamage() * 12 / 100;
int remaining = remaining1 + additional;
int resultDamage = result->getMaxDamage() - remaining;
if (resultDamage < 0) resultDamage = 0;
if (resultDamage < result->getAuxValue())
{
result->setAuxValue(resultDamage);
price += max(1, additional / 100);
if (DEBUG_COST)
{
app.DebugPrintf("Repairing; price is now %d (went up by %d)\n", price, max(1, additional / 100) );
}
}
}
unordered_map<int, int> *additionalEnchantments = EnchantmentHelper::getEnchantments(addition);
for(AUTO_VAR(it, additionalEnchantments->begin()); it != additionalEnchantments->end(); ++it)
{
int id = it->first;
Enchantment *enchantment = Enchantment::enchantments[id];
AUTO_VAR(localIt, enchantments->find(id));
int current = localIt != enchantments->end() ? localIt->second : 0;
int level = it->second;
level = (current == level) ? level += 1 : max(level, current);
int extra = level - current;
bool compatible = enchantment->canEnchant(input);
if (player->abilities.instabuild || input->id == EnchantedBookItem::enchantedBook_Id) compatible = true;
for(AUTO_VAR(it2, enchantments->begin()); it2 != enchantments->end(); ++it2)
{
int other = it2->first;
if (other != id && !enchantment->isCompatibleWith(Enchantment::enchantments[other]))
{
compatible = false;
price += extra;
if (DEBUG_COST)
{
app.DebugPrintf("Enchantment incompatibility fee; price is now %d (went up by %d)\n", price, extra);
}
}
}
if (!compatible) continue;
if (level > enchantment->getMaxLevel()) level = enchantment->getMaxLevel();
(*enchantments)[id] = level;
int fee = 0;
switch (enchantment->getFrequency())
{
case Enchantment::FREQ_COMMON:
fee = 1;
break;
case Enchantment::FREQ_UNCOMMON:
fee = 2;
break;
case Enchantment::FREQ_RARE:
fee = 4;
break;
case Enchantment::FREQ_VERY_RARE:
fee = 8;
break;
}
if (usingBook) fee = max(1, fee / 2);
price += fee * extra;
if (DEBUG_COST)
{
app.DebugPrintf("Enchantment increase fee; price is now %d (went up by %d)\n", price, fee*extra);
}
}
delete additionalEnchantments;
}
}
if (itemName.empty())
{
if (input->hasCustomHoverName())
{
namingCost = input->isDamageableItem() ? 7 : input->count * 5;
price += namingCost;
if (DEBUG_COST)
{
app.DebugPrintf("Un-naming cost; price is now %d (went up by %d)", price, namingCost);
}
result->resetHoverName();
}
}
else if (itemName.length() > 0 && !equalsIgnoreCase(itemName, input->getHoverName()) && itemName.length() > 0)
{
namingCost = input->isDamageableItem() ? 7 : input->count * 5;
price += namingCost;
if (DEBUG_COST)
{
app.DebugPrintf("Naming cost; price is now %d (went up by %d)", price, namingCost);
}
if (input->hasCustomHoverName())
{
tax += namingCost / 2;
if (DEBUG_COST)
{
app.DebugPrintf("Already-named tax; tax is now %d (went up by %d)", tax, (namingCost / 2));
}
}
result->setHoverName(itemName);
}
int count = 0;
for(AUTO_VAR(it, enchantments->begin()); it != enchantments->end(); ++it)
{
int id = it->first;
Enchantment *enchantment = Enchantment::enchantments[id];
int level = it->second;
int fee = 0;
count++;
switch (enchantment->getFrequency())
{
case Enchantment::FREQ_COMMON:
fee = 1;
break;
case Enchantment::FREQ_UNCOMMON:
fee = 2;
break;
case Enchantment::FREQ_RARE:
fee = 4;
break;
case Enchantment::FREQ_VERY_RARE:
fee = 8;
break;
}
if (usingBook) fee = max(1, fee / 2);
tax += count + level * fee;
if (DEBUG_COST)
{
app.DebugPrintf("Enchantment tax; tax is now %d (went up by %d)", tax, (count + level * fee));
}
}
if (usingBook) tax = max(1, tax / 2);
cost = tax + price;
if (price <= 0)
{
if (DEBUG_COST) app.DebugPrintf("No purchase, only tax; aborting");
result = nullptr;
}
if (namingCost == price && namingCost > 0 && cost >= 40)
{
if (DEBUG_COST) app.DebugPrintf("Cost is too high; aborting");
app.DebugPrintf("Naming an item only, cost too high; giving discount to cap cost to 39 levels");
cost = 39;
}
if (cost >= 40 && !player->abilities.instabuild)
{
if (DEBUG_COST) app.DebugPrintf("Cost is too high; aborting");
result = nullptr;
}
if (result != NULL)
{
int baseCost = result->getBaseRepairCost();
if (addition != NULL && baseCost < addition->getBaseRepairCost()) baseCost = addition->getBaseRepairCost();
if (result->hasCustomHoverName()) baseCost -= 9;
if (baseCost < 0) baseCost = 0;
baseCost += 2;
result->setRepairCost(baseCost);
EnchantmentHelper::setEnchantments(enchantments, result);
}
resultSlots->setItem(0, result);
}
broadcastChanges();
if (DEBUG_COST)
{
if (level->isClientSide)
{
app.DebugPrintf("CLIENT Cost is %d (%d price, %d tax)\n", cost, price, tax);
}
else
{
app.DebugPrintf("SERVER Cost is %d (%d price, %d tax)\n", cost, price, tax);
}
}
}
void AnvilMenu::sendData(int id, int value)
{
AbstractContainerMenu::sendData(id, value);
}
void AnvilMenu::addSlotListener(ContainerListener *listener)
{
AbstractContainerMenu::addSlotListener(listener);
listener->setContainerData(this, DATA_TOTAL_COST, cost);
}
void AnvilMenu::setData(int id, int value)
{
if (id == DATA_TOTAL_COST) cost = value;
}
void AnvilMenu::removed(shared_ptr<Player> player)
{
AbstractContainerMenu::removed(player);
if (level->isClientSide) return;
for (int i = 0; i < repairSlots->getContainerSize(); i++)
{
shared_ptr<ItemInstance> item = repairSlots->removeItemNoUpdate(i);
if (item != NULL)
{
player->drop(item);
}
}
}
bool AnvilMenu::stillValid(shared_ptr<Player> player)
{
if (level->getTile(x, y, z) != Tile::anvil_Id) return false;
if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false;
return true;
}
shared_ptr<ItemInstance> AnvilMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex)
{
shared_ptr<ItemInstance> clicked = nullptr;
Slot *slot = slots.at(slotIndex);
if (slot != NULL && slot->hasItem())
{
shared_ptr<ItemInstance> stack = slot->getItem();
clicked = stack->copy();
if (slotIndex == RESULT_SLOT)
{
if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, true))
{
return nullptr;
}
slot->onQuickCraft(stack, clicked);
}
else if (slotIndex == INPUT_SLOT || slotIndex == ADDITIONAL_SLOT)
{
if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, false))
{
return nullptr;
}
}
else if (slotIndex >= INV_SLOT_START && slotIndex < USE_ROW_SLOT_END)
{
if (!moveItemStackTo(stack, INPUT_SLOT, RESULT_SLOT, false))
{
return nullptr;
}
}
if (stack->count == 0)
{
slot->set(nullptr);
}
else
{
slot->setChanged();
}
if (stack->count == clicked->count)
{
return nullptr;
}
else
{
slot->onTake(player, stack);
}
}
return clicked;
}
void AnvilMenu::setItemName(const wstring &name)
{
itemName = name;
if (getSlot(RESULT_SLOT)->hasItem())
{
shared_ptr<ItemInstance> item = getSlot(RESULT_SLOT)->getItem();
if (name.empty())
{
item->resetHoverName();
}
else
{
item->setHoverName(itemName);
}
}
createResult();
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "AbstractContainerMenu.h"
class AnvilMenu : public AbstractContainerMenu
{
friend class RepairResultSlot;
private:
static const bool DEBUG_COST = false;
public:
static const int INPUT_SLOT = 0;
static const int ADDITIONAL_SLOT = 1;
static const int RESULT_SLOT = 2;
static const int INV_SLOT_START = RESULT_SLOT + 1;
static const int INV_SLOT_END = INV_SLOT_START + 9 * 3;
static const int USE_ROW_SLOT_START = INV_SLOT_END;
static const int USE_ROW_SLOT_END = USE_ROW_SLOT_START + 9;
public:
static const int DATA_TOTAL_COST = 0;
private:
shared_ptr<Container> resultSlots;
// 4J Stu - anonymous class here now RepairContainer
shared_ptr<Container> repairSlots;
Level *level;
int x, y, z;
public:
int cost;
private:
int repairItemCountCost;
wstring itemName;
shared_ptr<Player> player;
public:
using AbstractContainerMenu::slotsChanged;
AnvilMenu(shared_ptr<Inventory> inventory, Level *level, int xt, int yt, int zt, shared_ptr<Player> player);
void slotsChanged(shared_ptr<Container> container);
void createResult();
void sendData(int id, int value);
void addSlotListener(ContainerListener *listener);
void setData(int id, int value);
void removed(shared_ptr<Player> player);
bool stillValid(shared_ptr<Player> player);
shared_ptr<ItemInstance> quickMoveStack(shared_ptr<Player> player, int slotIndex);
void setItemName(const wstring &name);
};
+117
View File
@@ -0,0 +1,117 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.entity.item.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.h"
#include "net.minecraft.h"
#include "AnvilTile.h"
const unsigned int AnvilTile::ANVIL_NAMES[ANVIL_NAMES_LENGTH] = { IDS_TILE_ANVIL_INTACT,
IDS_TILE_ANVIL_SLIGHTLYDAMAGED,
IDS_TILE_ANVIL_VERYDAMAGED,
};
wstring AnvilTile::TEXTURE_DAMAGE_NAMES[ANVIL_NAMES_LENGTH] = {
L"anvil_top", L"anvil_top_damaged_1", L"anvil_top_damaged_2"
};
AnvilTile::AnvilTile(int id) : HeavyTile(id, Material::heavyMetal, isSolidRender() )
{
part = PART_BASE;
setLightBlock(0);
icons = NULL;
}
bool AnvilTile::isCubeShaped()
{
return false;
}
bool AnvilTile::isSolidRender(bool isServerLevel)
{
return false;
}
Icon *AnvilTile::getTexture(int face, int data)
{
if (part == PART_TOP && face == Facing::UP)
{
int damage = (data >> 2) % ANVIL_NAMES_LENGTH;
return icons[damage];
}
return icon;
}
void AnvilTile::registerIcons(IconRegister *iconRegister)
{
icon = iconRegister->registerIcon(L"anvil_base");
icons = new Icon*[ANVIL_NAMES_LENGTH];
for (int i = 0; i < ANVIL_NAMES_LENGTH; i++)
{
icons[i] = iconRegister->registerIcon(TEXTURE_DAMAGE_NAMES[i]);
}
}
void AnvilTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr<LivingEntity> by, shared_ptr<ItemInstance> itemInstance)
{
int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3;
int dmg = level->getData(x, y, z) >> 2;
dir = ++dir % 4;
if (dir == 0) level->setData(x, y, z, Direction::NORTH | (dmg << 2), Tile::UPDATE_CLIENTS);
if (dir == 1) level->setData(x, y, z, Direction::EAST | (dmg << 2), Tile::UPDATE_CLIENTS);
if (dir == 2) level->setData(x, y, z, Direction::SOUTH | (dmg << 2), Tile::UPDATE_CLIENTS);
if (dir == 3) level->setData(x, y, z, Direction::WEST | (dmg << 2), Tile::UPDATE_CLIENTS);
}
bool AnvilTile::use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly)
{
if (level->isClientSide)
{
return true;
}
player->startRepairing(x, y, z);
return true;
}
int AnvilTile::getRenderShape()
{
return SHAPE_ANVIL;
}
int AnvilTile::getSpawnResourcesAuxValue(int data)
{
return data >> 2;
}
void AnvilTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr<TileEntity> forceEntity)
{
int dir = level->getData(x, y, z) & 3;
if (dir == Direction::EAST || dir == Direction::WEST)
{
setShape(0, 0, 2 / 16.0f, 1, 1, 1 - 2 / 16.0f);
}
else
{
setShape(2 / 16.0f, 0, 0, 1 - 2 / 16.0f, 1, 1);
}
}
void AnvilTile::falling(shared_ptr<FallingTile> entity)
{
entity->setHurtsEntities(true);
}
void AnvilTile::onLand(Level *level, int xt, int yt, int zt, int data)
{
level->levelEvent(LevelEvent::SOUND_ANVIL_LAND, xt, yt, zt, 0);
}
bool AnvilTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face)
{
return true;
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include "HeavyTile.h"
class FallingTile;
class AnvilTile : public HeavyTile
{
friend class ChunkRebuildData;
friend class Tile;
public:
static const int PART_BASE = 0;
static const int PART_JOINT = 1;
static const int PART_COLUMN = 2;
static const int PART_TOP = 3;
static const int ANVIL_NAMES_LENGTH = 3;
static const unsigned int ANVIL_NAMES[ANVIL_NAMES_LENGTH];
private:
static wstring TEXTURE_DAMAGE_NAMES[ANVIL_NAMES_LENGTH];
public:
int part;
private:
Icon **icons;
protected:
AnvilTile(int id);
public:
bool isCubeShaped();
bool isSolidRender(bool isServerLevel = false);
Icon *getTexture(int face, int data);
void registerIcons(IconRegister *iconRegister);
void setPlacedBy(Level *level, int x, int y, int z, shared_ptr<LivingEntity> by, shared_ptr<ItemInstance> itemInstance);
bool use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false);
int getRenderShape();
int getSpawnResourcesAuxValue(int data);
void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr<TileEntity> forceEntity = shared_ptr<TileEntity>());
protected:
void falling(shared_ptr<FallingTile> entity);
public:
void onLand(Level *level, int xt, int yt, int zt, int data);
bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face);
};
+18
View File
@@ -0,0 +1,18 @@
#include "stdafx.h"
#include "net.minecraft.world.level.tile.h"
#include "AnvilTileItem.h"
AnvilTileItem::AnvilTileItem(Tile *tile) : MultiTextureTileItem(tile->id - 256, tile, (int *)AnvilTile::ANVIL_NAMES, 3)
{
}
int AnvilTileItem::getLevelDataForAuxValue(int auxValue)
{
return auxValue << 2;
}
unsigned int AnvilTileItem::getDescriptionId(int iData)
{
int damage = iData >> 2;
return MultiTextureTileItem::getDescriptionId(damage);
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "MultiTextureTileItem.h"
class AnvilTileItem : public MultiTextureTileItem
{
public:
AnvilTileItem(Tile *tile);
int getLevelDataForAuxValue(int auxValue);
virtual unsigned int getDescriptionId(int iData);
private:
};
+238
View File
@@ -0,0 +1,238 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.animal.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.item.crafting.h"
#include "ArmorDyeRecipe.h"
bool ArmorDyeRecipe::matches(shared_ptr<CraftingContainer> craftSlots, Level *level)
{
shared_ptr<ItemInstance> target = nullptr;
vector<shared_ptr<ItemInstance> > dyes;
for (int slot = 0; slot < craftSlots->getContainerSize(); slot++)
{
shared_ptr<ItemInstance> item = craftSlots->getItem(slot);
if (item == NULL) continue;
ArmorItem *armor = dynamic_cast<ArmorItem *>(item->getItem());
if (armor)
{
if (armor->getMaterial() == ArmorItem::ArmorMaterial::CLOTH && target == NULL)
{
target = item;
}
else
{
return false;
}
}
else if (item->id == Item::dye_powder_Id)
{
dyes.push_back(item);
}
else
{
return false;
}
}
return target != NULL && !dyes.empty();
}
shared_ptr<ItemInstance> ArmorDyeRecipe::assembleDyedArmor(shared_ptr<CraftingContainer> craftSlots)
{
shared_ptr<ItemInstance> target = nullptr;
int colorTotals[3] = {0,0,0};
int intensityTotal = 0;
int colourCounts = 0;
ArmorItem *armor = NULL;
if(craftSlots != NULL)
{
for (int slot = 0; slot < craftSlots->getContainerSize(); slot++)
{
shared_ptr<ItemInstance> item = craftSlots->getItem(slot);
if (item == NULL) continue;
armor = dynamic_cast<ArmorItem *>(item->getItem());
if (armor)
{
if (armor->getMaterial() == ArmorItem::ArmorMaterial::CLOTH && target == NULL)
{
target = item->copy();
target->count = 1;
if (armor->hasCustomColor(item))
{
int color = armor->getColor(target);
float red = (float) ((color >> 16) & 0xFF) / 0xFF;
float green = (float) ((color >> 8) & 0xFF) / 0xFF;
float blue = (float) (color & 0xFF) / 0xFF;
intensityTotal += max(red, max(green, blue)) * 0xFF;
colorTotals[0] += red * 0xFF;
colorTotals[1] += green * 0xFF;
colorTotals[2] += blue * 0xFF;
colourCounts++;
}
}
else
{
return nullptr;
}
}
else if (item->id == Item::dye_powder_Id)
{
int tileData = ColoredTile::getTileDataForItemAuxValue(item->getAuxValue());
int red = (int) (Sheep::COLOR[tileData][0] * 0xFF);
int green = (int) (Sheep::COLOR[tileData][1] * 0xFF);
int blue = (int) (Sheep::COLOR[tileData][2] * 0xFF);
intensityTotal += max(red, max(green, blue));
colorTotals[0] += red;
colorTotals[1] += green;
colorTotals[2] += blue;
colourCounts++;
}
else
{
return nullptr;
}
}
}
if (armor == NULL) return nullptr;
int red = (colorTotals[0] / colourCounts);
int green = (colorTotals[1] / colourCounts);
int blue = (colorTotals[2] / colourCounts);
float averageIntensity = (float) intensityTotal / colourCounts;
float resultIntensity = (float) max(red, max(green, blue));
// System.out.println(averageIntensity + ", " + resultIntensity);
red = (int) ((float) red * averageIntensity / resultIntensity);
green = (int) ((float) green * averageIntensity / resultIntensity);
blue = (int) ((float) blue * averageIntensity / resultIntensity);
int rgb = red;
rgb = (rgb << 8) + green;
rgb = (rgb << 8) + blue;
armor->setColor(target, rgb);
return target;
}
shared_ptr<ItemInstance> ArmorDyeRecipe::assemble(shared_ptr<CraftingContainer> craftSlots)
{
return ArmorDyeRecipe::assembleDyedArmor(craftSlots);
}
int ArmorDyeRecipe::size()
{
return 10;
}
const ItemInstance *ArmorDyeRecipe::getResultItem()
{
return NULL;
}
const int ArmorDyeRecipe::getGroup()
{
return ShapedRecipy::eGroupType_Armour;
}
// 4J-PB
bool ArmorDyeRecipe::requires(int iRecipe)
{
return false;
}
void ArmorDyeRecipe::requires(INGREDIENTS_REQUIRED *pIngReq)
{
//int iCount=0;
//bool bFound;
//int j;
INGREDIENTS_REQUIRED TempIngReq;
// shapeless doesn't have the 3x3 shape, but we'll just use this to store the ingredients anyway
TempIngReq.iIngC=0;
TempIngReq.iType = RECIPE_TYPE_2x2; // all the dyes can be made in a 2x2
TempIngReq.uiGridA = new unsigned int [9];
TempIngReq.iIngIDA= new int [3*3];
TempIngReq.iIngValA = new int [3*3];
TempIngReq.iIngAuxValA = new int [3*3];
ZeroMemory(TempIngReq.iIngIDA,sizeof(int)*9);
ZeroMemory(TempIngReq.iIngValA,sizeof(int)*9);
memset(TempIngReq.iIngAuxValA,Recipes::ANY_AUX_VALUE,sizeof(int)*9);
ZeroMemory(TempIngReq.uiGridA,sizeof(unsigned int)*9);
#if 0
AUTO_VAR(citEnd, ingredients->end());
for (vector<ItemInstance *>::const_iterator ingredient = ingredients->begin(); ingredient != citEnd; ingredient++)
{
ItemInstance *expected = *ingredient;
if (expected!=NULL)
{
int iAuxVal = (*ingredient)->getAuxValue();
TempIngReq.uiGridA[iCount++]=expected->id | iAuxVal<<24;
// 4J-PB - put the ingredients in boxes 1,2,4,5 so we can see them in a 2x2 crafting screen
if(iCount==2) iCount=3;
bFound=false;
for(j=0;j<TempIngReq.iIngC;j++)
{
if((TempIngReq.iIngIDA[j]==expected->id) && (iAuxVal == Recipes::ANY_AUX_VALUE || TempIngReq.iIngAuxValA[j] == iAuxVal))
{
bFound= true;
break;
}
}
if(bFound)
{
TempIngReq.iIngValA[j]++;
}
else
{
TempIngReq.iIngIDA[TempIngReq.iIngC]=expected->id;
TempIngReq.iIngAuxValA[TempIngReq.iIngC]=iAuxVal;
TempIngReq.iIngValA[TempIngReq.iIngC++]++;
}
}
}
#endif
pIngReq->iIngIDA = new int [TempIngReq.iIngC];
pIngReq->iIngValA = new int [TempIngReq.iIngC];
pIngReq->iIngAuxValA = new int [TempIngReq.iIngC];
pIngReq->uiGridA = new unsigned int [9];
pIngReq->pRecipy=this;
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
{
pIngReq->bCanMake[i]=false;
}
pIngReq->iIngC=TempIngReq.iIngC;
pIngReq->iType=TempIngReq.iType;
if(pIngReq->iIngC!=0)
{
memcpy(pIngReq->iIngIDA,TempIngReq.iIngIDA,sizeof(int)*TempIngReq.iIngC);
memcpy(pIngReq->iIngValA,TempIngReq.iIngValA,sizeof(int)*TempIngReq.iIngC);
memcpy(pIngReq->iIngAuxValA,TempIngReq.iIngAuxValA,sizeof(int)*TempIngReq.iIngC);
}
memcpy(pIngReq->uiGridA,TempIngReq.uiGridA,sizeof(unsigned int) *9);
delete [] TempIngReq.iIngIDA;
delete [] TempIngReq.iIngValA;
delete [] TempIngReq.iIngAuxValA;
delete [] TempIngReq.uiGridA;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "Recipy.h"
class ArmorDyeRecipe : public Recipy
{
public:
bool matches(shared_ptr<CraftingContainer> craftSlots, Level *level);
// 4J Stu - Made static as we use this in a different way from the Java (but needs to be a different name otherwise Orbis compiler complains
static shared_ptr<ItemInstance> assembleDyedArmor(shared_ptr<CraftingContainer> craftSlots);
shared_ptr<ItemInstance> assemble(shared_ptr<CraftingContainer> craftSlots);
int size();
const ItemInstance *getResultItem();
virtual const int getGroup();
// 4J-PB
virtual bool requires(int iRecipe);
virtual void requires(INGREDIENTS_REQUIRED *pIngReq);
};
+266
View File
@@ -0,0 +1,266 @@
#include "stdafx.h"
#include "..\Minecraft.Client\Minecraft.h"
#include "net.minecraft.world.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.phys.h"
#include "net.minecraft.world.level.h"
#include "com.mojang.nbt.h"
#include "ArmorItem.h"
const int ArmorItem::healthPerSlot[] = {
11, 16, 15, 13
};
const wstring ArmorItem::LEATHER_OVERLAYS[] = {
L"helmetCloth_overlay", L"chestplateCloth_overlay", L"leggingsCloth_overlay", L"bootsCloth_overlay"
};
const wstring ArmorItem::TEXTURE_EMPTY_SLOTS[] = {
L"slot_empty_helmet", L"slot_empty_chestplate", L"slot_empty_leggings", L"slot_empty_boots"
};
shared_ptr<ItemInstance> ArmorItem::ArmorDispenseItemBehavior::execute(BlockSource *source, shared_ptr<ItemInstance> dispensed, eOUTCOME &outcome)
{
FacingEnum *facing = DispenserTile::getFacing(source->getData());
int x = source->getBlockX() + facing->getStepX();
int y = source->getBlockY() + facing->getStepY();
int z = source->getBlockZ() + facing->getStepZ();
AABB *bb = AABB::newTemp(x, y, z, x + 1, y + 1, z + 1);
EntitySelector *selector = new MobCanWearArmourEntitySelector(dispensed);
vector<shared_ptr<Entity> > *entities = source->getWorld()->getEntitiesOfClass(typeid(LivingEntity), bb, selector);
delete selector;
if (entities->size() > 0)
{
shared_ptr<LivingEntity> target = dynamic_pointer_cast<LivingEntity>( entities->at(0) );
int offset = target->instanceof(eTYPE_PLAYER) ? 1 : 0;
int slot = Mob::getEquipmentSlotForItem(dispensed);
shared_ptr<ItemInstance> equip = dispensed->copy();
equip->count = 1;
target->setEquippedSlot(slot - offset, equip);
if (target->instanceof(eTYPE_MOB)) dynamic_pointer_cast<Mob>(target)->setDropChance(slot, 2);
dispensed->count--;
outcome = ACTIVATED_ITEM;
delete entities;
return dispensed;
}
else
{
delete entities;
return DefaultDispenseItemBehavior::execute(source, dispensed, outcome);
}
}
typedef ArmorItem::ArmorMaterial _ArmorMaterial;
const int _ArmorMaterial::clothArray[] = {1,3,2,1};
const int _ArmorMaterial::chainArray[] = {2, 5, 4, 1};
const int _ArmorMaterial::ironArray[] = {2, 6, 5, 2};
const int _ArmorMaterial::goldArray[] = {2, 5, 3, 1};
const int _ArmorMaterial::diamondArray[] = {3, 8, 6, 3};
const _ArmorMaterial *_ArmorMaterial::CLOTH = new _ArmorMaterial(5, _ArmorMaterial::clothArray, 15);
const _ArmorMaterial *_ArmorMaterial::CHAIN = new _ArmorMaterial(15, _ArmorMaterial::chainArray, 12);
const _ArmorMaterial *_ArmorMaterial::IRON = new _ArmorMaterial(15, _ArmorMaterial::ironArray, 9);
const _ArmorMaterial *_ArmorMaterial::GOLD = new _ArmorMaterial(7, _ArmorMaterial::goldArray, 25);
const _ArmorMaterial *_ArmorMaterial::DIAMOND = new _ArmorMaterial(33, _ArmorMaterial::diamondArray, 10);
_ArmorMaterial::ArmorMaterial(int durabilityMultiplier, const int slotProtections[], int enchantmentValue)
{
this->durabilityMultiplier = durabilityMultiplier;
this->slotProtections = (int *)slotProtections;
this->enchantmentValue = enchantmentValue;
}
_ArmorMaterial::~ArmorMaterial()
{
delete [] slotProtections;
}
int _ArmorMaterial::getHealthForSlot(int slot) const
{
return healthPerSlot[slot] * durabilityMultiplier;
}
int _ArmorMaterial::getDefenseForSlot(int slot) const
{
return slotProtections[slot];
}
int _ArmorMaterial::getEnchantmentValue() const
{
return enchantmentValue;
}
int _ArmorMaterial::getTierItemId() const
{
if (this == CLOTH)
{
return Item::leather_Id;
}
else if (this == CHAIN)
{
return Item::ironIngot_Id;
}
else if (this == GOLD)
{
return Item::goldIngot_Id;
}
else if (this == IRON)
{
return Item::ironIngot_Id;
}
else if (this == DIAMOND)
{
return Item::diamond_Id;
}
return 0;
}
ArmorItem::ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot) : Item( id ), armorType( armorType ), slot( slot ), modelIndex( icon ), defense( armorType->getDefenseForSlot(slot) )
{
setMaxDamage(armorType->getHealthForSlot(slot));
maxStackSize = 1;
DispenserTile::REGISTRY.add(this, new ArmorDispenseItemBehavior());
}
int ArmorItem::getColor(shared_ptr<ItemInstance> item, int spriteLayer)
{
if (spriteLayer > 0)
{
return 0xFFFFFF;
}
int color = getColor(item);
if (color < 0) color = 0xFFFFFF;
return color;
}
bool ArmorItem::hasMultipleSpriteLayers()
{
return armorType == ArmorMaterial::CLOTH;
}
int ArmorItem::getEnchantmentValue()
{
return armorType->getEnchantmentValue();
}
const _ArmorMaterial *ArmorItem::getMaterial()
{
return armorType;
}
bool ArmorItem::hasCustomColor(shared_ptr<ItemInstance> item)
{
if (armorType != ArmorMaterial::CLOTH) return false;
if (!item->hasTag()) return false;
if (!item->getTag()->contains(L"display")) return false;
if (!item->getTag()->getCompound(L"display")->contains(L"color")) return false;
return true;
}
int ArmorItem::getColor(shared_ptr<ItemInstance> item)
{
if (armorType != ArmorMaterial::CLOTH) return -1;
CompoundTag *tag = item->getTag();
if (tag == NULL) return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
CompoundTag *display = tag->getCompound(L"display");
if (display == NULL) return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
if (display->contains(L"color"))
{
return display->getInt(L"color");
}
else
{
return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
}
}
Icon *ArmorItem::getLayerIcon(int auxValue, int spriteLayer)
{
if (spriteLayer == 1)
{
return overlayIcon;
}
return Item::getLayerIcon(auxValue, spriteLayer);
}
void ArmorItem::clearColor(shared_ptr<ItemInstance> item)
{
if (armorType != ArmorMaterial::CLOTH) return;
CompoundTag *tag = item->getTag();
if (tag == NULL) return;
CompoundTag *display = tag->getCompound(L"display");
if (display->contains(L"color")) display->remove(L"color");
}
void ArmorItem::setColor(shared_ptr<ItemInstance> item, int color)
{
if (armorType != ArmorMaterial::CLOTH)
{
#ifndef _CONTENT_PACKAGE
printf("Can't dye non-leather!");
__debugbreak();
#endif
//throw new UnsupportedOperationException("Can't dye non-leather!");
}
CompoundTag *tag = item->getTag();
if (tag == NULL)
{
tag = new CompoundTag();
item->setTag(tag);
}
CompoundTag *display = tag->getCompound(L"display");
if (!tag->contains(L"display")) tag->putCompound(L"display", display);
display->putInt(L"color", color);
}
bool ArmorItem::isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem)
{
if (armorType->getTierItemId() == repairItem->id)
{
return true;
}
return Item::isValidRepairItem(source, repairItem);
}
void ArmorItem::registerIcons(IconRegister *iconRegister)
{
Item::registerIcons(iconRegister);
if (armorType == ArmorMaterial::CLOTH)
{
overlayIcon = iconRegister->registerIcon(LEATHER_OVERLAYS[slot]);
}
iconEmpty = iconRegister->registerIcon(TEXTURE_EMPTY_SLOTS[slot]);
}
Icon *ArmorItem::getEmptyIcon(int slot)
{
switch (slot)
{
case 0:
return Item::helmet_diamond->iconEmpty;
case 1:
return Item::chestplate_diamond->iconEmpty;
case 2:
return Item::leggings_diamond->iconEmpty;
case 3:
return Item::boots_diamond->iconEmpty;
}
return NULL;
}
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include "Item.h"
#include "DefaultDispenseItemBehavior.h"
class ArmorItem : public Item
{
public:
static const int SLOT_HEAD = 0;
static const int SLOT_TORSO = 1;
static const int SLOT_LEGS = 2;
static const int SLOT_FEET = 3;
static const eMinecraftColour DEFAULT_LEATHER_COLOR = eMinecraftColour_Armour_Default_Leather_Colour;
private:
static const int healthPerSlot[];
static const wstring LEATHER_OVERLAYS[] ;
public:
static const wstring TEXTURE_EMPTY_SLOTS[];
private:
class ArmorDispenseItemBehavior : public DefaultDispenseItemBehavior
{
protected:
virtual shared_ptr<ItemInstance> execute(BlockSource *source, shared_ptr<ItemInstance> dispensed, eOUTCOME &outcome);
};
public:
class ArmorMaterial
{
public:
static const int clothArray[];
static const int chainArray[];
static const int ironArray[];
static const int goldArray[];
static const int diamondArray[];
public:
static const ArmorMaterial *CLOTH;
static const ArmorMaterial *CHAIN;
static const ArmorMaterial *IRON;
static const ArmorMaterial *GOLD;
static const ArmorMaterial *DIAMOND;
private:
int durabilityMultiplier;
int *slotProtections;
int enchantmentValue;
// 4J Stu - Had to make this public but was private
// We shouldn't be creating these except the static initialisation
public:
ArmorMaterial(int durabilityMultiplier, const int slotProtections[], int enchantmentValue);
~ArmorMaterial();
public:
int getHealthForSlot(int slot) const;
int getDefenseForSlot(int slot) const;
int getEnchantmentValue() const;
int getTierItemId() const;
};
const int slot;
const int defense;
const int modelIndex;
private:
const ArmorMaterial *armorType;
Icon *overlayIcon;
Icon *iconEmpty;
public:
ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot);
virtual int getColor(shared_ptr<ItemInstance> item, int spriteLayer);
virtual bool hasMultipleSpriteLayers();
virtual int getEnchantmentValue();
virtual const ArmorMaterial *getMaterial();
virtual bool hasCustomColor(shared_ptr<ItemInstance> item);
virtual int getColor(shared_ptr<ItemInstance> item);
virtual Icon *getLayerIcon(int auxValue, int spriteLayer);
virtual void clearColor(shared_ptr<ItemInstance> item);
virtual void setColor(shared_ptr<ItemInstance> item, int color);
virtual bool isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem);
virtual void registerIcons(IconRegister *iconRegister);
static Icon *getEmptyIcon(int slot);
};
+158
View File
@@ -0,0 +1,158 @@
//package net.minecraft.world.item.crafting;
//import net.minecraft.world.item.*;
//import net.minecraft.world.level.tile.Tile;
#include "stdafx.h"
#include "net.minecraft.world.item.h"
#include "Tile.h"
#include "Recipy.h"
#include "Recipes.h"
#include "ArmorRecipes.h"
// 4J-PB - adding "" on the end of these so we can detect it
wstring ArmorRecipes::shapes[][4] =
{
{L"XXX", //
L"X X",L""},//
{L"X X", //
L"XXX",//
L"XXX",L""},//
{L"XXX", //
L"X X",//
L"X X",L""},//
{L"X X",//
L"X X",L""},//
};
/*
ArmorRecipes::map[5] =
{
{Item::leather, Tile::fire, Item::ironIngot, Item::diamond, Item::goldIngot},
{Item::helmet_cloth, Item::helmet_chain, Item::helmet_iron, Item::helmet_diamond, Item::helmet_gold},
{Item::chestplate_cloth, Item::chestplate_chain, Item::chestplate_iron, Item::chestplate_diamond, Item::chestplate_gold},
{Item::leggings_cloth, Item::leggings_chain, Item::leggings_iron, Item::leggings_diamond, Item::leggings_gold},
{Item::boots_cloth, Item::boots_chain, Item::boots_iron, Item::boots_diamond, Item::boots_gold},
};
*/
void ArmorRecipes::_init()
{
map = new vector <Object *> [MAX_ARMOUR_RECIPES];
// 4J-PB - removing the chain armour, since we show all possible recipes in the xbox game, and it's not one you can make
ADD_OBJECT(map[0],Item::leather);
// ADD_OBJECT(map[0],Tile::fire);
ADD_OBJECT(map[0],Item::ironIngot);
ADD_OBJECT(map[0],Item::diamond);
ADD_OBJECT(map[0],Item::goldIngot);
ADD_OBJECT(map[1],Item::helmet_leather);
// ADD_OBJECT(map[1],Item::helmet_chain);
ADD_OBJECT(map[1],Item::helmet_iron);
ADD_OBJECT(map[1],Item::helmet_diamond);
ADD_OBJECT(map[1],Item::helmet_gold);
ADD_OBJECT(map[2],Item::chestplate_leather);
// ADD_OBJECT(map[2],Item::chestplate_chain);
ADD_OBJECT(map[2],Item::chestplate_iron);
ADD_OBJECT(map[2],Item::chestplate_diamond);
ADD_OBJECT(map[2],Item::chestplate_gold);
ADD_OBJECT(map[3],Item::leggings_leather);
// ADD_OBJECT(map[3],Item::leggings_chain);
ADD_OBJECT(map[3],Item::leggings_iron);
ADD_OBJECT(map[3],Item::leggings_diamond);
ADD_OBJECT(map[3],Item::leggings_gold);
ADD_OBJECT(map[4],Item::boots_leather);
// ADD_OBJECT(map[4],Item::boots_chain);
ADD_OBJECT(map[4],Item::boots_iron);
ADD_OBJECT(map[4],Item::boots_diamond);
ADD_OBJECT(map[4],Item::boots_gold);
}
// 4J-PB added for quick equip in the inventory
ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId)
{
switch(iId)
{
case Item::helmet_leather_Id:
case Item::helmet_chain_Id:
case Item::helmet_iron_Id:
case Item::helmet_diamond_Id:
case Item::helmet_gold_Id:
return eArmorType_Helmet;
break;
case Item::chestplate_leather_Id:
case Item::chestplate_chain_Id:
case Item::chestplate_iron_Id:
case Item::chestplate_diamond_Id:
case Item::chestplate_gold_Id:
return eArmorType_Chestplate;
break;
case Item::leggings_leather_Id:
case Item::leggings_chain_Id:
case Item::leggings_iron_Id:
case Item::leggings_diamond_Id:
case Item::leggings_gold_Id:
return eArmorType_Leggings;
break;
case Item::boots_leather_Id:
case Item::boots_chain_Id:
case Item::boots_iron_Id:
case Item::boots_diamond_Id:
case Item::boots_gold_Id:
return eArmorType_Boots;
break;
}
return eArmorType_None;
}
void ArmorRecipes::addRecipes(Recipes *r)
{
wchar_t wchTypes[5];
wchTypes[4]=0;
for (unsigned int m = 0; m < map[0].size(); m++)
{
Object *pObjMaterial = map[0].at(m);
for (int t=0; t<MAX_ARMOUR_RECIPES-1; t++)
{
Item *target = map[t+1].at(m)->item;
wchTypes[0]=L'w';
wchTypes[1]=L'c';
wchTypes[3]=L'g';
if(pObjMaterial->GetType()==eType_TILE)
{
wchTypes[2]=L't';
r->addShapedRecipy(new ItemInstance(target),
wchTypes,
shapes[t],
L'X', pObjMaterial->tile,
L'A');
}
else
{
// must be Item
wchTypes[2]=L'i';
r->addShapedRecipy(new ItemInstance(target),
wchTypes,
shapes[t],
L'X', pObjMaterial->item,
L'A');
}
}
}
}
+34
View File
@@ -0,0 +1,34 @@
//package net.minecraft.world.item.crafting;
//import net.minecraft.world.item.*;
//import net.minecraft.world.level.tile.Tile;
#pragma once
#define MAX_ARMOUR_RECIPES 5
class ArmorRecipes
{
public:
enum _eArmorType
{
eArmorType_None=0,
eArmorType_Helmet,
eArmorType_Chestplate,
eArmorType_Leggings,
eArmorType_Boots,
}
eArmorType;
// 4J - added for common ctor code
void _init();
ArmorRecipes() {_init();}
private:
// 4J-PB - this wasn't static in java, so might not be right
static wstring shapes[][4];
private:
vector <Object *> *map;
public:
void addRecipes(Recipes *r);
static _eArmorType GetArmorType(int iId);
};
+63
View File
@@ -0,0 +1,63 @@
#include "stdafx.h"
#include "net.minecraft.world.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.inventory.h"
#include "net.minecraft.world.item.crafting.h"
#include "ArmorSlot.h"
ArmorSlot::ArmorSlot(int slotNum, shared_ptr<Container> container, int id, int x, int y)
: Slot( container, id, x, y ),
slotNum( slotNum )
{
}
int ArmorSlot::getMaxStackSize()
{
return 1;
}
bool ArmorSlot::mayPlace(shared_ptr<ItemInstance> item)
{
if (item == NULL)
{
return false;
}
if ( dynamic_cast<ArmorItem *>( item->getItem() ) != NULL)
{
return dynamic_cast<ArmorItem *>( item->getItem() )->slot == slotNum;
}
if (item->getItem()->id == Tile::pumpkin_Id || item->getItem()->id == Item::skull_Id)
{
return slotNum == 0;
}
return false;
}
Icon *ArmorSlot::getNoItemIcon()
{
return ArmorItem::getEmptyIcon(slotNum);
}
//
//bool ArmorSlot::mayCombine(shared_ptr<ItemInstance> item)
//{
// shared_ptr<ItemInstance> thisItemI = getItem();
// if(thisItemI == NULL || item == NULL) return false;
//
// ArmorItem *thisItem = (ArmorItem *)thisItemI->getItem();
// bool thisIsDyableArmor = thisItem->getMaterial() == ArmorItem::ArmorMaterial::CLOTH;
// bool itemIsDye = item->id == Item::dye_powder_Id;
// return thisIsDyableArmor && itemIsDye;
//}
//
//shared_ptr<ItemInstance> ArmorSlot::combine(shared_ptr<ItemInstance> item)
//{
// shared_ptr<CraftingContainer> craftSlots = shared_ptr<CraftingContainer>( new CraftingContainer(NULL, 2, 2) );
// craftSlots->setItem(0, item);
// craftSlots->setItem(1, getItem()); // Armour item needs to go second
// shared_ptr<ItemInstance> result = ArmorDyeRecipe::assembleDyedArmor(craftSlots);
// craftSlots->setItem(0, nullptr);
// craftSlots->setItem(1, nullptr);
// return result;
//}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
// 4J Stu Added
// In InventoryMenu.java they create an anoymous class while creating some slot. I have moved the content
// of that anonymous class to here
#include "Slot.h"
class Container;
class ArmorSlot : public Slot
{
private:
const int slotNum;
public:
ArmorSlot(int slotNum, shared_ptr<Container> container, int id, int x, int y);
virtual ~ArmorSlot() {}
virtual int getMaxStackSize();
virtual bool mayPlace(shared_ptr<ItemInstance> item);
Icon *getNoItemIcon();
//virtual bool mayCombine(shared_ptr<ItemInstance> item); // 4J Added
//virtual shared_ptr<ItemInstance> combine(shared_ptr<ItemInstance> item); // 4J Added
};
+116
View File
@@ -0,0 +1,116 @@
#pragma once
#include <assert.h>
//Note - this is meant to be a really simple wrapper round a pointer just to be able to add a length value to arrays.
// As such, it shouldn't delete its data in a destructor as shallow copies will be made of this and we don't want to
// free the data just because one of those has gone out of scope
template <class T> class arrayWithLength
{
public:
T *data;
unsigned int length;
arrayWithLength() { data = NULL; length = 0; }
arrayWithLength(unsigned int elements, bool bClearArray=true) { assert(elements!=0); data = new T[elements]; if(bClearArray){ memset( data,0,sizeof(T)*elements); } this->length = elements; }
// 4J Stu Added this ctor so I static init arrays in the Item derivation tree
arrayWithLength( T data[], unsigned int elements) { this->data = data; this->length = elements; }
//~arrayWithLength() { delete[] data; }
void resize( unsigned int elements )
{
assert( elements > length );
T *temp = new T[elements];
memset( temp,0,sizeof(T)*elements);
if( data != NULL )
{
std::copy( data, data+length, temp );
delete[] data;
}
data = temp;
length = elements;
}
T& operator[](unsigned int i) { return data[i]; }
T operator[](unsigned int i) const { return data[i]; }
};
// TODO 4J Stu - This looks right, but is it?
template <class T> class array2DWithLength
{
typedef arrayWithLength< T >* _parrayWithLength;
public:
_parrayWithLength *data;
unsigned int length;
array2DWithLength() { data = NULL; length = 0; }
array2DWithLength(unsigned int dimA, unsigned int dimB)
{
data = new _parrayWithLength[dimA];
this->length = dimA;
for( unsigned int i = 0; i < length; i++ )
data[i] = new arrayWithLength<T>(dimB);
}
_parrayWithLength& operator[](unsigned int i) { return data[i]; }
_parrayWithLength operator[](unsigned int i) const { return data[i]; }
};
class Biome;
class LevelChunk;
class Node;
class Item;
class Tile;
class Stat;
class MobCategory;
class File;
class Vertex;
class _Polygon; // Renaming as have conflict with Windows Polygon fn
class ServerLevel;
class MultiPlayerLevel;
class Level;
class LevelRenderer;
class WeighedRandomItem;
class WeighedTreasure;
class Layer;
//class Cube;
class ModelPart;
class Enchantment;
class ClipChunk;
typedef arrayWithLength<double> doubleArray;
typedef array2DWithLength<double> coords2DArray;
typedef arrayWithLength<byte> byteArray;
typedef arrayWithLength<char> charArray;
typedef arrayWithLength<short> shortArray;
typedef arrayWithLength<int> intArray;
typedef arrayWithLength<float> floatArray;
typedef arrayWithLength<Biome *> BiomeArray;
typedef arrayWithLength<LevelChunk *> LevelChunkArray;
typedef array2DWithLength<LevelChunk *> LevelChunk2DArray;
typedef arrayWithLength<Node *> NodeArray;
typedef arrayWithLength<Item *> ItemArray;
typedef arrayWithLength<Tile *> TileArray;
typedef arrayWithLength<Stat *> StatArray;
typedef arrayWithLength<MobCategory *> MobCategoryArray;
typedef arrayWithLength<File *> FileArray;
typedef arrayWithLength<Vertex *> VertexArray;
typedef arrayWithLength<_Polygon *> PolygonArray;
typedef arrayWithLength<ServerLevel *> ServerLevelArray;
typedef arrayWithLength<MultiPlayerLevel *> MultiPlayerLevelArray;
typedef arrayWithLength<Level *> LevelArray;
typedef arrayWithLength<LevelRenderer *> LevelRendererArray;
typedef arrayWithLength<WeighedRandomItem *> WeighedRandomItemArray;
typedef arrayWithLength<WeighedTreasure *> WeighedTreasureArray;
typedef arrayWithLength< shared_ptr<Layer> > LayerArray;
//typedef arrayWithLength<Cube *> CubeArray;
typedef arrayWithLength<ModelPart *> ModelPartArray;
typedef arrayWithLength<Enchantment *> EnchantmentArray;
typedef arrayWithLength<ClipChunk> ClipChunkArray;
#include "ItemInstance.h"
typedef arrayWithLength<shared_ptr<ItemInstance> > ItemInstanceArray;
+23
View File
@@ -0,0 +1,23 @@
#pragma once
using namespace std;
#include "ArrayWithLength.h"
class Arrays
{
public:
static void fill(doubleArray arr, unsigned int from, unsigned int to, double value)
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
static void fill(floatArray arr, unsigned int from, unsigned int to, float value)
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
static void fill(BiomeArray arr, unsigned int from, unsigned int to, Biome *value)
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
static void fill(byteArray arr, unsigned int from, unsigned int to, byte value)
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
static void fill(byteArray arr, byte value)
{ std::fill( arr.data, arr.data+arr.length, value ); }
};
+565
View File
@@ -0,0 +1,565 @@
#include "stdafx.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.phys.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.damagesource.h"
#include "net.minecraft.world.item.enchantment.h"
#include "net.minecraft.network.packet.h"
#include "..\Minecraft.Client\ServerPlayer.h"
#include "..\Minecraft.Client\PlayerConnection.h"
#include "com.mojang.nbt.h"
#include "Arrow.h"
// 4J : WESTY : Added for other award, kill creeper with arrow.
#include "net.minecraft.world.entity.monster.h"
#include "net.minecraft.stats.h"
#include "SoundTypes.h"
// base damage, multiplied with velocity
const double Arrow::ARROW_BASE_DAMAGE = 2.0f;
// 4J - added common ctor code.
void Arrow::_init()
{
// 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
// the derived version of the function is called
this->defineSynchedData();
xTile = -1;
yTile = -1;
zTile = -1;
lastTile = 0;
lastData = 0;
inGround = false;
pickup = PICKUP_DISALLOWED;
shakeTime = 0;
flightTime = 0;
owner = nullptr;
life = 0;
baseDamage = ARROW_BASE_DAMAGE;
knockback = 0;
}
Arrow::Arrow(Level *level) : Entity( level )
{
_init();
viewScale = 10;
setSize(0.5f, 0.5f);
}
Arrow::Arrow(Level *level, shared_ptr<LivingEntity> mob, shared_ptr<LivingEntity> target, float power, float uncertainty) : Entity( level )
{
_init();
viewScale = 10;
owner = mob;
if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED;
y = mob->y + mob->getHeadHeight() - 0.1f;
double xd = target->x - mob->x;
double yd = (target->y + target->getHeadHeight() - 0.7f) - y;
double zd = target->z - mob->z;
double sd = sqrt(xd * xd + zd * zd);
if (sd < 0.0000001) return;
float yRot = (float) (atan2(zd, xd) * 180 / PI) - 90;
float xRot = (float) -(atan2(yd, sd) * 180 / PI);
double xdn = xd / sd;
double zdn = zd / sd;
moveTo(mob->x + xdn, y, mob->z + zdn, yRot, xRot);
heightOffset = 0;
float yo = (float) sd * 0.2f;
shoot(xd, yd + yo, zd, power, uncertainty);
}
Arrow::Arrow(Level *level, double x, double y, double z) : Entity( level )
{
_init();
viewScale = 10;
setSize(0.5f, 0.5f);
setPos(x, y, z);
heightOffset = 0;
}
Arrow::Arrow(Level *level, shared_ptr<LivingEntity> mob, float power) : Entity( level )
{
_init();
viewScale = 10;
owner = mob;
if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED;
setSize(0.5f, 0.5f);
moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
x -= Mth::cos(yRot / 180 * PI) * 0.16f;
y -= 0.1f;
z -= Mth::sin(yRot / 180 * PI) * 0.16f;
setPos(x, y, z);
heightOffset = 0;
xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
yd = -Mth::sin(xRot / 180 * PI);
shoot(xd, yd, zd, power * 1.5f, 1);
}
void Arrow::defineSynchedData()
{
entityData->define(ID_FLAGS, (byte) 0);
}
void Arrow::shoot(double xd, double yd, double zd, float pow, float uncertainty)
{
float dist = (float) sqrt(xd * xd + yd * yd + zd * zd);
xd /= dist;
yd /= dist;
zd /= dist;
xd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty;
yd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty;
zd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty;
xd *= pow;
yd *= pow;
zd *= pow;
this->xd = xd;
this->yd = yd;
this->zd = zd;
double sd = sqrt(xd * xd + zd * zd);
yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI);
life = 0;
}
void Arrow::lerpTo(double x, double y, double z, float yRot, float xRot, int steps)
{
setPos(x, y, z);
setRot(yRot, xRot);
}
void Arrow::lerpMotion(double xd, double yd, double zd)
{
this->xd = xd;
this->yd = yd;
this->zd = zd;
if (xRotO == 0 && yRotO == 0)
{
double sd = sqrt(xd * xd + zd * zd);
yRotO = yRot = (float) (atan2( xd, zd) * 180 / PI);
xRotO = xRot = (float) (atan2( yd, sd) * 180 / PI);
xRotO = xRot;
yRotO = yRot;
app.DebugPrintf("%f %f : 0x%x\n",xRot,yRot,&yRot);
moveTo(x, y, z, yRot, xRot);
life = 0;
}
}
void Arrow::tick()
{
Entity::tick();
if (xRotO == 0 && yRotO == 0)
{
double sd = sqrt(xd * xd + zd * zd);
yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI);
}
{
int t = level->getTile(xTile, yTile, zTile);
if (t > 0)
{
Tile::tiles[t]->updateShape(level, xTile, yTile, zTile);
AABB *aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile);
if (aabb != NULL && aabb->contains(Vec3::newTemp(x, y, z)))
{
inGround = true;
}
}
}
if (shakeTime > 0) shakeTime--;
if (inGround)
{
int tile = level->getTile(xTile, yTile, zTile);
int data = level->getData(xTile, yTile, zTile);
if (tile != lastTile || data != lastData)
{
inGround = false;
xd *= random->nextFloat() * 0.2f;
yd *= random->nextFloat() * 0.2f;
zd *= random->nextFloat() * 0.2f;
life = 0;
flightTime = 0;
return;
}
else
{
life++;
if (life == 20 * 60) remove();
return;
}
}
else
{
flightTime++;
}
Vec3 *from = Vec3::newTemp(x, y, z);
Vec3 *to = Vec3::newTemp(x + xd, y + yd, z + zd);
HitResult *res = level->clip(from, to, false, true);
from = Vec3::newTemp(x, y, z);
to = Vec3::newTemp(x + xd, y + yd, z + zd);
if (res != NULL)
{
to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z);
}
shared_ptr<Entity> hitEntity = nullptr;
vector<shared_ptr<Entity> > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1));
double nearest = 0;
AUTO_VAR(itEnd, objects->end());
for (AUTO_VAR(it, objects->begin()); it != itEnd; it++)
{
shared_ptr<Entity> e = *it; //objects->at(i);
if (!e->isPickable() || (e == owner && flightTime < 5)) continue;
float rr = 0.3f;
AABB *bb = e->bb->grow(rr, rr, rr);
HitResult *p = bb->clip(from, to);
if (p != NULL)
{
double dd = from->distanceTo(p->pos);
if (dd < nearest || nearest == 0)
{
hitEntity = e;
nearest = dd;
}
delete p;
}
}
if (hitEntity != NULL)
{
delete res;
res = new HitResult(hitEntity);
}
if ( (res != NULL) && (res->entity != NULL) && res->entity->instanceof(eTYPE_PLAYER))
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(res->entity);
// 4J: Check for owner being null
if ( player->abilities.invulnerable || ((owner != NULL) && (owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(owner)->canHarmPlayer(player))))
{
res = NULL;
}
}
if (res != NULL)
{
if (res->entity != NULL)
{
float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd);
int dmg = (int) Mth::ceil((float)(pow * baseDamage));
if(isCritArrow()) dmg += random->nextInt(dmg / 2 + 2);
DamageSource *damageSource = NULL;
if (owner == NULL)
{
damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), shared_from_this());
}
else
{
damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), owner);
}
if(res->entity->hurt(damageSource, dmg))
{
// Firx for #67839 - Customer Encountered: Bows enchanted with "Flame" still set things on fire if pvp/attack animals is turned off
// 4J Stu - We should not set the entity on fire unless we can cause some damage (this doesn't necessarily mean that the arrow hit lowered their health)
// set targets on fire first because we want cooked
// pork/chicken/steak
if (isOnFire() && res->entity->GetType() != eTYPE_ENDERMAN)
{
res->entity->setOnFire(5);
}
if (res->entity->instanceof(eTYPE_LIVINGENTITY))
{
shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(res->entity);
if (!level->isClientSide)
{
mob->setArrowCount(mob->getArrowCount() + 1);
}
if (knockback > 0)
{
float pushLen = sqrt(xd * xd + zd * zd);
if (pushLen > 0)
{
res->entity->push(xd * knockback * .6f / pushLen, 0.1, zd * knockback * .6f / pushLen);
}
}
if (owner != NULL)
{
ThornsEnchantment::doThornsAfterAttack(owner, mob, random);
}
if (owner != NULL && res->entity != owner && owner->GetType() == eTYPE_SERVERPLAYER)
{
dynamic_pointer_cast<ServerPlayer>(owner)->connection->send( shared_ptr<GameEventPacket>( new GameEventPacket(GameEventPacket::SUCCESSFUL_BOW_HIT, 0)) );
}
}
// 4J : WESTY : For award, need to track if creeper was killed by arrow from the player.
if (owner != NULL && owner->instanceof(eTYPE_PLAYER) // arrow owner is a player
&& !res->entity->isAlive() // target is now dead
&& (res->entity->GetType() == eTYPE_CREEPER)) // target is a creeper
{
dynamic_pointer_cast<Player>(owner)->awardStat(
GenericStats::arrowKillCreeper(),
GenericStats::param_arrowKillCreeper()
);
}
playSound( eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f));
if (res->entity->GetType() != eTYPE_ENDERDRAGON) remove();
}
else
{
xd *= -0.1f;
yd *= -0.1f;
zd *= -0.1f;
yRot += 180;
yRotO += 180;
flightTime = 0;
}
delete damageSource;
}
else
{
xTile = res->x;
yTile = res->y;
zTile = res->z;
lastTile = level->getTile(xTile, yTile, zTile);
lastData = level->getData(xTile, yTile, zTile);
xd = (float) (res->pos->x - x);
yd = (float) (res->pos->y - y);
zd = (float) (res->pos->z - z);
float dd = (float) sqrt(xd * xd + yd * yd + zd * zd);
// 4J added check - zero dd here was creating NaNs
if( dd > 0.0001f )
{
x -= (xd / dd) * 0.05f;
y -= (yd / dd) * 0.05f;
z -= (zd / dd) * 0.05f;
}
playSound(eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f));
inGround = true;
shakeTime = 7;
setCritArrow(false);
if (lastTile != 0)
{
Tile::tiles[lastTile]->entityInside(level, xTile, yTile, zTile, shared_from_this() );
}
}
}
delete res;
if(isCritArrow())
{
for (int i = 0; i < 4; i++)
{
level->addParticle(eParticleType_crit, x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2, -zd);
}
}
x += xd;
y += yd;
z += zd;
double sd = sqrt(xd * xd + zd * zd);
yRot = (float) (atan2(xd, zd) * 180 / PI);
xRot = (float) (atan2(yd, sd) * 180 / PI);
while (xRot - xRotO < -180)
xRotO -= 360;
while (xRot - xRotO >= 180)
xRotO += 360;
while (yRot - yRotO < -180)
yRotO -= 360;
while (yRot - yRotO >= 180)
yRotO += 360;
xRot = xRotO + (xRot - xRotO) * 0.2f;
yRot = yRotO + (yRot - yRotO) * 0.2f;
float inertia = 0.99f;
float gravity = 0.05f;
if (isInWater())
{
for (int i = 0; i < 4; i++)
{
float s = 1 / 4.0f;
level->addParticle(eParticleType_bubble, x - xd * s, y - yd * s, z - zd * s, xd, yd, zd);
}
inertia = 0.80f;
}
xd *= inertia;
yd *= inertia;
zd *= inertia;
yd -= gravity;
setPos(x, y, z);
checkInsideTiles();
}
void Arrow::addAdditonalSaveData(CompoundTag *tag)
{
tag->putShort(L"xTile", (short) xTile);
tag->putShort(L"yTile", (short) yTile);
tag->putShort(L"zTile", (short) zTile);
tag->putByte(L"inTile", (byte) lastTile);
tag->putByte(L"inData", (byte) lastData);
tag->putByte(L"shake", (byte) shakeTime);
tag->putByte(L"inGround", (byte) (inGround ? 1 : 0));
tag->putByte(L"pickup", (byte) pickup);
tag->putDouble(L"damage", baseDamage);
}
void Arrow::readAdditionalSaveData(CompoundTag *tag)
{
xTile = tag->getShort(L"xTile");
yTile = tag->getShort(L"yTile");
zTile = tag->getShort(L"zTile");
lastTile = tag->getByte(L"inTile") & 0xff;
lastData = tag->getByte(L"inData") & 0xff;
shakeTime = tag->getByte(L"shake") & 0xff;
inGround = tag->getByte(L"inGround") == 1;
if (tag->contains(L"damage"))
{
baseDamage = tag->getDouble(L"damage");
}
if (tag->contains(L"pickup"))
{
pickup = tag->getByte(L"pickup");
}
else if (tag->contains(L"player"))
{
pickup = tag->getBoolean(L"player") ? PICKUP_ALLOWED : PICKUP_DISALLOWED;
}
}
void Arrow::playerTouch(shared_ptr<Player> player)
{
if (level->isClientSide || !inGround || shakeTime > 0) return;
bool bRemove = pickup == PICKUP_ALLOWED || (pickup == PICKUP_CREATIVE_ONLY && player->abilities.instabuild);
if (pickup == PICKUP_ALLOWED)
{
if (!player->inventory->add( shared_ptr<ItemInstance>( new ItemInstance(Item::arrow, 1) ) ))
{
bRemove = false;
}
}
if (bRemove)
{
playSound(eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f);
player->take(shared_from_this(), 1);
remove();
}
}
bool Arrow::makeStepSound()
{
return false;
}
float Arrow::getShadowHeightOffs()
{
return 0;
}
void Arrow::setBaseDamage(double baseDamage)
{
this->baseDamage = baseDamage;
}
double Arrow::getBaseDamage()
{
return baseDamage;
}
void Arrow::setKnockback(int knockback)
{
this->knockback = knockback;
}
bool Arrow::isAttackable()
{
return false;
}
void Arrow::setCritArrow(bool critArrow)
{
byte flags = entityData->getByte(ID_FLAGS);
if (critArrow)
{
entityData->set(ID_FLAGS, (byte) (flags | FLAG_CRIT));
}
else
{
entityData->set(ID_FLAGS, (byte) (flags & ~FLAG_CRIT));
}
}
bool Arrow::isCritArrow()
{
byte flags = entityData->getByte(ID_FLAGS);
return (flags & FLAG_CRIT) != 0;
}
+84
View File
@@ -0,0 +1,84 @@
#pragma once
using namespace std;
#include "Entity.h"
#include "Projectile.h"
class Level;
class CompoundTag;
class Arrow : public Entity, public Projectile
{
public:
eINSTANCEOF GetType() { return eTYPE_ARROW; }
static Entity *create(Level *level) { return new Arrow(level); }
private:
// base damage, multiplied with velocity
static const double ARROW_BASE_DAMAGE;
public:
static const int PICKUP_DISALLOWED = 0;
static const int PICKUP_ALLOWED = 1;
static const int PICKUP_CREATIVE_ONLY = 2;
private:
static const int ID_FLAGS = 16;
static const int FLAG_CRIT = 1;
private:
int xTile;
int yTile;
int zTile;
int lastTile;
int lastData;
bool inGround;
public:
int pickup;
int shakeTime;
shared_ptr<Entity> owner;
private:
double baseDamage;
int knockback;
private:
int life;
int flightTime;
// 4J - added common ctor code.
void _init();
public:
Arrow(Level *level);
Arrow(Level *level, shared_ptr<LivingEntity> mob, shared_ptr<LivingEntity> target, float power, float uncertainty);
Arrow(Level *level, double x, double y, double z);
Arrow(Level *level, shared_ptr<LivingEntity> mob, float power);
protected:
virtual void defineSynchedData();
public:
void shoot(double xd, double yd, double zd, float pow, float uncertainty);
virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps);
virtual void lerpMotion(double xd, double yd, double zd);
virtual void tick();
virtual void addAdditonalSaveData(CompoundTag *tag);
virtual void readAdditionalSaveData(CompoundTag *tag);
virtual void playerTouch(shared_ptr<Player> player);
protected:
virtual bool makeStepSound();
public:
virtual float getShadowHeightOffs();
void setBaseDamage(double baseDamage);
double getBaseDamage();
void setKnockback(int knockback);
virtual bool isAttackable();
void setCritArrow(bool critArrow);
bool isCritArrow();
};
@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "ArrowDamageEnchantment.h"
ArrowDamageEnchantment::ArrowDamageEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
{
setDescriptionId(IDS_ENCHANTMENT_ARROW_DAMAGE);
}
int ArrowDamageEnchantment::getMinCost(int level)
{
return 1 + (level - 1) * 10;
}
int ArrowDamageEnchantment::getMaxCost(int level)
{
return getMinCost(level) + 15;
}
int ArrowDamageEnchantment::getMaxLevel()
{
return 5;
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "Enchantment.h"
class ArrowDamageEnchantment : public Enchantment
{
public:
ArrowDamageEnchantment(int id, int frequency);
virtual int getMinCost(int level);
virtual int getMaxCost(int level);
virtual int getMaxLevel();
};
+22
View File
@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "ArrowFireEnchantment.h"
ArrowFireEnchantment::ArrowFireEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
{
setDescriptionId(IDS_ENCHANTMENT_ARROW_FIRE);
}
int ArrowFireEnchantment::getMinCost(int level)
{
return 20;
}
int ArrowFireEnchantment::getMaxCost(int level)
{
return 50;
}
int ArrowFireEnchantment::getMaxLevel()
{
return 1;
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "Enchantment.h"
class ArrowFireEnchantment : public Enchantment
{
public:
ArrowFireEnchantment(int id, int frequency);
virtual int getMinCost(int level);
virtual int getMaxCost(int level);
virtual int getMaxLevel();
};
@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "ArrowInfiniteEnchantment.h"
ArrowInfiniteEnchantment::ArrowInfiniteEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
{
setDescriptionId(IDS_ENCHANTMENT_ARROW_INFINITE);
}
int ArrowInfiniteEnchantment::getMinCost(int level)
{
return 20;
}
int ArrowInfiniteEnchantment::getMaxCost(int level)
{
return 50;
}
int ArrowInfiniteEnchantment::getMaxLevel()
{
return 1;
}
@@ -0,0 +1,13 @@
#pragma once
#include "Enchantment.h"
class ArrowInfiniteEnchantment : public Enchantment
{
public:
ArrowInfiniteEnchantment(int id, int frequency);
virtual int getMinCost(int level);
virtual int getMaxCost(int level);
virtual int getMaxLevel();
};
@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "ArrowKnockbackEnchantment.h"
ArrowKnockbackEnchantment::ArrowKnockbackEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
{
setDescriptionId(IDS_ENCHANTMENT_ARROW_KNOCKBACK);
}
int ArrowKnockbackEnchantment::getMinCost(int level)
{
return 12 + (level - 1) * 20;
}
int ArrowKnockbackEnchantment::getMaxCost(int level)
{
return getMinCost(level) + 25;
}
int ArrowKnockbackEnchantment::getMaxLevel()
{
return 2;
}
@@ -0,0 +1,13 @@
#pragma once
#include "Enchantment.h"
class ArrowKnockbackEnchantment : public Enchantment
{
public:
ArrowKnockbackEnchantment(int id, int frequency);
virtual int getMinCost(int level);
virtual int getMaxCost(int level);
virtual int getMaxLevel();
};
+19
View File
@@ -0,0 +1,19 @@
#include "stdafx.h"
#include "AttackDamageMobEffect.h"
AttackDamageMobEffect::AttackDamageMobEffect(int id, bool isHarmful, eMinecraftColour color) : MobEffect(id, isHarmful, color)
{
}
double AttackDamageMobEffect::getAttributeModifierValue(int amplifier, AttributeModifier *original)
{
if (id == MobEffect::weakness->id)
{
return -0.5f * (amplifier + 1);
}
else
{
return 1.3 * (amplifier + 1);
}
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "MobEffect.h"
class AttributeModifier;
class AttackDamageMobEffect : public MobEffect
{
public:
AttackDamageMobEffect(int id, bool isHarmful, eMinecraftColour color);
double getAttributeModifierValue(int amplifier, AttributeModifier *original);
};
+18
View File
@@ -0,0 +1,18 @@
#include "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];
}
+71
View File
@@ -0,0 +1,71 @@
#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 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 string ID for attribute
static int getName(eATTRIBUTE_ID id);
protected:
static const int AttributeNames [];
};
#ifdef __ORBIS__
typedef unordered_map<eATTRIBUTE_ID, AttributeModifier *, std::hash<int>> attrAttrModMap;
#else
typedef unordered_map<eATTRIBUTE_ID, AttributeModifier *> attrAttrModMap;
#endif
+22
View File
@@ -0,0 +1,22 @@
#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 unordered_set<AttributeModifier *> *getModifiers(int operation) = 0;
virtual void getModifiers(unordered_set<AttributeModifier *>& result) = 0;
virtual AttributeModifier *getModifier(eMODIFIER_ID id) = 0;
virtual void addModifiers(unordered_set<AttributeModifier *> *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;
};
+129
View File
@@ -0,0 +1,129 @@
#include "stdafx.h"
#include "AttributeModifier.h"
#include "HtmlString.h"
void AttributeModifier::_init(eMODIFIER_ID id, const 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;
}
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;
}
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);
}
+69
View File
@@ -0,0 +1,69 @@
#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;
wstring name;
eMODIFIER_ID id;
bool serialize;
void _init(eMODIFIER_ID id, const wstring name, double amount, int operation);
public:
AttributeModifier(double amount, int operation);
AttributeModifier(eMODIFIER_ID id, double amount, int operation);
eMODIFIER_ID getId();
wstring getName();
int getOperation();
double getAmount();
bool isSerializable();
AttributeModifier *setSerialize(bool serialize);
bool equals(AttributeModifier *modifier);
wstring toString();
HtmlString getHoverText(eATTRIBUTE_ID attribute); // 4J: Added to keep modifier readable string creation in one place
};
+21
View File
@@ -0,0 +1,21 @@
#include "stdafx.h"
#include "net.minecraft.world.level.tile.h"
#include "AuxDataTileItem.h"
AuxDataTileItem::AuxDataTileItem(int id, Tile *parentTile) : TileItem(id)
{
this->parentTile = parentTile;
setMaxDamage(0);
setStackedByData(true);
}
Icon *AuxDataTileItem::getIcon(int itemAuxValue)
{
return parentTile->getTexture(2, itemAuxValue);
}
int AuxDataTileItem::getLevelDataForAuxValue(int auxValue)
{
return auxValue;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include "TileItem.h"
class Tile;
class AuxDataTileItem : public TileItem
{
private:
Tile *parentTile;
public:
AuxDataTileItem(int id, Tile *parentTile);
Icon *getIcon(int itemAuxValue);
int getLevelDataForAuxValue(int auxValue);
};
+96
View File
@@ -0,0 +1,96 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.ai.control.h"
#include "net.minecraft.world.entity.ai.navigation.h"
#include "net.minecraft.world.entity.ai.sensing.h"
#include "net.minecraft.world.entity.ai.util.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.animal.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.pathfinder.h"
#include "net.minecraft.world.phys.h"
#include "AvoidPlayerGoal.h"
AvoidPlayerGoalEntitySelector::AvoidPlayerGoalEntitySelector(AvoidPlayerGoal *parent)
{
m_parent = parent;
}
bool AvoidPlayerGoalEntitySelector::matches(shared_ptr<Entity> entity) const
{
return entity->isAlive() && m_parent->mob->getSensing()->canSee(entity);
}
AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, double walkSpeedModifier, double sprintSpeedModifier) : avoidType(avoidType)
{
this->mob = mob;
//this->avoidType = avoidType;
this->maxDist = maxDist;
this->walkSpeedModifier = walkSpeedModifier;
this->sprintSpeedModifier = sprintSpeedModifier;
this->pathNav = mob->getNavigation();
setRequiredControlFlags(Control::MoveControlFlag);
entitySelector = new AvoidPlayerGoalEntitySelector(this);
toAvoid = weak_ptr<Entity>();
path = NULL;
}
AvoidPlayerGoal::~AvoidPlayerGoal()
{
if(path != NULL) delete path;
delete entitySelector;
}
bool AvoidPlayerGoal::canUse()
{
if (avoidType == typeid(Player))
{
shared_ptr<TamableAnimal> tamableAnimal = dynamic_pointer_cast<TamableAnimal>(mob->shared_from_this());
if (tamableAnimal != NULL && tamableAnimal->isTame()) return false;
toAvoid = weak_ptr<Entity>(mob->level->getNearestPlayer(mob->shared_from_this(), maxDist));
if (toAvoid.lock() == NULL) return false;
}
else
{
vector<shared_ptr<Entity> > *entities = mob->level->getEntitiesOfClass(avoidType, mob->bb->grow(maxDist, 3, maxDist), entitySelector);
if (entities->empty())
{
delete entities;
return false;
}
toAvoid = weak_ptr<Entity>(entities->at(0));
delete entities;
}
Vec3 *pos = RandomPos::getPosAvoid(dynamic_pointer_cast<PathfinderMob>(mob->shared_from_this()), 16, 7, Vec3::newTemp(toAvoid.lock()->x, toAvoid.lock()->y, toAvoid.lock()->z));
if (pos == NULL) return false;
if (toAvoid.lock()->distanceToSqr(pos->x, pos->y, pos->z) < toAvoid.lock()->distanceToSqr(mob->shared_from_this())) return false;
delete path;
path = pathNav->createPath(pos->x, pos->y, pos->z);
if (path == NULL) return false;
if (!path->endsInXZ(pos)) return false;
return true;
}
bool AvoidPlayerGoal::canContinueToUse()
{
return toAvoid.lock() != NULL && !pathNav->isDone();
}
void AvoidPlayerGoal::start()
{
pathNav->moveTo(path, walkSpeedModifier);
path = NULL;
}
void AvoidPlayerGoal::stop()
{
toAvoid = weak_ptr<Entity>();
}
void AvoidPlayerGoal::tick()
{
if (mob->distanceToSqr(toAvoid.lock()) < 7 * 7) mob->getNavigation()->setSpeedModifier(sprintSpeedModifier);
else mob->getNavigation()->setSpeedModifier(walkSpeedModifier);
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include "Goal.h"
#include "EntitySelector.h"
class PathNavigation;
class PathfinderMob;
class Path;
class AvoidPlayerGoal;
class AvoidPlayerGoalEntitySelector : public EntitySelector
{
private:
AvoidPlayerGoal *m_parent;
public:
AvoidPlayerGoalEntitySelector(AvoidPlayerGoal *parent);
bool matches(shared_ptr<Entity> entity) const;
};
class AvoidPlayerGoal : public Goal
{
friend class AvoidPlayerGoalEntitySelector;
private:
PathfinderMob *mob; // Owner of this goal
double walkSpeedModifier, sprintSpeedModifier;
weak_ptr<Entity> toAvoid;
float maxDist;
Path *path;
PathNavigation *pathNav;
const type_info& avoidType;
EntitySelector *entitySelector;
public:
AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, double walkSpeedModifier, double sprintSpeedModifier);
~AvoidPlayerGoal();
virtual bool canUse();
virtual bool canContinueToUse();
virtual void start();
virtual void stop();
virtual void tick();
};
+89
View File
@@ -0,0 +1,89 @@
#include "stdafx.h"
#include <iostream>
#include "InputOutputStream.h"
#include "PacketListener.h"
#include "AwardStatPacket.h"
AwardStatPacket::AwardStatPacket()
{
this->m_paramData.data = NULL;
this->m_paramData.length = 0;
}
AwardStatPacket::AwardStatPacket(int statId, int count)
{
this->statId = statId;
this->m_paramData.data = (byte *) new int(count);
this->m_paramData.length = sizeof(int);
}
AwardStatPacket::AwardStatPacket(int statId, byteArray paramData)
{
this->statId = statId;
this->m_paramData = paramData;
}
AwardStatPacket::~AwardStatPacket()
{
if (m_paramData.data != NULL)
{
delete [] m_paramData.data;
m_paramData.data = NULL;
}
}
void AwardStatPacket::handle(PacketListener *listener)
{
listener->handleAwardStat(shared_from_this());
m_paramData.data = NULL;
}
void AwardStatPacket::read(DataInputStream *dis) //throws IOException
{
statId = dis->readInt();
// Read parameter blob.
int length = dis->readInt();
if(length > 0)
{
m_paramData = byteArray(length);
dis->readFully(m_paramData);
}
}
void AwardStatPacket::write(DataOutputStream *dos) //throws IOException
{
dos->writeInt(statId);
dos->writeInt(m_paramData.length);
if(m_paramData.length > 0) dos->write(m_paramData);
}
int AwardStatPacket::getEstimatedSize()
{
return 6;
}
bool AwardStatPacket::isAync()
{
return true;
}
// On most platforms we only store 'count' in an AwardStatPacket.
int AwardStatPacket::getCount()
{
#ifdef _DURANGO
assert(false); // Method not supported on Durango.
return 0;
#else
return *((int*)this->m_paramData.data);
#endif
}
// On Durango we store 'Event' parameters here in a blob.
byteArray AwardStatPacket::getParamData()
{
return m_paramData;
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
using namespace std;
#include "Packet.h"
class AwardStatPacket : public Packet, public enable_shared_from_this<AwardStatPacket>
{
public:
int statId;
// 4J-JEV: Changed to allow for Durango events.
protected:
byteArray m_paramData;
public:
AwardStatPacket();
AwardStatPacket(int statId, int count);
AwardStatPacket(int statId, byteArray paramData);
~AwardStatPacket();
virtual void handle(PacketListener *listener);
virtual void read(DataInputStream *dis);
virtual void write(DataOutputStream *dos);
virtual int getEstimatedSize();
virtual bool isAync();
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AwardStatPacket()); }
virtual int getId() { return 200; }
public:
// 4J-JEV: New getters to help prevent unsafe access
int getCount();
byteArray getParamData();
};
+31
View File
@@ -0,0 +1,31 @@
#include "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;
}
+20
View File
@@ -0,0 +1,20 @@
#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);
};
+82
View File
@@ -0,0 +1,82 @@
#include "stdafx.h"
#include "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(vector<AttributeInstance *>& atts)
{
for(AUTO_VAR(it,attributesById.begin()); it != attributesById.end(); ++it)
{
atts.push_back(it->second);
}
}
void BaseAttributeMap::onAttributeModified(ModifiableAttributeInstance *attributeInstance)
{
}
void BaseAttributeMap::removeItemModifiers(shared_ptr<ItemInstance> 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(shared_ptr<ItemInstance> 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;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
class ModifiableAttributeInstance;
class BaseAttributeMap
{
protected:
//unordered_map<Attribute *, AttributeInstance *> attributesByObject;
#ifdef __ORBIS__
unordered_map<eATTRIBUTE_ID, AttributeInstance *, std::hash<int> > attributesById;
#else
unordered_map<eATTRIBUTE_ID, AttributeInstance *> 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(vector<AttributeInstance *>& 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(shared_ptr<ItemInstance> item);
virtual void addItemModifiers(shared_ptr<ItemInstance> item);
};
+33
View File
@@ -0,0 +1,33 @@
#include "stdafx.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.entity.h"
#include "TileEntity.h"
#include "BaseEntityTile.h"
BaseEntityTile::BaseEntityTile(int id, Material *material, bool isSolidRender /*= true*/) : Tile(id, material, isSolidRender)
{
_isEntityTile = true;
}
void BaseEntityTile::onPlace(Level *level, int x, int y, int z)
{
Tile::onPlace(level, x, y, z);
//level->setTileEntity(x, y, z, newTileEntity(level));
}
void BaseEntityTile::onRemove(Level *level, int x, int y, int z, int id, int data)
{
Tile::onRemove(level, x, y, z, id, data);
level->removeTileEntity(x, y, z);
}
bool BaseEntityTile::triggerEvent(Level *level, int x, int y, int z, int b0, int b1)
{
Tile::triggerEvent(level, x, y, z, b0, b1);
shared_ptr<TileEntity> te = level->getTileEntity(x, y, z);
if (te != NULL)
{
return te->triggerEvent(b0, b1);
}
return false;
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "Tile.h"
#include "EntityTile.h"
class TileEntity;
class BaseEntityTile : public Tile, public EntityTile
{
protected:
BaseEntityTile(int id, Material *material, bool isSolidRender = true);
public:
virtual void onPlace(Level *level, int x, int y, int z);
virtual void onRemove(Level *level, int x, int y, int z, int id, int data);
virtual bool triggerEvent(Level *level, int x, int y, int z, int b0, int b1);
};
+401
View File
@@ -0,0 +1,401 @@
#include "stdafx.h"
#include "net.minecraft.world.entity.h"
#include "net.minecraft.world.entity.item.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.phys.h"
#include "BaseMobSpawner.h"
BaseMobSpawner::BaseMobSpawner()
{
spawnPotentials = NULL;
spawnDelay = 20;
entityId = L"Pig";
nextSpawnData = NULL;
spin = oSpin = 0.0;
minSpawnDelay = SharedConstants::TICKS_PER_SECOND * 10;
maxSpawnDelay = SharedConstants::TICKS_PER_SECOND * 40;
spawnCount = 4;
displayEntity = nullptr;
maxNearbyEntities = 6;
requiredPlayerRange = 16;
spawnRange = 4;
}
BaseMobSpawner::~BaseMobSpawner()
{
if(spawnPotentials)
{
for(AUTO_VAR(it,spawnPotentials->begin()); it != spawnPotentials->end(); ++it)
{
delete *it;
}
delete spawnPotentials;
}
}
wstring BaseMobSpawner::getEntityId()
{
if (getNextSpawnData() == NULL)
{
if (entityId.compare(L"Minecart") == 0)
{
entityId = L"MinecartRideable";
}
return entityId;
}
else
{
return getNextSpawnData()->type;
}
}
void BaseMobSpawner::setEntityId(const wstring &entityId)
{
this->entityId = entityId;
}
bool BaseMobSpawner::isNearPlayer()
{
return getLevel()->getNearestPlayer(getX() + 0.5, getY() + 0.5, getZ() + 0.5, requiredPlayerRange) != NULL;
}
void BaseMobSpawner::tick()
{
if (!isNearPlayer())
{
return;
}
if (getLevel()->isClientSide)
{
double xP = getX() + getLevel()->random->nextFloat();
double yP = getY() + getLevel()->random->nextFloat();
double zP = getZ() + getLevel()->random->nextFloat();
getLevel()->addParticle(eParticleType_smoke, xP, yP, zP, 0, 0, 0);
getLevel()->addParticle(eParticleType_flame, xP, yP, zP, 0, 0, 0);
if (spawnDelay > 0) spawnDelay--;
oSpin = spin;
spin = (int)(spin + 1000 / (spawnDelay + 200.0f)) % 360;
}
else
{
if (spawnDelay == -1) delay();
if (spawnDelay > 0)
{
spawnDelay--;
return;
}
bool _delay = false;
for (int c = 0; c < spawnCount; c++)
{
shared_ptr<Entity> entity = EntityIO::newEntity(getEntityId(), getLevel());
if (entity == NULL) return;
int nearBy = getLevel()->getEntitiesOfClass( typeid(entity.get()), AABB::newTemp(getX(), getY(), getZ(), getX() + 1, getY() + 1, getZ() + 1)->grow(spawnRange * 2, 4, spawnRange * 2))->size();
if (nearBy >= maxNearbyEntities)
{
delay();
return;
}
double xp = getX() + (getLevel()->random->nextDouble() - getLevel()->random->nextDouble()) * spawnRange;
double yp = getY() + getLevel()->random->nextInt(3) - 1;
double zp = getZ() + (getLevel()->random->nextDouble() - getLevel()->random->nextDouble()) * spawnRange;
shared_ptr<Mob> mob = entity->instanceof(eTYPE_MOB) ? dynamic_pointer_cast<Mob>( entity ) : nullptr;
entity->moveTo(xp, yp, zp, getLevel()->random->nextFloat() * 360, 0);
if (mob == NULL || mob->canSpawn())
{
loadDataAndAddEntity(entity);
getLevel()->levelEvent(LevelEvent::PARTICLES_MOBTILE_SPAWN, getX(), getY(), getZ(), 0);
if (mob != NULL)
{
mob->spawnAnim();
}
_delay = true;
}
}
if (_delay) delay();
}
}
shared_ptr<Entity> BaseMobSpawner::loadDataAndAddEntity(shared_ptr<Entity> entity)
{
if (getNextSpawnData() != NULL)
{
CompoundTag *data = new CompoundTag();
entity->save(data);
vector<Tag *> *tags = getNextSpawnData()->tag->getAllTags();
for (AUTO_VAR(it, tags->begin()); it != tags->end(); ++it)
{
Tag *tag = *it;
data->put(tag->getName(), tag->copy());
}
delete tags;
entity->load(data);
if (entity->level != NULL) entity->level->addEntity(entity);
// add mounts
shared_ptr<Entity> rider = entity;
while (data->contains(Entity::RIDING_TAG))
{
CompoundTag *ridingTag = data->getCompound(Entity::RIDING_TAG);
shared_ptr<Entity> mount = EntityIO::newEntity(ridingTag->getString(L"id"), entity->level);
if (mount != NULL)
{
CompoundTag *mountData = new CompoundTag();
mount->save(mountData);
vector<Tag *> *ridingTags = ridingTag->getAllTags();
for (AUTO_VAR(it, ridingTags->begin()); it != ridingTags->end(); ++it)
{
Tag *tag = *it;
mountData->put(tag->getName(), tag->copy());
}
delete ridingTags;
mount->load(mountData);
mount->moveTo(rider->x, rider->y, rider->z, rider->yRot, rider->xRot);
if (entity->level != NULL) entity->level->addEntity(mount);
rider->ride(mount);
}
rider = mount;
data = ridingTag;
}
}
else if (entity->instanceof(eTYPE_LIVINGENTITY) && entity->level != NULL)
{
dynamic_pointer_cast<Mob>( entity )->finalizeMobSpawn(NULL);
getLevel()->addEntity(entity);
}
return entity;
}
void BaseMobSpawner::delay()
{
if (maxSpawnDelay <= minSpawnDelay)
{
spawnDelay = minSpawnDelay;
}
else
{
spawnDelay = minSpawnDelay + getLevel()->random->nextInt(maxSpawnDelay - minSpawnDelay);
}
if ( (spawnPotentials != NULL) && (spawnPotentials->size() > 0) )
{
setNextSpawnData( (SpawnData*) WeighedRandom::getRandomItem((Random*)getLevel()->random, (vector<WeighedRandomItem*>*)spawnPotentials) );
}
broadcastEvent(EVENT_SPAWN);
}
void BaseMobSpawner::load(CompoundTag *tag)
{
entityId = tag->getString(L"EntityId");
spawnDelay = tag->getShort(L"Delay");
if (tag->contains(L"SpawnPotentials"))
{
spawnPotentials = new vector<SpawnData *>();
ListTag<CompoundTag> *potentials = (ListTag<CompoundTag> *) tag->getList(L"SpawnPotentials");
for (int i = 0; i < potentials->size(); i++)
{
spawnPotentials->push_back(new SpawnData(potentials->get(i)));
}
}
else
{
spawnPotentials = NULL;
}
if (tag->contains(L"SpawnData"))
{
setNextSpawnData(new SpawnData(tag->getCompound(L"SpawnData"), entityId));
}
else
{
setNextSpawnData(NULL);
}
if (tag->contains(L"MinSpawnDelay"))
{
minSpawnDelay = tag->getShort(L"MinSpawnDelay");
maxSpawnDelay = tag->getShort(L"MaxSpawnDelay");
spawnCount = tag->getShort(L"SpawnCount");
}
if (tag->contains(L"MaxNearbyEntities"))
{
maxNearbyEntities = tag->getShort(L"MaxNearbyEntities");
requiredPlayerRange = tag->getShort(L"RequiredPlayerRange");
}
if (tag->contains(L"SpawnRange")) spawnRange = tag->getShort(L"SpawnRange");
if (getLevel() != NULL && getLevel()->isClientSide)
{
displayEntity = nullptr;
}
}
void BaseMobSpawner::save(CompoundTag *tag)
{
tag->putString(L"EntityId", getEntityId());
tag->putShort(L"Delay", (short) spawnDelay);
tag->putShort(L"MinSpawnDelay", (short) minSpawnDelay);
tag->putShort(L"MaxSpawnDelay", (short) maxSpawnDelay);
tag->putShort(L"SpawnCount", (short) spawnCount);
tag->putShort(L"MaxNearbyEntities", (short) maxNearbyEntities);
tag->putShort(L"RequiredPlayerRange", (short) requiredPlayerRange);
tag->putShort(L"SpawnRange", (short) spawnRange);
if (getNextSpawnData() != NULL)
{
tag->putCompound(L"SpawnData", (CompoundTag *) getNextSpawnData()->tag->copy());
}
if (getNextSpawnData() != NULL || (spawnPotentials != NULL && spawnPotentials->size() > 0))
{
ListTag<CompoundTag> *list = new ListTag<CompoundTag>();
if (spawnPotentials != NULL && spawnPotentials->size() > 0)
{
for (AUTO_VAR(it, spawnPotentials->begin()); it != spawnPotentials->end(); ++it)
{
SpawnData *data = *it;
list->add(data->save());
}
}
else
{
list->add(getNextSpawnData()->save());
}
tag->put(L"SpawnPotentials", list);
}
}
shared_ptr<Entity> BaseMobSpawner::getDisplayEntity()
{
if (displayEntity == NULL)
{
shared_ptr<Entity> e = EntityIO::newEntity(getEntityId(), NULL);
e = loadDataAndAddEntity(e);
displayEntity = e;
}
return displayEntity;
}
bool BaseMobSpawner::onEventTriggered(int id)
{
if (id == EVENT_SPAWN && getLevel()->isClientSide)
{
spawnDelay = minSpawnDelay;
return true;
}
return false;
}
BaseMobSpawner::SpawnData *BaseMobSpawner::getNextSpawnData()
{
return nextSpawnData;
}
void BaseMobSpawner::setNextSpawnData(SpawnData *nextSpawnData)
{
this->nextSpawnData = nextSpawnData;
}
BaseMobSpawner::SpawnData::SpawnData(CompoundTag *base) : WeighedRandomItem(base->getInt(L"Weight"))
{
CompoundTag *tag = base->getCompound(L"Properties");
wstring _type = base->getString(L"Type");
if (_type.compare(L"Minecart") == 0)
{
if (tag != NULL)
{
switch (tag->getInt(L"Type"))
{
case Minecart::TYPE_CHEST:
type = L"MinecartChest";
break;
case Minecart::TYPE_FURNACE:
type = L"MinecartFurnace";
break;
case Minecart::TYPE_RIDEABLE:
type = L"MinecartRideable";
break;
}
}
else
{
type = L"MinecartRideable";
}
}
this->tag = tag;
this->type = _type;
}
BaseMobSpawner::SpawnData::SpawnData(CompoundTag *tag, wstring _type) : WeighedRandomItem(1)
{
if (_type.compare(L"Minecart") == 0)
{
if (tag != NULL)
{
switch (tag->getInt(L"Type"))
{
case Minecart::TYPE_CHEST:
_type = L"MinecartChest";
break;
case Minecart::TYPE_FURNACE:
_type = L"MinecartFurnace";
break;
case Minecart::TYPE_RIDEABLE:
_type = L"MinecartRideable";
break;
}
}
else
{
_type = L"MinecartRideable";
}
}
this->tag = tag;
this->type = _type;
}
BaseMobSpawner::SpawnData::~SpawnData()
{
delete tag;
}
CompoundTag *BaseMobSpawner::SpawnData::save()
{
CompoundTag *result = new CompoundTag();
result->putCompound(L"Properties", tag);
result->putString(L"Type", type);
result->putInt(L"Weight", randomWeight);
return result;
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include "WeighedRandom.h"
class BaseMobSpawner
{
public:
class SpawnData : public WeighedRandomItem
{
public:
CompoundTag *tag;
wstring type;
SpawnData(CompoundTag *base);
SpawnData(CompoundTag *tag, wstring type);
~SpawnData();
virtual CompoundTag *save();
};
private:
static const int EVENT_SPAWN = 1;
public:
int spawnDelay;
private:
wstring entityId;
vector<SpawnData *> *spawnPotentials;
SpawnData *nextSpawnData;
public:
double spin, oSpin;
private:
int minSpawnDelay;
int maxSpawnDelay;
int spawnCount;
shared_ptr<Entity> displayEntity;
int maxNearbyEntities;
int requiredPlayerRange;
int spawnRange;
public:
BaseMobSpawner();
~BaseMobSpawner();
virtual wstring getEntityId();
virtual void setEntityId(const wstring &entityId);
virtual bool isNearPlayer();
virtual void tick();
virtual shared_ptr<Entity> loadDataAndAddEntity(shared_ptr<Entity> entity);
private:
virtual void delay();
public:
virtual void load(CompoundTag *tag);
virtual void save(CompoundTag *tag);
virtual shared_ptr<Entity> getDisplayEntity();
virtual bool onEventTriggered(int id);
virtual SpawnData *getNextSpawnData();
virtual void setNextSpawnData(SpawnData *nextSpawnData);
virtual void broadcastEvent(int id) = 0;
virtual Level *getLevel() = 0;
virtual int getX() = 0;
virtual int getY() = 0;
virtual int getZ() = 0;
};
+189
View File
@@ -0,0 +1,189 @@
#include "stdafx.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.redstone.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.phys.h"
#include "net.minecraft.h"
#include "net.minecraft.world.h"
#include "BasePressurePlateTile.h"
BasePressurePlateTile::BasePressurePlateTile(int id, const wstring &tex, Material *material) : Tile(id, material, isSolidRender())
{
texture = tex;
setTicking(true);
// 4J Stu - Move this to derived classes
//updateShape(getDataForSignal(Redstone::SIGNAL_MAX));
}
void BasePressurePlateTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr<TileEntity> forceEntity)
{
updateShape(level->getData(x, y, z));
}
void BasePressurePlateTile::updateShape(int data)
{
bool pressed = getSignalForData(data) > Redstone::SIGNAL_NONE;
float o = 1 / 16.0f;
if (pressed)
{
setShape(o, 0, o, 1 - o, 0.5f / 16.0f, 1 - o);
}
else
{
setShape(o, 0, o, 1 - o, 1 / 16.0f, 1 - o);
}
}
int BasePressurePlateTile::getTickDelay(Level *level)
{
return SharedConstants::TICKS_PER_SECOND;
}
AABB *BasePressurePlateTile::getAABB(Level *level, int x, int y, int z)
{
return NULL;
}
bool BasePressurePlateTile::isSolidRender(bool isServerLevel)
{
return false;
}
bool BasePressurePlateTile::blocksLight()
{
return false;
}
bool BasePressurePlateTile::isCubeShaped()
{
return false;
}
bool BasePressurePlateTile::isPathfindable(LevelSource *level, int x, int y, int z)
{
return true;
}
bool BasePressurePlateTile::mayPlace(Level *level, int x, int y, int z)
{
return level->isTopSolidBlocking(x, y - 1, z) || FenceTile::isFence(level->getTile(x, y - 1, z));
}
void BasePressurePlateTile::neighborChanged(Level *level, int x, int y, int z, int type)
{
bool replace = false;
if (!level->isTopSolidBlocking(x, y - 1, z) && !FenceTile::isFence(level->getTile(x, y - 1, z))) replace = true;
if (replace)
{
spawnResources(level, x, y, z, level->getData(x, y, z), 0);
level->removeTile(x, y, z);
}
}
void BasePressurePlateTile::tick(Level *level, int x, int y, int z, Random *random)
{
if (level->isClientSide) return;
int signal = getSignalForData(level->getData(x, y, z));
if (signal > Redstone::SIGNAL_NONE) checkPressed(level, x, y, z, signal);
}
void BasePressurePlateTile::entityInside(Level *level, int x, int y, int z, shared_ptr<Entity> entity)
{
if (level->isClientSide) return;
int signal = getSignalForData(level->getData(x, y, z));
if (signal == Redstone::SIGNAL_NONE) checkPressed(level, x, y, z, signal);
}
void BasePressurePlateTile::checkPressed(Level *level, int x, int y, int z, int oldSignal)
{
int signal = getSignalStrength(level, x, y, z);
bool wasPressed = oldSignal > Redstone::SIGNAL_NONE;
bool shouldBePressed = signal > Redstone::SIGNAL_NONE;
if (oldSignal != signal)
{
level->setData(x, y, z, getDataForSignal(signal), Tile::UPDATE_CLIENTS);
updateNeighbours(level, x, y, z);
level->setTilesDirty(x, y, z, x, y, z);
}
if (!shouldBePressed && wasPressed)
{
level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.5f);
}
else if (shouldBePressed && !wasPressed)
{
level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f);
}
if (shouldBePressed)
{
level->addToTickNextTick(x, y, z, id, getTickDelay(level));
}
}
AABB *BasePressurePlateTile::getSensitiveAABB(int x, int y, int z)
{
float b = 2 / 16.0f;
return AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 0.25, z + 1 - b);
}
void BasePressurePlateTile::onRemove(Level *level, int x, int y, int z, int id, int data)
{
if (getSignalForData(data) > 0)
{
updateNeighbours(level, x, y, z);
}
Tile::onRemove(level, x, y, z, id, data);
}
void BasePressurePlateTile::updateNeighbours(Level *level, int x, int y, int z)
{
level->updateNeighborsAt(x, y, z, id);
level->updateNeighborsAt(x, y - 1, z, id);
}
int BasePressurePlateTile::getSignal(LevelSource *level, int x, int y, int z, int dir)
{
return getSignalForData(level->getData(x, y, z));
}
int BasePressurePlateTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir)
{
if (dir == Facing::UP)
{
return getSignalForData(level->getData(x, y, z));
}
else
{
return Redstone::SIGNAL_NONE;
}
}
bool BasePressurePlateTile::isSignalSource()
{
return true;
}
void BasePressurePlateTile::updateDefaultShape()
{
float x = 8 / 16.0f;
float y = 2 / 16.0f;
float z = 8 / 16.0f;
setShape(0.5f - x, 0.5f - y, 0.5f - z, 0.5f + x, 0.5f + y, 0.5f + z);
}
int BasePressurePlateTile::getPistonPushReaction()
{
return Material::PUSH_DESTROY;
}
void BasePressurePlateTile::registerIcons(IconRegister *iconRegister)
{
icon = iconRegister->registerIcon(texture);
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "Tile.h"
class BasePressurePlateTile : public Tile
{
private:
wstring texture;
protected:
BasePressurePlateTile(int id, const wstring &tex, Material *material);
public:
virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr<TileEntity> forceEntity = shared_ptr<TileEntity>());
protected:
virtual void updateShape(int data);
public:
virtual int getTickDelay(Level *level);
virtual AABB *getAABB(Level *level, int x, int y, int z);
virtual bool isSolidRender(bool isServerLevel = false);
virtual bool blocksLight();
virtual bool isCubeShaped();
virtual bool isPathfindable(LevelSource *level, int x, int y, int z);
virtual bool mayPlace(Level *level, int x, int y, int z);
virtual void neighborChanged(Level *level, int x, int y, int z, int type);
virtual void tick(Level *level, int x, int y, int z, Random *random);
virtual void entityInside(Level *level, int x, int y, int z, shared_ptr<Entity> entity);
protected:
virtual void checkPressed(Level *level, int x, int y, int z, int oldSignal);
virtual AABB *getSensitiveAABB(int x, int y, int z);
public:
virtual void onRemove(Level *level, int x, int y, int z, int id, int data);
protected:
virtual void updateNeighbours(Level *level, int x, int y, int z);
public:
virtual int getSignal(LevelSource *level, int x, int y, int z, int dir);
virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir);
virtual bool isSignalSource();
virtual void updateDefaultShape();
virtual int getPistonPushReaction();
protected:
virtual int getSignalStrength(Level *level, int x, int y, int z) = 0;
virtual int getSignalForData(int data) = 0;
virtual int getDataForSignal(int signal) = 0;
public:
virtual void registerIcons(IconRegister *iconRegister);
};
+511
View File
@@ -0,0 +1,511 @@
#include "stdafx.h"
#include "net.minecraft.world.phys.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.h"
#include "BaseRailTile.h"
BaseRailTile::Rail::Rail(Level *level, int x, int y, int z)
{
this->level = level;
this->x = x;
this->y = y;
this->z = z;
int id = level->getTile(x, y, z);
// 4J Stu - We saw a random crash near the end of development on XboxOne orignal version where the id here isn't a tile any more
// Adding this check in to avoid that crash
m_bValidRail = isRail(id);
if(m_bValidRail)
{
int direction = level->getData(x, y, z);
if (((BaseRailTile *) Tile::tiles[id])->usesDataBit)
{
usesDataBit = true;
direction = direction & ~RAIL_DATA_BIT;
}
else
{
usesDataBit = false;
}
updateConnections(direction);
}
}
BaseRailTile::Rail::~Rail()
{
for( int i = 0; i < connections.size(); i++ )
{
delete connections[i];
}
}
void BaseRailTile::Rail::updateConnections(int direction)
{
if(m_bValidRail)
{
for( int i = 0; i < connections.size(); i++ )
{
delete connections[i];
}
connections.clear();
MemSect(50);
if (direction == DIR_FLAT_Z)
{
connections.push_back(new TilePos(x, y, z - 1));
connections.push_back(new TilePos(x, y, z + 1));
} else if (direction == DIR_FLAT_X)
{
connections.push_back(new TilePos(x - 1, y, z));
connections.push_back(new TilePos(x + 1, y, z));
} else if (direction == 2)
{
connections.push_back(new TilePos(x - 1, y, z));
connections.push_back(new TilePos(x + 1, y + 1, z));
} else if (direction == 3)
{
connections.push_back(new TilePos(x - 1, y + 1, z));
connections.push_back(new TilePos(x + 1, y, z));
} else if (direction == 4)
{
connections.push_back(new TilePos(x, y + 1, z - 1));
connections.push_back(new TilePos(x, y, z + 1));
} else if (direction == 5)
{
connections.push_back(new TilePos(x, y, z - 1));
connections.push_back(new TilePos(x, y + 1, z + 1));
} else if (direction == 6)
{
connections.push_back(new TilePos(x + 1, y, z));
connections.push_back(new TilePos(x, y, z + 1));
} else if (direction == 7)
{
connections.push_back(new TilePos(x - 1, y, z));
connections.push_back(new TilePos(x, y, z + 1));
} else if (direction == 8)
{
connections.push_back(new TilePos(x - 1, y, z));
connections.push_back(new TilePos(x, y, z - 1));
} else if (direction == 9)
{
connections.push_back(new TilePos(x + 1, y, z));
connections.push_back(new TilePos(x, y, z - 1));
}
MemSect(0);
}
}
void BaseRailTile::Rail::removeSoftConnections()
{
if(m_bValidRail)
{
for (unsigned int i = 0; i < connections.size(); i++)
{
Rail *rail = getRail(connections[i]);
if (rail == NULL || !rail->connectsTo(this))
{
delete connections[i];
connections.erase(connections.begin()+i);
i--;
} else
{
delete connections[i];
MemSect(50);
connections[i] =new TilePos(rail->x, rail->y, rail->z);
MemSect(0);
}
delete rail;
}
}
}
bool BaseRailTile::Rail::hasRail(int x, int y, int z)
{
if(!m_bValidRail) return false;
if (isRail(level, x, y, z)) return true;
if (isRail(level, x, y + 1, z)) return true;
if (isRail(level, x, y - 1, z)) return true;
return false;
}
BaseRailTile::Rail *BaseRailTile::Rail::getRail(TilePos *p)
{
if(!m_bValidRail) return NULL;
if (isRail(level, p->x, p->y, p->z)) return new Rail(level, p->x, p->y, p->z);
if (isRail(level, p->x, p->y + 1, p->z)) return new Rail(level, p->x, p->y + 1, p->z);
if (isRail(level, p->x, p->y - 1, p->z)) return new Rail(level, p->x, p->y - 1, p->z);
return NULL;
}
bool BaseRailTile::Rail::connectsTo(Rail *rail)
{
if(m_bValidRail)
{
AUTO_VAR(itEnd, connections.end());
for (AUTO_VAR(it, connections.begin()); it != itEnd; it++)
{
TilePos *p = *it; //connections[i];
if (p->x == rail->x && p->z == rail->z)
{
return true;
}
}
}
return false;
}
bool BaseRailTile::Rail::hasConnection(int x, int y, int z)
{
if(m_bValidRail)
{
AUTO_VAR(itEnd, connections.end());
for (AUTO_VAR(it, connections.begin()); it != itEnd; it++)
{
TilePos *p = *it; //connections[i];
if (p->x == x && p->z == z)
{
return true;
}
}
}
return false;
}
int BaseRailTile::Rail::countPotentialConnections()
{
int count = 0;
if(m_bValidRail)
{
if (hasRail(x, y, z - 1)) count++;
if (hasRail(x, y, z + 1)) count++;
if (hasRail(x - 1, y, z)) count++;
if (hasRail(x + 1, y, z)) count++;
}
return count;
}
bool BaseRailTile::Rail::canConnectTo(Rail *rail)
{
if(!m_bValidRail) return false;
if (connectsTo(rail)) return true;
if (connections.size() == 2)
{
return false;
}
if (connections.empty())
{
return true;
}
return true;
}
void BaseRailTile::Rail::connectTo(Rail *rail)
{
if(m_bValidRail)
{
MemSect(50);
connections.push_back(new TilePos(rail->x, rail->y, rail->z));
MemSect(0);
bool n = hasConnection(x, y, z - 1);
bool s = hasConnection(x, y, z + 1);
bool w = hasConnection(x - 1, y, z);
bool e = hasConnection(x + 1, y, z);
int dir = -1;
if (n || s) dir = DIR_FLAT_Z;
if (w || e) dir = DIR_FLAT_X;
if (!usesDataBit)
{
if (s && e && !n && !w) dir = 6;
if (s && w && !n && !e) dir = 7;
if (n && w && !s && !e) dir = 8;
if (n && e && !s && !w) dir = 9;
}
if (dir == DIR_FLAT_Z)
{
if (isRail(level, x, y + 1, z - 1)) dir = 4;
if (isRail(level, x, y + 1, z + 1)) dir = 5;
}
if (dir == DIR_FLAT_X)
{
if (isRail(level, x + 1, y + 1, z)) dir = 2;
if (isRail(level, x - 1, y + 1, z)) dir = 3;
}
if (dir < 0) dir = DIR_FLAT_Z;
int data = dir;
if (usesDataBit)
{
data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir;
}
level->setData(x, y, z, data, Tile::UPDATE_ALL);
}
}
bool BaseRailTile::Rail::hasNeighborRail(int x, int y, int z)
{
if(!m_bValidRail) return false;
TilePos tp(x,y,z);
Rail *neighbor = getRail( &tp );
if (neighbor == NULL) return false;
neighbor->removeSoftConnections();
bool retval = neighbor->canConnectTo(this);
delete neighbor;
return retval;
}
void BaseRailTile::Rail::place(bool hasSignal, bool first)
{
if(m_bValidRail)
{
bool n = hasNeighborRail(x, y, z - 1);
bool s = hasNeighborRail(x, y, z + 1);
bool w = hasNeighborRail(x - 1, y, z);
bool e = hasNeighborRail(x + 1, y, z);
int dir = -1;
if ((n || s) && !w && !e) dir = DIR_FLAT_Z;
if ((w || e) && !n && !s) dir = DIR_FLAT_X;
if (!usesDataBit)
{
if (s && e && !n && !w) dir = 6;
if (s && w && !n && !e) dir = 7;
if (n && w && !s && !e) dir = 8;
if (n && e && !s && !w) dir = 9;
}
if (dir == -1)
{
if (n || s) dir = DIR_FLAT_Z;
if (w || e) dir = DIR_FLAT_X;
if (!usesDataBit)
{
if (hasSignal)
{
if (s && e) dir = 6;
if (w && s) dir = 7;
if (e && n) dir = 9;
if (n && w) dir = 8;
} else {
if (n && w) dir = 8;
if (e && n) dir = 9;
if (w && s) dir = 7;
if (s && e) dir = 6;
}
}
}
if (dir == DIR_FLAT_Z)
{
if (isRail(level, x, y + 1, z - 1)) dir = 4;
if (isRail(level, x, y + 1, z + 1)) dir = 5;
}
if (dir == DIR_FLAT_X)
{
if (isRail(level, x + 1, y + 1, z)) dir = 2;
if (isRail(level, x - 1, y + 1, z)) dir = 3;
}
if (dir < 0) dir = DIR_FLAT_Z;
updateConnections(dir);
int data = dir;
if (usesDataBit)
{
data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir;
}
if (first || level->getData(x, y, z) != data)
{
level->setData(x, y, z, data, Tile::UPDATE_ALL);
AUTO_VAR(itEnd, connections.end());
for (AUTO_VAR(it, connections.begin()); it != itEnd; it++)
{
Rail *neighbor = getRail(*it);
if (neighbor == NULL) continue;
neighbor->removeSoftConnections();
if (neighbor->canConnectTo(this))
{
neighbor->connectTo(this);
}
delete neighbor;
}
}
}
}
bool BaseRailTile::isRail(Level *level, int x, int y, int z)
{
return isRail(level->getTile(x, y, z));
}
bool BaseRailTile::isRail(int id)
{
return id == Tile::rail_Id || id == Tile::goldenRail_Id || id == Tile::detectorRail_Id || id == Tile::activatorRail_Id;
}
BaseRailTile::BaseRailTile(int id, bool usesDataBit) : Tile(id, Material::decoration, isSolidRender())
{
this->usesDataBit = usesDataBit;
setShape(0, 0, 0, 1, 2 / 16.0f, 1);
iconTurn = NULL;
}
bool BaseRailTile::isUsesDataBit()
{
return usesDataBit;
}
AABB *BaseRailTile::getAABB(Level *level, int x, int y, int z)
{
return NULL;
}
bool BaseRailTile::blocksLight()
{
return false;
}
bool BaseRailTile::isSolidRender(bool isServerLevel)
{
return false;
}
HitResult *BaseRailTile::clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b)
{
updateShape(level, xt, yt, zt);
return Tile::clip(level, xt, yt, zt, a, b);
}
void BaseRailTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr<TileEntity> forceEntity) // 4J added forceData, forceEntity param
{
int data = level->getData(x, y, z);
if (data >= 2 && data <= 5)
{
setShape(0, 0, 0, 1, 2 / 16.0f + 0.5f, 1);
} else
{
setShape(0, 0, 0, 1, 2 / 16.0f, 1);
}
}
bool BaseRailTile::isCubeShaped()
{
return false;
}
int BaseRailTile::getRenderShape()
{
return Tile::SHAPE_RAIL;
}
int BaseRailTile::getResourceCount(Random random)
{
return 1;
}
bool BaseRailTile::mayPlace(Level *level, int x, int y, int z)
{
if (level->isTopSolidBlocking(x, y - 1, z))
{
return true;
}
return false;
}
void BaseRailTile::onPlace(Level *level, int x, int y, int z)
{
if (!level->isClientSide)
{
updateDir(level, x, y, z, true);
if (usesDataBit)
{
neighborChanged(level, x, y, z, id);
}
}
}
void BaseRailTile::neighborChanged(Level *level, int x, int y, int z, int type)
{
if (level->isClientSide) return;
int data = level->getData(x, y, z);
int dir = data;
if (usesDataBit) {
dir = dir & RAIL_DIRECTION_MASK;
}
bool remove = false;
if (!level->isTopSolidBlocking(x, y - 1, z)) remove = true;
if (dir == 2 && !level->isTopSolidBlocking(x + 1, y, z)) remove = true;
if (dir == 3 && !level->isTopSolidBlocking(x - 1, y, z)) remove = true;
if (dir == 4 && !level->isTopSolidBlocking(x, y, z - 1)) remove = true;
if (dir == 5 && !level->isTopSolidBlocking(x, y, z + 1)) remove = true;
if (remove)
{
spawnResources(level, x, y, z, level->getData(x, y, z), 0);
level->removeTile(x, y, z);
}
else
{
updateState(level, x, y, z, data, dir, type);
}
}
void BaseRailTile::updateState(Level *level, int x, int y, int z, int data, int dir, int type)
{
}
void BaseRailTile::updateDir(Level *level, int x, int y, int z, bool first)
{
if (level->isClientSide) return;
Rail *rail = new Rail(level, x, y, z);
rail->place(level->hasNeighborSignal(x, y, z), first);
delete rail;
}
int BaseRailTile::getPistonPushReaction()
{
// override the decoration material's reaction
return Material::PUSH_NORMAL;
}
void BaseRailTile::onRemove(Level *level, int x, int y, int z, int id, int data)
{
int dir = data;
if (usesDataBit)
{
dir &= RAIL_DIRECTION_MASK;
}
Tile::onRemove(level, x, y, z, id, data);
if (dir == 2 || dir == 3 || dir == 4 || dir == 5)
{
level->updateNeighborsAt(x, y + 1, z, id);
}
if (usesDataBit)
{
level->updateNeighborsAt(x, y, z, id);
level->updateNeighborsAt(x, y - 1, z, id);
}
}
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#include "Tile.h"
#include "TilePos.h"
#include "Definitions.h"
class Random;
class HitResult;
class ChunkRebuildData;
using namespace std;
class BaseRailTile : public Tile
{
friend class Tile;
friend class ChunkRebuildData;
public:
static const int DIR_FLAT_Z = 0;
static const int DIR_FLAT_X = 1;
// the data bit is used by boosters and detectors, so they can't turn
static const int RAIL_DATA_BIT = 8;
static const int RAIL_DIRECTION_MASK = 7;
private:
Icon *iconTurn;
protected:
bool usesDataBit;
class Rail
{
friend class BaseRailTile;
friend class RailTile;
private:
Level *level;
int x, y, z;
bool usesDataBit;
vector<TilePos *> connections;
bool m_bValidRail; // 4J added
public:
Rail(Level *level, int x, int y, int z);
~Rail();
private:
void updateConnections(int direction);
void removeSoftConnections();
bool hasRail(int x, int y, int z);
Rail *getRail(TilePos *p);
bool connectsTo(Rail *rail);
bool hasConnection(int x, int y, int z);
protected:
int countPotentialConnections();
private:
bool canConnectTo(Rail *rail);
void connectTo(Rail *rail);
bool hasNeighborRail(int x, int y, int z);
public:
void place(bool hasSignal, bool first);
};
public:
static bool isRail(Level *level, int x, int y, int z);
static bool isRail(int id);
protected:
BaseRailTile(int id, bool usesDataBit);
public:
using Tile::getResourceCount;
bool isUsesDataBit();
virtual AABB *getAABB(Level *level, int x, int y, int z);
virtual bool blocksLight();
virtual bool isSolidRender(bool isServerLevel = false);
virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b);
virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr<TileEntity> forceEntity = shared_ptr<TileEntity>()); // 4J added forceData, forceEntity param
virtual bool isCubeShaped();
virtual int getRenderShape();
virtual int getResourceCount(Random random);
virtual bool mayPlace(Level *level, int x, int y, int z);
virtual void onPlace(Level *level, int x, int y, int z);
virtual void neighborChanged(Level *level, int x, int y, int z, int type);
protected:
virtual void updateState(Level *level, int x, int y, int z, int data, int dir, int type);
virtual void updateDir(Level *level, int x, int y, int z, bool first);
public:
int getPistonPushReaction();
void onRemove(Level *level, int x, int y, int z, int id, int data);
};
+565
View File
@@ -0,0 +1,565 @@
#include "stdafx.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "BasicTree.h"
byte BasicTree::axisConversionArray[] = { 2, 0, 0, 1, 2, 1 };
BasicTree::~BasicTree()
{
delete rnd;
for( int i = 0; i < foliageCoordsLength; i++ )
{
delete [] foliageCoords[i];
}
delete [] foliageCoords;
}
BasicTree::BasicTree(bool doUpdate) : Feature(doUpdate)
{
rnd = new Random();
origin[0] = 0;
origin[1] = 0;
origin[2] = 0;
// Field to hold the tree height.
height = 0;
// Other important tree information.
trunkHeight = 0;
trunkHeightScale = 0.618;
branchDensity = 1.0;
branchSlope = 0.381;
widthScale = 1.0;
foliageDensity = 1.0;
trunkWidth = 1;
heightVariance = 12;
foliageHeight = 4;
foliageCoords = NULL;
foliageCoordsLength = 0;
}
void BasicTree::prepare()
{
// Initialize the instance variables.
// Populate the list of foliage cluster locations.
// Designed to be overridden in child classes to change basic
// tree properties (trunk width, branch angle, foliage density, etc..).
trunkHeight = (int) (height * trunkHeightScale);
if (trunkHeight >= height) trunkHeight = height - 1;
int clustersPerY = (int) (1.382 + pow(foliageDensity * height / 13.0, 2));
if (clustersPerY < 1) clustersPerY = 1;
// The foliage coordinates are a list of [x,y,z,y of branch base] values for each cluster
int **tempFoliageCoords = new int *[clustersPerY * height];
for( int i = 0; i < clustersPerY * height; i++ )
{
tempFoliageCoords[i] = new int[4];
}
int y = origin[1] + height - foliageHeight;
int clusterCount = 1;
int trunkTop = origin[1] + trunkHeight;
int relativeY = y - origin[1];
tempFoliageCoords[0][0] = origin[0];
tempFoliageCoords[0][1] = y;
tempFoliageCoords[0][2] = origin[2];
tempFoliageCoords[0][3] = trunkTop;
y--;
while (relativeY >= 0)
{
int num = 0;
float shapefac = treeShape(relativeY);
if (shapefac < 0)
{
y--;
relativeY--;
continue;
}
// The originOffset is to put the value in the middle of the block.
double originOffset = 0.5;
while (num < clustersPerY)
{
double radius = widthScale * (shapefac * (rnd->nextFloat() + 0.328));
double angle = rnd->nextFloat() * 2.0 * 3.14159;
int x = Mth::floor(radius * sin(angle) + origin[0] + originOffset);
int z = Mth::floor(radius * cos(angle) + origin[2] + originOffset);
int checkStart[] = { x, y, z };
int checkEnd[] = { x, y + foliageHeight, z };
// check the center column of the cluster for obstructions.
if (checkLine(checkStart, checkEnd) == -1) {
// If the cluster can be created, check the branch path
// for obstructions.
int checkBranchBase[] = { origin[0], origin[1], origin[2] };
double distance = sqrt(pow(abs(origin[0] - checkStart[0]), 2.0) + pow(abs(origin[2] - checkStart[2]), 2.0));
double branchHeight = distance * branchSlope;
if ((checkStart[1] - branchHeight) > trunkTop)
{
checkBranchBase[1] = trunkTop;
}
else
{
checkBranchBase[1] = (int) (checkStart[1] - branchHeight);
}
// Now check the branch path
if (checkLine(checkBranchBase, checkStart) == -1)
{
// If the branch path is clear, add the position to the list
// of foliage positions
tempFoliageCoords[clusterCount][0] = x;
tempFoliageCoords[clusterCount][1] = y;
tempFoliageCoords[clusterCount][2] = z;
tempFoliageCoords[clusterCount][3] = checkBranchBase[1];
clusterCount++;
}
}
num++;
}
y--;
relativeY--;
}
// 4J Stu - Rather than copying the array, we are storing the number of valid elements in the array
foliageCoordsLength = clusterCount;
foliageCoords = tempFoliageCoords;
// Delete the rest of the array whilst we still know how big it was
for( int i = clusterCount; i < clustersPerY * height; i++ )
{
delete [] tempFoliageCoords[i];
tempFoliageCoords[i] = NULL;
}
// 4J - original code for above is the following, it isn't obvious to me why it is doing a copy of the array, so let's not for now
// foliageCoords = new int[clusterCount][4];
// System.arraycopy(tempFoliageCoords, 0, foliageCoords, 0, clusterCount);
}
void BasicTree::crossection(int x, int y, int z, float radius, byte direction, int material)
{
PIXBeginNamedEvent(0, "BasicTree crossection");
// Create a circular cross section.
//
// Used to nearly everything in the foliage, branches, and trunk.
// This is a good target for performance optimization.
// Passed values:
// x,y,z is the center location of the cross section
// radius is the radius of the section from the center
// direction is the direction the cross section is pointed, 0 for x, 1 for y, 2 for z
// material is the index number for the material to use
int rad = (int) (radius + 0.618);
byte secidx1 = axisConversionArray[direction];
byte secidx2 = axisConversionArray[direction + 3];
int center[] = { x, y, z };
int position[] = { 0, 0, 0 };
int offset1 = -rad;
int offset2 = -rad;
int thismat;
position[direction] = center[direction];
while (offset1 <= rad)
{
position[secidx1] = center[secidx1] + offset1;
offset2 = -rad;
while (offset2 <= rad)
{
double thisdistance = pow(abs(offset1) + 0.5, 2) + pow(abs(offset2) + 0.5, 2);
if (thisdistance > radius * radius)
{
offset2++;
continue;
}
position[secidx2] = center[secidx2] + offset2;
PIXBeginNamedEvent(0,"BasicTree getting tile");
thismat = thisLevel->getTile(position[0], position[1], position[2]);
PIXEndNamedEvent();
if (!((thismat == 0) || (thismat == Tile::leaves_Id)))
{
// If the material of the checked block is anything other than
// air or foliage, skip this tile.
offset2++;
continue;
}
PIXBeginNamedEvent(0,"BasicTree placing block");
placeBlock(thisLevel, position[0], position[1], position[2], material, 0);
PIXEndNamedEvent();
offset2++;
}
offset1++;
}
PIXEndNamedEvent();
}
float BasicTree::treeShape(int y)
{
// Take the y position relative to the base of the tree.
// Return the distance the foliage should be from the trunk axis.
// Return a negative number if foliage should not be created at this height.
// This method is intended for overriding in child classes, allowing
// different shaped trees.
// This method should return a consistent value for each y (don't randomize).
if (y < (((float) height) * 0.3)) return (float) -1.618;
float radius = ((float) height) / ((float) 2.0);
float adjacent = (((float) height) / ((float) 2.0)) - y;
float distance;
if (adjacent == 0) distance = radius;
else if (abs(adjacent) >= radius) distance = (float) 0.0;
else distance = (float) sqrt(pow(abs(radius), 2) - pow(abs(adjacent), 2));
// Alter this factor to change the overall width of the tree.
distance *= (float) 0.5;
return distance;
}
float BasicTree::foliageShape(int y)
{
// Take the y position relative to the base of the foliage cluster.
// Return the radius of the cluster at this y
// Return a negative number if no foliage should be created at this level
// this method is intended for overriding in child classes, allowing
// foliage of different sizes and shapes.
if ((y < 0) || (y >= foliageHeight)) return (float) -1;
else if ((y == 0) || (y == (foliageHeight - 1))) return (float) 2;
else return (float) 3;
}
void BasicTree::foliageCluster(int x, int y, int z)
{
PIXBeginNamedEvent(0,"BasicTree foliageCluster");
// Generate a cluster of foliage, with the base at x, y, z.
// The shape of the cluster is derived from foliageShape
// crossection is called to make each level.
int topy = y + foliageHeight;
int cury = topy - 1;
float radius;
// 4J Stu - Generate foliage from the top down so that we don't keep recalculating heightmaps
while (cury >= y)
{
radius = foliageShape(cury - y);
crossection(x, cury, z, radius, (byte) 1, Tile::leaves_Id);
cury--;
}
PIXEndNamedEvent();
}
void BasicTree::limb(int *start, int *end, int material)
{
// Create a limb from the start position to the end position.
// Used for creating the branches and trunk.
// Populate delta, the difference between start and end for all three axies.
// Set primidx to the index with the largest overall distance traveled.
int delta[] = { 0, 0, 0 };
byte idx = 0;
byte primidx = 0;
while (idx < 3)
{
delta[idx] = end[idx] - start[idx];
if (abs(delta[idx]) > abs(delta[primidx]))
{
primidx = idx;
}
idx++;
}
// If the largest distance is zero, don't bother to do anything else.
if (delta[primidx] == 0) return;
// set up the other two axis indices.
byte secidx1 = axisConversionArray[primidx];
byte secidx2 = axisConversionArray[primidx + 3];
// primsign is digit 1 or -1 depending on whether the limb is headed
// along the positive or negative primidx axis.
char primsign;
if (delta[primidx] > 0) primsign = 1;
else primsign = -1;
// Initilize the per-step movement for the non-primary axies.
double secfac1 = ((double) delta[secidx1]) / ((double) delta[primidx]);
double secfac2 = ((double) delta[secidx2]) / ((double) delta[primidx]);
// Initialize the coordinates.
int coordinate[] = { 0, 0, 0 };
// Loop through each crossection along the primary axis, from start to end
int primoffset = 0;
int endoffset = delta[primidx] + primsign;
while (primoffset != endoffset)
{
coordinate[primidx] = Mth::floor(start[primidx] + primoffset + 0.5);
coordinate[secidx1] = Mth::floor(start[secidx1] + (primoffset * secfac1) + 0.5);
coordinate[secidx2] = Mth::floor(start[secidx2] + (primoffset * secfac2) + 0.5);
int dir = TreeTile::FACING_Y;
int xdiff = abs(coordinate[0] - start[0]);
int zdiff = abs(coordinate[2] - start[2]);
int maxdiff = max(xdiff, zdiff);
if (maxdiff > 0)
{
if (xdiff == maxdiff)
{
dir = TreeTile::FACING_X;
}
else if (zdiff == maxdiff)
{
dir = TreeTile::FACING_Z;
}
}
placeBlock(thisLevel, coordinate[0], coordinate[1], coordinate[2], material, dir);
primoffset += primsign;
}
}
void BasicTree::makeFoliage()
{
// Create the tree foliage.
// Call foliageCluster at the correct locations
int idx = 0;
int finish = foliageCoordsLength;
while (idx < finish)
{
int x = foliageCoords[idx][0];
int y = foliageCoords[idx][1];
int z = foliageCoords[idx][2];
foliageCluster(x, y, z);
idx++;
}
}
bool BasicTree::trimBranches(int localY)
{
// For larger trees, randomly "prune" the branches so there
// aren't too many.
// Return true if the branch should be created.
// This method is intended for overriding in child classes, allowing
// decent amounts of branches on very large trees.
// Can also be used to disable branches on some tree types, or
// make branches more sparse.
if (localY < (height * 0.2)) return false;
else return true;
}
void BasicTree::makeTrunk()
{
// Create the trunk of the tree.
int x = origin[0];
int startY = origin[1];
int topY = origin[1] + trunkHeight;
int z = origin[2];
int startCoord[] = { x, startY, z };
int endCoord[] = { x, topY, z };
limb(startCoord, endCoord, Tile::treeTrunk_Id);
if (trunkWidth == 2)
{
startCoord[0] += 1;
endCoord[0] += 1;
limb(startCoord, endCoord, Tile::treeTrunk_Id);
startCoord[2] += 1;
endCoord[2] += 1;
limb(startCoord, endCoord, Tile::treeTrunk_Id);
startCoord[0] += -1;
endCoord[0] += -1;
limb(startCoord, endCoord, Tile::treeTrunk_Id);
}
}
void BasicTree::makeBranches()
{
// Create the tree branches.
// Call trimBranches for each branch to see if you should create it.
// Call taperedLimb to the correct locations
int idx = 0;
int finish = foliageCoordsLength;
int baseCoord[] = { origin[0], origin[1], origin[2] };
while (idx < finish)
{
int *coordValues = foliageCoords[idx];
int endCoord[] = { coordValues[0], coordValues[1], coordValues[2] };
baseCoord[1] = coordValues[3];
int localY = baseCoord[1] - origin[1];
if (trimBranches(localY))
{
limb(baseCoord, endCoord, Tile::treeTrunk_Id);
}
idx++;
}
}
int BasicTree::checkLine(int *start, int *end)
{
// Check from coordinates start to end (both inclusive) for blocks other than air and foliage
// If a block other than air and foliage is found, return the number of steps taken.
// If no block other than air and foliage is found, return -1.
// Examples:
// If the third block searched is stone, return 2
// If the first block searched is lava, return 0
int delta[] = { 0, 0, 0 };
byte idx = 0;
byte primidx = 0;
while (idx < 3)
{
delta[idx] = end[idx] - start[idx];
if (abs(delta[idx]) > abs(delta[primidx]))
{
primidx = idx;
}
idx++;
}
// If the largest distance is zero, don't bother to do anything else.
if (delta[primidx] == 0) return -1;
// set up the other two axis indices.
byte secidx1 = axisConversionArray[primidx];
byte secidx2 = axisConversionArray[primidx + 3];
// primsign is digit 1 or -1 depending on whether the limb is headed
// along the positive or negative primidx axis.
char primsign; // 4J Stu - Was byte, but we use in a sum below and byte=unsigned char so we were setting endoffset incorrectly
if (delta[primidx] > 0) primsign = 1;
else primsign = -1;
// Initilize the per-step movement for the non-primary axies.
double secfac1 = ((double) delta[secidx1]) / ((double) delta[primidx]);
double secfac2 = ((double) delta[secidx2]) / ((double) delta[primidx]);
// Initialize the coordinates.
int coordinate[] = { 0, 0, 0 };
// Loop through each crossection along the primary axis, from start to end
int primoffset = 0;
int endoffset = delta[primidx] + primsign;
int thismat;
while (primoffset != endoffset)
{
coordinate[primidx] = start[primidx] + primoffset;
coordinate[secidx1] = Mth::floor(start[secidx1] + (primoffset * secfac1));
coordinate[secidx2] = Mth::floor(start[secidx2] + (primoffset * secfac2));
thismat = thisLevel->getTile(coordinate[0], coordinate[1], coordinate[2]);
if (!((thismat == 0) || (thismat == Tile::leaves_Id)))
{
// If the material of the checked block is anything other than
// air or foliage, stop looking.
break;
}
primoffset += primsign;
}
// If you reached the end without finding anything, return -1.
if (primoffset == endoffset)
{
return -1;
}
// Otherwise, return the number of steps you took.
else
{
return abs(primoffset);
}
}
bool BasicTree::checkLocation()
{
// Return true if the tree can be placed here.
// Return false if the tree can not be placed here.
// Examine the square under the trunk. Is it grass or dirt?
// If not, return false
// Examine center column for how tall the tree can be.
// If the checked height is shorter than height, but taller
// than 4, set the tree to the maximum height allowed.
// If the space is too short, return false.
int startPosition[] = { origin[0], origin[1], origin[2] };
int endPosition[] = { origin[0], origin[1] + height - 1, origin[2] };
// 4J Stu Added to stop tree features generating areas previously place by game rule generation
if(app.getLevelGenerationOptions() != NULL)
{
LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions();
bool intersects = levelGenOptions->checkIntersects(startPosition[0], startPosition[1], startPosition[2], endPosition[0], endPosition[1], endPosition[2]);
if(intersects)
{
//app.DebugPrintf("Skipping reeds feature generation as it overlaps a game rule structure\n");
return false;
}
}
// Check the location it is resting on
int baseMaterial = thisLevel->getTile(origin[0], origin[1] - 1, origin[2]);
if (!((baseMaterial == 2) || (baseMaterial == 3)))
{
return false;
}
int allowedHeight = checkLine(startPosition, endPosition);
// If the set height is good, go with that
if (allowedHeight == -1)
{
return true;
}
// If the space is too short, tell the build to abort
else if (allowedHeight < 6)
{
return false;
}
// If the space is shorter than the set height, but not too short
// shorten the height, and tell the build to continue
else
{
height = allowedHeight;
//System.out.println("Shortened the tree");
return true;
}
}
void BasicTree::init(double heightInit, double widthInit, double foliageDensityInit)
{
// all of the parameters should be from 0.0 to 1.0
// heightInit scales the maximum overall height of the tree (still randomizes height within the possible range)
// widthInit scales the maximum overall width of the tree (keep this above 0.3 or so)
// foliageDensityInit scales how many foliage clusters are created.
//
// Note, you can call "place" without calling "init".
// This is the same as calling init(1.0,1.0,1.0) and then calling place.
heightVariance = (int) (heightInit * 12);
if (heightInit > 0.5) foliageHeight = 5;
widthScale = widthInit;
foliageDensity = foliageDensityInit;
}
bool BasicTree::place(Level *level, Random *random, int x, int y, int z)
{
// Note to Markus.
// currently the following fields are set randomly. If you like, make them
// parameters passed into "place".
//
// height: so the map generator can intelligently set the height of the tree,
// and make forests with large trees in the middle and smaller ones on the edges.
// Initialize the instance fields for the level and the seed.
thisLevel = level;
__int64 seed = random->nextLong();
rnd->setSeed(seed);
// Initialize the origin of the tree trunk
origin[0] = x;
origin[1] = y;
origin[2] = z;
// Sets the height. Take out this line if height is passed as a parameter
if (height == 0)
{
height = 5 + rnd->nextInt(heightVariance);
}
if (!(checkLocation()))
{
//System.out.println("Tree location failed");
return false;
}
PIXBeginNamedEvent(0, "Placing BasicTree");
//System.out.println("The height is");
//System.out.println(height);
//System.out.println("Trunk Height check done");
PIXBeginNamedEvent(0, "Preparing tree");
prepare();
PIXEndNamedEvent();
//System.out.println("Prepare done");
PIXBeginNamedEvent(0, "Making foliage");
makeFoliage();
PIXEndNamedEvent();
//System.out.println("Foliage done");
PIXBeginNamedEvent(0, "Making trunk");
makeTrunk();
PIXEndNamedEvent();
//System.out.println("Trunk done");
PIXBeginNamedEvent(0, "Making branches");
makeBranches();
PIXEndNamedEvent();
//System.out.println("Branches done");
PIXEndNamedEvent();
return true;
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include "Feature.h"
class Level;
class BasicTree : public Feature
{
private:
// The axisConversionArray, when given a primary index, allows easy
// access to the indices of the other two axies. Access the data at the
// primary index location to get the horizontal secondary axis.
// Access the data at the primary location plus three to get the
// remaining, tertiary, axis.
// All directions are specified by an index, 0, 1, or 2 which
// correspond to x, y, and z.
// The axisConversionArray is used in several places
// notably the crossection and taperedLimb methods.
// Example:
// If the primary axis is z, then the primary index is 2.
// The secondary index is axisConversionArray[2] which is 0,
// the index for the x axis.
// The remaining axis is axisConversionArray[2 + 3] which is 1,
// the index for the y axis.
// Using this method, the secondary axis will always be horizontal (x or z),
// and the tertiary always vertical (y), if possible.
static byte axisConversionArray[];
// Set up the pseudorandom number generator
Random *rnd;
// Make fields to hold the level data and the random seed
Level *thisLevel;
// Field to hold the tree origin, x y and z.
int origin[3];
// Field to hold the tree height.
int height;
// Other important tree information.
int trunkHeight;
double trunkHeightScale;
double branchDensity;
double branchSlope;
double widthScale;
double foliageDensity;
int trunkWidth;
int heightVariance;
int foliageHeight;
// The foliage coordinates are a list of [x,y,z,y of branch base] values for each cluster
int **foliageCoords;
int foliageCoordsLength;
void prepare();
void crossection(int x, int y, int z, float radius, byte direction, int material);
float treeShape(int y);
float foliageShape(int y);
void foliageCluster(int x, int y, int z);
void limb(int *start, int *end, int material);
void makeFoliage();
bool trimBranches(int localY);
void makeTrunk();
void makeBranches();
int checkLine(int *start, int *end);
bool checkLocation();
public:
BasicTree(bool doUpdate);
virtual ~BasicTree();
virtual void init(double heightInit, double widthInit, double foliageDensityInit);
virtual bool place(Level *level, Random *random, int x, int y, int z);
};
+22
View File
@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "BasicTypeContainers.h"
#include <limits>
/* 4J Jev TODO,
this is different to Float::MAX_VALUE, javas floats
seem to actually allow values of infinity which c++ does not.
*/
//A constant holding the positive infinity of type float. It is equal to the value returned by Float.intBitsToFloat(0x7f800000).
const float Float::POSITIVE_INFINITY = 0x7f800000;
const float Float::MAX_VALUE = FLT_MAX;
const double Double::MAX_VALUE = DBL_MAX;
const double Double::MIN_NORMAL = DBL_MIN;
int Integer::parseInt(wstring &str, int radix /* = 10*/)
{
return wcstol( str.c_str(), NULL, radix );
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
class Byte
{
public:
static const char MAX_VALUE = CHAR_MAX;
static const char MIN_VALUE = CHAR_MIN;
};
class Short
{
public:
static const short MAX_VALUE = SHRT_MAX;
static const short MIN_VALUE = SHRT_MIN;
};
class Integer
{
public:
static const int MAX_VALUE = INT_MAX;
static int parseInt(wstring &str, int radix = 10);
};
class Float
{
public:
static const float MAX_VALUE;
static int floatToIntBits( float value )
{
return *(int *)&value;
}
static int floatToRawIntBits( float value )
{
return *(int *)&value;
}
static float intBitsToFloat( int bits )
{
return *(float *)&bits;
}
static const float POSITIVE_INFINITY;
};
class Double
{
public:
static const double MAX_VALUE;
static const double MIN_NORMAL;
static bool isNaN( double a ) {
#ifdef __PS3__
return isnan(a);
#else
return ( a != a );
#endif
}
static bool isInfinite( double a ) { return false; /*4J TODO*/ }
static double longBitsToDouble( __int64 bits )
{
return *(double *)&bits;
}
static __int64 doubleToLongBits( double d )
{
return *(__int64 *)&d;
}
};
// 4J Stu - The String class should only be used if we need to use the BaseClass::class type
// As such I have renamed it so that we don't confuse it with places where we should use std::string
class _String
{
};
Loaded 100 of 5375 files, more files were not shown because too many files have changed in this diff. Show more