Make objects fall through the planet and warp around the edges

Make objects visible and active across planet edges
master
Evert 2018-03-20 20:25:03 +02:00
parent d20b830575
commit 62465fd158
No known key found for this signature in database
GPG Key ID: 1688DA83D222D0B5
4 changed files with 117 additions and 3 deletions

View File

@ -272,12 +272,13 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
bool any_position_valid = false;
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE;
v3s16 p;
for (p.X = min.X; p.X <= max.X; p.X++)
for (p.Y = min.Y; p.Y <= max.Y; p.Y++)
for (p.Z = min.Z; p.Z <= max.Z; p.Z++) {
if (g_settings->getBool("planet_enable")) {
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE;
if (p.X >= planet_circumference / 2) p.X -= planet_circumference;
if (p.Z >= planet_circumference / 2) p.Z -= planet_circumference;
if (p.X < -planet_circumference / 2) p.X += planet_circumference;

View File

@ -738,7 +738,38 @@ void GenericCAO::updateNodePos()
if (node) {
v3s16 camera_offset = m_env->getCameraOffset();
node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS));
/*
* Planet: Since the planet is actually just a flat map that wraps around
* a seemingly spherical object, there are 9 possible minimal distances to
* the same object, because the end of the map on one side is the beginning
* of the map on the other side again. Find the minimal distance from the player
* to this object.
*/
if (!g_settings->getBool("planet_enable")) {
node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS));
} else {
v3s16 cam_pos_nodes = floatToInt(m_client->getCamera()->getPosition(), BS);
// Round planet circumference up to even number of mapblocks, in nodes
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE;
float mindist = (cam_pos_nodes - floatToInt(m_position, BS)).getLength();
int offset_minimal_x = 0, offset_minimal_z = 0;
for (int wrapx = -1; wrapx <= 1; ++wrapx)
for (int wrapz = -1; wrapz <= 1; ++wrapz) {
float distx = cam_pos_nodes.X - (m_position.X / BS + wrapx * planet_circumference);
float distz = cam_pos_nodes.Z - (m_position.Z / BS + wrapz * planet_circumference);
float dist = sqrt(distx * distx + distz * distz);
if (dist < mindist) {
mindist = dist;
offset_minimal_x = wrapx * planet_circumference;
offset_minimal_z = wrapz * planet_circumference;
}
}
node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS) + v3f(offset_minimal_x * BS, 0, offset_minimal_z * BS));
}
if (node != m_spritenode) { // rotate if not a sprite
v3f rot = node->getRotation();
rot.Y = -m_yaw;

View File

@ -373,6 +373,33 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
m_velocity += dtime * m_acceleration;
}
/*
Handle Planet
*/
if (g_settings->getBool("planet_enable")) {
int planet_radius = g_settings->getU16("planet_radius") * MAP_BLOCKSIZE * BS;
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE * BS;
// Teleport items to other side of planet at planet edges
if (m_base_position.X > planet_circumference / 2 - 0.5 * BS)
m_base_position.X = -(float)planet_circumference / 2 - 0.5 * BS;
if (m_base_position.X < -planet_circumference / 2 - 0.5 * BS)
m_base_position.X = (float)planet_circumference / 2 - 0.5 * BS;
if (m_base_position.Z > planet_circumference / 2 - 0.5 * BS)
m_base_position.Z = -(float)planet_circumference / 2 - 0.5 * BS;
if (m_base_position.Z < -planet_circumference / 2 - 0.5 * BS)
m_base_position.Z = (float)planet_circumference / 2 - 0.5 * BS;
// Make objects fall through the planet center
if (g_settings->getBool("planet_fallthrough_enable")) {
if (m_base_position.Y < -planet_radius) {
m_base_position.Y = -planet_radius + BS;
m_base_position.X += planet_circumference / 2. * (m_base_position.X < 0 ? 1 : -1);
m_velocity.Y *= -1;
}
}
}
if (m_prop.automatic_face_movement_dir &&
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {

View File

@ -279,6 +279,10 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{
bool planet_enable = g_settings->getBool("planet_enable");
int planet_radius = g_settings->getU16("planet_radius");
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2;
v3s16 p;
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
@ -287,7 +291,26 @@ void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
// limit to a sphere
if (p.getDistanceFrom(p0) <= r) {
// Set in list
list.insert(p);
// Activate blocks across planet edges, insert in list
if (planet_enable) {
v3s16 ppos = p;
if (ppos.X >= planet_circumference / 2)
ppos.X -= planet_circumference;
if (ppos.X < -planet_circumference / 2)
ppos.X += planet_circumference;
if (ppos.Z >= planet_circumference / 2)
ppos.Z -= planet_circumference;
if (ppos.Z < -planet_circumference / 2)
ppos.Z += planet_circumference;
if (ppos.Y < -planet_radius) {
ppos.Y = -planet_radius - ppos.Y;
ppos.X += planet_circumference / 2 * (ppos.X < 0 ? 1 : -1);
}
list.insert(ppos);
} else {
list.insert(p);
}
}
}
}
@ -1483,6 +1506,9 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
if (player_radius_f < 0)
player_radius_f = 0;
bool planet_enable = g_settings->getBool("planet_enable");
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE * BS;
/*
Go through the object list,
- discard removed/deactivated objects,
@ -1503,6 +1529,19 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
f32 distance_f = object->getBasePosition().
getDistanceFrom(playersao->getBasePosition());
// Distances on the planet are different, calculate distance across edges
if (planet_enable) {
for (int wrapx = -1; wrapx <= 1; ++wrapx)
for (int wrapz = -1; wrapz <= 1; ++wrapz) {
float dist = object->getBasePosition().getDistanceFrom(
v3f(playersao->getBasePosition() - v3f(wrapx, 0, wrapz) * planet_circumference));
if (dist < distance_f)
distance_f = dist;
}
}
if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
// Discard if too far
if (distance_f > player_radius_f && player_radius_f != 0)
@ -1534,6 +1573,9 @@ void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius
if (player_radius_f < 0)
player_radius_f = 0;
bool planet_enable = g_settings->getBool("planet_enable");
int planet_circumference = ceil(g_settings->getU16("planet_radius") * M_PI) * 2 * MAP_BLOCKSIZE * BS;
/*
Go through current_objects; object is removed if:
- object is not found in m_active_objects (this is actually an
@ -1558,6 +1600,19 @@ void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius
}
f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
// Distances on the planet are different, calculate distance across edges
if (planet_enable) {
for (int wrapx = -1; wrapx <= 1; ++wrapx)
for (int wrapz = -1; wrapz <= 1; ++wrapz) {
float dist = object->getBasePosition().getDistanceFrom(
v3f(playersao->getBasePosition() - v3f(wrapx, 0, wrapz) * planet_circumference));
if (dist < distance_f)
distance_f = dist;
}
}
if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
if (distance_f <= player_radius_f || player_radius_f == 0)
continue;