the whole game

This commit is contained in:
2026-03-02 22:04:18 +03:00
parent 816e9060b4
commit f0617a5d22
2069 changed files with 581500 additions and 0 deletions

View File

@@ -0,0 +1,346 @@
#include "Arrow.h"
#include "../Mob.h"
#include "../player/Player.h"
#include "../../item/Item.h"
#include "../../item/ItemInstance.h"
#include "../../level/Level.h"
#include "../../level/tile/Tile.h"
#include "../../../util/Mth.h"
#include "../../../nbt/CompoundTag.h"
const float Arrow::ARROW_BASE_DAMAGE = 2.0f;
Arrow::Arrow( Level* level )
: super(level),
playerArrow(false),
ownerId(0)
{
_init();
}
Arrow::Arrow( Level* level, float x, float y, float z )
: super(level),
playerArrow(false),
ownerId(0)
{
_init();
this->setPos(x, y, z);
this->heightOffset = 0;
}
Arrow::Arrow( Level* level, Mob* mob, float power )
: super(level),
ownerId(mob->entityId),
playerArrow(mob->isPlayer())
{
_init();
moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
const float dx = Mth::cos(yRot * Mth::DEGRAD);
const float dz = Mth::sin(yRot * Mth::DEGRAD);
x -= dx * 0.16f;
y -= 0.1f;
z -= dz * 0.16f;
this->setPos(x, y, z);
this->heightOffset = 0;
const float dxx = Mth::cos(xRot / 180 * Mth::PI);
xd = -dz * dxx;
zd = dx * dxx;
yd = -Mth::sin(xRot / 180 * Mth::PI);
shoot(xd, yd, zd, power * 1.5f, 1);
}
void Arrow::_init()
{
entityRendererId = ER_ARROW_RENDERER;
setSize(0.5f, 0.5f);
shakeTime = 0;
critArrow = false;
xTile = -1;
yTile = -1;
zTile = -1;
lastTile = 0;
lastData = 0;
inGround = false;
life = 0;
flightTime = 0;
}
void Arrow::shoot( float xd, float yd, float zd, float pow, float uncertainty )
{
float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd);
xd /= dist;
yd /= dist;
zd /= dist;
const float radius = 0.0075f * uncertainty;
xd += sharedRandom.nextGaussian() * radius;
yd += sharedRandom.nextGaussian() * radius;
zd += sharedRandom.nextGaussian() * radius;
xd *= pow;
yd *= pow;
zd *= pow;
this->xd = xd;
this->yd = yd;
this->zd = zd;
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
life = 0;
}
void Arrow::lerpMotion( float xd, float yd, float zd )
{
this->xd = xd;
this->yd = yd;
this->zd = zd;
if (xRotO == 0 && yRotO == 0) {
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
moveTo(x, y, z, yRot, xRot);
life = 0;
}
}
void Arrow::tick()
{
super::tick();
if (xRotO == 0 && yRotO == 0) {
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
}
{
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(x, y, z))) {
inGround = true;
}
}
}
if (shakeTime > 0) shakeTime--;
if (inGround) {
// xd = 0;
// yd = 0;
// zd = 0;
int tile = level->getTile(xTile, yTile, zTile);
int data = level->getData(xTile, yTile, zTile);
if (tile != lastTile || data != lastData) {
inGround = false;
xd *= sharedRandom.nextFloat() * 0.2f;
yd *= sharedRandom.nextFloat() * 0.2f;
zd *= sharedRandom.nextFloat() * 0.2f;
life = 0;
flightTime = 0;
return;
} else {
if (++life == 60 * SharedConstants::TicksPerSecond) remove();
return;
}
} else {
flightTime++;
}
Vec3 from(x, y, z);
Vec3 to(x + xd, y + yd, z + zd);
HitResult res = level->clip(from, to, false, true);
from.set(x, y, z);
to.set(x + xd, y + yd, z + zd);
if (res.isHit()) {
to.set(res.pos.x, res.pos.y, res.pos.z);
}
Entity* hitEntity = NULL;
EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1));
float nearest = 0;
for (unsigned int i = 0; i < objects.size(); i++) {
Entity* e = objects[i];
if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue;
float rr = 0.3f;
AABB bb = e->bb.grow(rr, rr, rr);
HitResult p = bb.clip(from, to);
if (p.isHit()) {
float dd = from.distanceTo(p.pos);
if (dd < nearest || nearest == 0) {
hitEntity = e;
nearest = dd;
}
}
}
if (hitEntity != NULL) {
res = HitResult(hitEntity);
}
if (res.isHit()) {
if (res.type == ENTITY) {
float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd);
int dmg = (int) std::ceil(pow * ARROW_BASE_DAMAGE);
if (critArrow) dmg += sharedRandom.nextInt(dmg / 2 + 2);
//@todo
//DamageSource damageSource = NULL;
//if (owner == NULL) {
// damageSource = DamageSource.arrow(this, this);
//} else {
// damageSource = DamageSource.arrow(this, owner);
//}
//if (res.entity->hurt(damageSource, dmg)) {
// if (res.entity instanceof Mob) {
if (res.entity->hurt(this, dmg)) {
if (res.entity->isMob()) {
((Mob*) res.entity)->arrowCount++;
}
level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f));
remove();
} else {
xd *= -0.1f;
yd *= -0.1f;
zd *= -0.1f;
yRot += 180;
yRotO += 180;
flightTime = 0;
}
} 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 = Mth::sqrt(xd * xd + yd * yd + zd * zd);
x -= (xd / dd) * 0.05f;
y -= (yd / dd) * 0.05f;
z -= (zd / dd) * 0.05f;
level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f));
inGround = true;
shakeTime = 7;
critArrow = false;
}
}
if (critArrow) {
for (int i = 0; i < 4; i++) {
level->addParticle(PARTICLETYPE(crit), x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2f, -zd);
}
}
x += xd;
y += yd;
z += zd;
float sd = Mth::sqrt(xd * xd + zd * zd);
yRot = std::atan2(xd, zd) * Mth::RADDEG;
xRot = std::atan2(yd, sd) * Mth::RADDEG;
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(PARTICLETYPE(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);
}
void Arrow::addAdditonalSaveData( CompoundTag* tag )
{
tag->putShort("xTile", (short) xTile);
tag->putShort("yTile", (short) yTile);
tag->putShort("zTile", (short) zTile);
tag->putByte("inTile", (char) lastTile);
tag->putByte("inData", (char) lastData);
tag->putByte("shake", (char) shakeTime);
tag->putByte("inGround", (char) (inGround ? 1 : 0));
tag->putBoolean("player", playerArrow);
}
void Arrow::readAdditionalSaveData( CompoundTag* tag )
{
xTile = tag->getShort("xTile");
yTile = tag->getShort("yTile");
zTile = tag->getShort("zTile");
lastTile = tag->getByte("inTile") & 0xff;
lastData = tag->getByte("inData") & 0xff;
shakeTime = tag->getByte("shake") & 0xff;
inGround = tag->getByte("inGround") == 1;
playerArrow = tag->getBoolean("player");
}
void Arrow::playerTouch( Player* player )
{
if (level->isClientSide) return;
if (inGround && playerArrow && shakeTime <= 0) {
ItemInstance item(Item::arrow, 1);
if (player->inventory->add(&item)) {
level->playSound(this, "random.pop", 0.2f, ((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f + 1.0f) * 2.f);
player->take(this, 1);
remove();
}
}
}
float Arrow::getShadowHeightOffs() {
return 0;
}
int Arrow::getEntityTypeId() const {
return EntityTypes::IdArrow;
}
int Arrow::getAuxData() {
return ownerId;
}

View File

@@ -0,0 +1,57 @@
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__
//package net.minecraft.world.entity.projectile;
#include "../Entity.h"
class Level;
class Mob;
class CompoundTag;
class Arrow: public Entity
{
typedef Entity super;
// base damage, multiplied with velocity
static const float ARROW_BASE_DAMAGE;
public:
Arrow(Level* level);
Arrow(Level* level, float x, float y, float z);
Arrow(Level* level, Mob* mob, float power);
void _init();
void shoot(float xd, float yd, float zd, float pow, float uncertainty);
void lerpMotion(float xd, float yd, float zd);
void tick();
int getEntityTypeId() const;
void addAdditonalSaveData(CompoundTag* tag);
void readAdditionalSaveData(CompoundTag* tag);
void playerTouch(Player* player);
float getShadowHeightOffs();
int getAuxData();
public:
bool playerArrow;
int shakeTime;
int ownerId;
bool critArrow;
private:
int xTile;
int yTile;
int zTile;
int lastTile;
int lastData;
bool inGround;
int life;
int flightTime;
};
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__*/

View File

@@ -0,0 +1,50 @@
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__
//package net.minecraft.world.entity->projectile;
#include "Throwable.h"
#include "../Mob.h"
#include "../../level/Level.h"
#include "../../phys/HitResult.h"
class Snowball: public Throwable
{
typedef Throwable super;
public:
Snowball(Level* level)
: super(level)
{
entityRendererId = ER_SNOWBALL_RENDERER;
}
Snowball(Level* level, Mob* mob)
: super(level, mob)
{
entityRendererId = ER_SNOWBALL_RENDERER;
}
Snowball(Level* level, float x, float y, float z)
: super(level, x, y, z)
{
entityRendererId = ER_SNOWBALL_RENDERER;
}
virtual int getEntityTypeId() const {
return EntityTypes::IdSnowball;
}
/*@Override*/
void onHit(const HitResult& res) {
if (res.type == ENTITY)
res.entity->hurt(this, 0);
for (int i = 0; i < 6; i++)
level->addParticle(PARTICLETYPE(snowballpoof), x, y, z, 0, 0, 0);
if (!level->isClientSide)
remove();
}
};
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__*/

View File

@@ -0,0 +1,260 @@
#include "Throwable.h"
#include "../player/Player.h"
#include "../../level/Level.h"
#include "../../../util/Mth.h"
#include "../../phys/HitResult.h"
Throwable::Throwable( Level* level )
: super(level)
{
_init();
setSize(0.25f, 0.25f);
}
Throwable::Throwable( Level* level, Mob* mob )
: super(level)
{
_init();
setSize(0.25f, 0.25f);
ownerId = mob->entityId;
this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
const float rcos = Mth::cos(yRot / 180 * Mth::PI);
const float rsin = Mth::sin(yRot / 180 * Mth::PI);
x -= rcos * 0.16f;
y -= 0.1f;
z -= rsin * 0.16f;
this->setPos(x, y, z);
this->heightOffset = 0;
if (mob->isPlayer()) {
shoot(mob->aimDirection, getThrowPower(), 1);
} else {
float xd = (-rsin * Mth::cos(xRot / 180 * Mth::PI));
float zd = ( rcos * Mth::cos(xRot / 180 * Mth::PI));
float yd = (-Mth::sin((xRot + getThrowUpAngleOffset()) / 180 * Mth::PI));
shoot(xd, yd, zd, getThrowPower(), 1);
}
}
Throwable::Throwable( Level* level, float x, float y, float z )
: super(level)
{
_init();
setSize(0.25f, 0.25f);
this->setPos(x, y, z);
this->heightOffset = 0;
}
void Throwable::_init() {
ownerId = 0;
shakeTime = 0;
inGround = false;
life = 0;
flightTime = 0;
xTile = -1;
yTile = -1;
zTile = -1;
lastTile = 0;
}
bool Throwable::shouldRenderAtSqrDistance( float distance ) {
float size = bb.getSize() * 4;
size *= 64.0f;
return distance < size * size;
}
float Throwable::getThrowPower() {
return 1.5f;
}
float Throwable::getThrowUpAngleOffset() {
return 0;
}
float Throwable::getGravity() {
return 0.03f;
}
void Throwable::shoot(const Vec3& v, float pow, float uncertainty) {
shoot(v.x, v.y, v.z, pow, uncertainty);
}
void Throwable::shoot( float xd, float yd, float zd, float pow, float uncertainty ) {
float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd);
if (dist >= 0.001f) {
xd /= dist;
yd /= dist;
zd /= dist;
} else {
xd = yd = zd = 0;
}
xd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
yd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
zd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
xd *= pow;
yd *= pow;
zd *= pow;
this->xd = xd;
this->yd = yd;
this->zd = zd;
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI);
xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI);
life = 0;
}
void Throwable::lerpMotion( float xd, float yd, float zd ) {
this->xd = xd;
this->yd = yd;
this->zd = zd;
if (xRotO == 0 && yRotO == 0) {
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI);
xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI);
}
}
void Throwable::tick() {
xOld = x;
yOld = y;
zOld = z;
super::tick();
if (shakeTime > 0) shakeTime--;
if (inGround) {
// xd = 0;
// yd = 0;
// zd = 0;
int tile = level->getTile(xTile, yTile, zTile);
if (tile != lastTile) {
inGround = false;
xd *= sharedRandom.nextFloat() * 0.2f;
yd *= sharedRandom.nextFloat() * 0.2f;
zd *= sharedRandom.nextFloat() * 0.2f;
life = 0;
flightTime = 0;
} else {
life++;
if (life == 20 * 60)
remove();
return;
}
} else {
flightTime++;
}
Vec3 from(x, y, z);
Vec3 to(x + xd, y + yd, z + zd);
HitResult res = level->clip(from, to);
from.set(x, y, z);
to.set(x + xd, y + yd, z + zd);
if (res.isHit())
to.set(res.pos.x, res.pos.y, res.pos.z);
if (!level->isClientSide) {
Entity* hitEntity = NULL;
EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1));
float nearest = 0;
for (unsigned int i = 0; i < objects.size(); i++) {
Entity* e = objects[i];
if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue;
float rr = 0.3f;
AABB bb = e->bb.grow(rr, rr, rr);
HitResult p = bb.clip(from, to);
if (p.isHit()) {
float dd = from.distanceTo(p.pos);
if (dd < nearest || nearest == 0) {
hitEntity = e;
nearest = dd;
}
}
}
if (hitEntity != NULL)
res = HitResult(hitEntity);
}
if (res.isHit())
onHit(res);
x += xd;
y += yd;
z += zd;
float sd = Mth::sqrt(xd * xd + zd * zd);
yRot = Mth::atan2(xd, zd) * 180 / Mth::PI;
xRot = Mth::atan2(yd, sd) * 180 / Mth::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 = getGravity();
if (isInWater()) {
for (int i = 0; i < 4; i++) {
float s = 1 / 4.0f;
level->addParticle("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);
}
float Throwable::getShadowHeightOffs() {
return 0;
}
void Throwable::addAdditonalSaveData( CompoundTag* tag ) {
tag->putShort("xTile", (short) xTile);
tag->putShort("yTile", (short) yTile);
tag->putShort("zTile", (short) zTile);
tag->putByte("inTile", (char) lastTile);
tag->putByte("shake", (char) shakeTime);
tag->putByte("inGround", (char) (inGround ? 1 : 0));
}
void Throwable::readAdditionalSaveData( CompoundTag* tag ) {
xTile = tag->getShort("xTile");
yTile = tag->getShort("yTile");
zTile = tag->getShort("zTile");
lastTile = tag->getByte("inTile") & 0xff;
shakeTime = tag->getByte("shake") & 0xff;
inGround = tag->getByte("inGround") == 1;
}
int Throwable::getAuxData() {
return ownerId;
}

View File

@@ -0,0 +1,63 @@
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__
//package net.minecraft.world.entity->projectile;
class Level;
class Mob;
class Player;
class CompoundTag;
#include "../Entity.h"
class HitResult;
/*abstract*/
class Throwable: public Entity
{
typedef Entity super;
public:
Throwable(Level* level);
Throwable(Level* level, Mob* mob);
Throwable(Level* level, float x, float y, float z);
void shoot(const Vec3& v, float pow, float uncertainty);
void shoot(float xd, float yd, float zd, float pow, float uncertainty);
void tick();
void lerpMotion(float xd, float yd, float zd);
void addAdditonalSaveData(CompoundTag* tag);
void readAdditionalSaveData(CompoundTag* tag);
bool shouldRenderAtSqrDistance(float distance);
float getShadowHeightOffs();
int getAuxData();
protected:
virtual float getThrowPower();
virtual float getThrowUpAngleOffset();
virtual float getGravity();
virtual void onHit(const HitResult& res) = 0;
private:
void _init();
public:
int shakeTime;
protected:
bool inGround;
int ownerId;
private:
int life;
int flightTime;
int xTile;
int yTile;
int zTile;
int lastTile;
};
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__*/

View File

@@ -0,0 +1,63 @@
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__
//package net.minecraft.world.entity->projectile;
#include "Throwable.h"
#include "../Mob.h"
#include "../animal/Chicken.h"
#include "../../level/Level.h"
#include "../../phys/HitResult.h"
class ThrownEgg: public Throwable
{
typedef Throwable super;
public:
ThrownEgg(Level* level)
: super(level)
{
entityRendererId = ER_THROWNEGG_RENDERER;
}
ThrownEgg(Level* level, Mob* mob)
: super(level, mob)
{
entityRendererId = ER_THROWNEGG_RENDERER;
}
ThrownEgg(Level* level, float x, float y, float z)
: super(level, x, y, z)
{
entityRendererId = ER_THROWNEGG_RENDERER;
}
virtual int getEntityTypeId() const {
return EntityTypes::IdThrownEgg;
}
/*@Override*/
protected:
void onHit(const HitResult& res) {
if (res.type == ENTITY)
res.entity->hurt(this, 0);
if (!level->isClientSide && sharedRandom.nextInt(8) == 0) {
int count = 1;
if (sharedRandom.nextInt(32) == 0) count = 4;
for (int i = 0; i < count; i++) {
Chicken* chicken = new Chicken(level);
//chicken.setAge(-20 * 60 * 20);
chicken->moveTo(x, y, z, yRot, 0);
level->addEntity(chicken);
}
}
for (int i = 0; i < 6; i++)
level->addParticle(PARTICLETYPE(snowballpoof), x, y, z, 0, 0, 0);
if (!level->isClientSide)
remove();
}
};
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__*/