#!/usr/bin/python
+"
+This is an example script that generates some valid map data.
+"
+
import struct
import random
}
else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
{
- /*
- u16 command
- u16 count of removed objects
- for all removed objects {
- u16 id
- }
- u16 count of added objects
- for all added objects {
- u16 id
- u8 type
- u16 initialization data length
- string initialization data
- }
- */
+ if(g_settings.getBool("enable_experimental"))
+ {
+ /*
+ u16 command
+ u16 count of removed objects
+ for all removed objects {
+ u16 id
+ }
+ u16 count of added objects
+ for all added objects {
+ u16 id
+ u8 type
+ u16 initialization data length
+ string initialization data
+ }
+ */
- char buf[6];
- // Get all data except the command number
- std::string datastring((char*)&data[2], datasize-2);
- // Throw them in an istringstream
- std::istringstream is(datastring, std::ios_base::binary);
+ char buf[6];
+ // Get all data except the command number
+ std::string datastring((char*)&data[2], datasize-2);
+ // Throw them in an istringstream
+ std::istringstream is(datastring, std::ios_base::binary);
- // Read stuff
-
- // Read removed objects
- is.read(buf, 2);
- u16 removed_count = readU16((u8*)buf);
- for(u16 i=0; i<removed_count; i++)
- {
+ // Read stuff
+
+ // Read removed objects
is.read(buf, 2);
- u16 id = readU16((u8*)buf);
- // Remove it
+ u16 removed_count = readU16((u8*)buf);
+ for(u16 i=0; i<removed_count; i++)
{
- JMutexAutoLock envlock(m_env_mutex);
- m_env.removeActiveObject(id);
+ is.read(buf, 2);
+ u16 id = readU16((u8*)buf);
+ // Remove it
+ {
+ JMutexAutoLock envlock(m_env_mutex);
+ m_env.removeActiveObject(id);
+ }
}
- }
-
- // Read added objects
- is.read(buf, 2);
- u16 added_count = readU16((u8*)buf);
- for(u16 i=0; i<added_count; i++)
- {
+
+ // Read added objects
is.read(buf, 2);
- u16 id = readU16((u8*)buf);
- is.read(buf, 1);
- u8 type = readU8((u8*)buf);
- std::string data = deSerializeLongString(is);
- // Add it
+ u16 added_count = readU16((u8*)buf);
+ for(u16 i=0; i<added_count; i++)
{
- JMutexAutoLock envlock(m_env_mutex);
- m_env.addActiveObject(id, type, data);
+ is.read(buf, 2);
+ u16 id = readU16((u8*)buf);
+ is.read(buf, 1);
+ u8 type = readU8((u8*)buf);
+ std::string data = deSerializeLongString(is);
+ // Add it
+ {
+ JMutexAutoLock envlock(m_env_mutex);
+ m_env.addActiveObject(id, type, data);
+ }
}
}
}
else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
{
- /*
- u16 command
- for all objects
- {
- u16 id
- u16 message length
- string message
- }
- */
- char buf[6];
- // Get all data except the command number
- std::string datastring((char*)&data[2], datasize-2);
- // Throw them in an istringstream
- std::istringstream is(datastring, std::ios_base::binary);
-
- while(is.eof() == false)
+ if(g_settings.getBool("enable_experimental"))
{
- // Read stuff
- is.read(buf, 2);
- u16 id = readU16((u8*)buf);
- if(is.eof())
- break;
- is.read(buf, 2);
- u16 message_size = readU16((u8*)buf);
- std::string message;
- message.reserve(message_size);
- for(u16 i=0; i<message_size; i++)
- {
- is.read(buf, 1);
- message.append(buf, 1);
- }
- // Pass on to the environment
+ /*
+ u16 command
+ for all objects
+ {
+ u16 id
+ u16 message length
+ string message
+ }
+ */
+ char buf[6];
+ // Get all data except the command number
+ std::string datastring((char*)&data[2], datasize-2);
+ // Throw them in an istringstream
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ while(is.eof() == false)
{
- JMutexAutoLock envlock(m_env_mutex);
- m_env.processActiveObjectMessage(id, message);
+ // Read stuff
+ is.read(buf, 2);
+ u16 id = readU16((u8*)buf);
+ if(is.eof())
+ break;
+ is.read(buf, 2);
+ u16 message_size = readU16((u8*)buf);
+ std::string message;
+ message.reserve(message_size);
+ for(u16 i=0; i<message_size; i++)
+ {
+ is.read(buf, 1);
+ message.append(buf, 1);
+ }
+ // Pass on to the environment
+ {
+ JMutexAutoLock envlock(m_env_mutex);
+ m_env.processActiveObjectMessage(id, message);
+ }
}
}
}
\r
* Combine meshes to bigger ones in ClientMap and set them EHM_STATIC\r
\r
+SUGG: Draw cubes in inventory directly with 3D drawing commands, so that\r
+ animating them is easier.\r
+\r
Configuration:\r
--------------\r
\r
\r
TODO: Flowing water to actually contain flow direction information\r
\r
-TODO: Remove duplicate lighting implementation from Map (leave\r
- VoxelManipulator, which is faster)\r
-\r
FEATURE: Create a system that allows a huge amount of different "map\r
generator modules/filters"\r
\r
the other chunk making nasty straight walls when the other chunk\r
is generated. Fix it.\r
\r
+Mapgen v4 (not doing):\r
+* only_from_disk might not work anymore - check and fix it.\r
+* Make the generator to run in background and not blocking block\r
+ placement and transfer\r
+* Make chunks to be tiled vertically too\r
+* MAKE IT FASTER\r
+\r
Mapgen v3:\r
* Generate trees better\r
- Add a "trees_added" flag to sector, or something\r
* How 'bout making turbulence controlled so that for a given 2d position\r
it can be completely turned off, and is usually so. This way generation\r
can be sped up a lot.\r
+* Add a way to generate a block partly, so that trees are not added, like\r
+ the chunks in v2\r
+* Add mud "discretely", not by guessing from the noise\r
\r
Mapgen v4:\r
-* only_from_disk might not work anymore - check and fix it.\r
-* Make the generator to run in background and not blocking block\r
- placement and transfer\r
-* Make chunks to be tiled vertically too\r
+* This will be the final way.\r
+* Generate blocks in the same way as chunks, by copying a voxelmanipulator\r
+ from the map that is one block larger in all directions.\r
\r
Misc. stuff:\r
------------\r
light_sources to re-light the area without the removed light.
values of from_nodes are lighting values.
+
+ There is a duplicate implementation of this in VoxelManipulator,
+ which is faster for large volumes
*/
void Map::unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
/*
Lights neighbors of from_nodes, collects all them and then
goes on recursively.
+
+ There is a duplicate implementation of this in VoxelManipulator,
+ which is faster for large volumes
*/
void Map::spreadLight(enum LightBank bank,
core::map<v3s16, bool> & from_nodes,
This is called after changing a node from transparent to opaque.
The lighting value of the node should be left as-is after changing
other values. This sets the lighting value to 0.
+
+ NOTE: This takes almost no time, the slow one is updateMeshes.
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks)
}
/*
+ NOTE: This takes almost no time, the slow one is updateMeshes.
*/
void Map::removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks)
double sandnoise = noise2d_perlin(
0.5+(float)p.X/500, 0.5+(float)p.Y/500,
seed+54290232, 6, 0.65);
- return (sandnoise > 0.8);
+ return (sandnoise > 1.0);
}
// -1->0, 0->1, 1->0
{
DSTACK(__FUNCTION_NAME);
-
/*
Don't generate if already fully generated
*/
}
}
+#if 0
dstream<<"generateChunkRaw(): Generating chunk "
<<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
<<std::endl;
block->updateDayNightDiff();
}
}
-
+#endif
/*
Create chunk metadata
/*
NOTE: This is not used for main map generation, only for blocks
- that are very high or low
+ that are very high or low.
+ NOTE: Now it is used mainly. Might change in the future.
*/
MapBlock * ServerMap::generateBlock(
v3s16 p,
float surface_y_f = 0;
s16 surface_y = 0;
- if(turbulence_is_used == false)
- {
- surface_y_f = base_rock_level_2d(m_seed, real_p2d_f),
- surface_y = surface_y_f;
+ float noturb_surface_y_f = base_rock_level_2d(m_seed, real_p2d_f);
+ s16 noturb_surface_y = noturb_surface_y_f;
- // Get some statistics of surface height
- if(surface_y < lowest_ground_y)
- lowest_ground_y = surface_y;
- if(surface_y > highest_ground_y)
- highest_ground_y = surface_y;
- }
-
+ // Get some statistics of surface height
+ if(noturb_surface_y < lowest_ground_y)
+ lowest_ground_y = noturb_surface_y;
+ if(noturb_surface_y > highest_ground_y)
+ highest_ground_y = noturb_surface_y;
+
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
{
#if 1
bool is_ground = false;
v3f real_pos_f = intToFloat(real_pos, 1);
- if(turbulence_is_used)
+ bool turb_for_node = (turbulence_is_used
+ && real_y >= TURBULENCE_BOTTOM_CUTOFF_Y);
+
+ bool is_cavern = false;
+
+ if(is_carved(m_seed, real_pos_f))
{
- double depth_guess;
- is_ground = is_base_ground(m_seed,
- real_pos_f, &depth_guess);
-
- // Estimate the surface height
- surface_y_f = (float)real_y + depth_guess;
- surface_y = real_y + depth_guess;
-
- // Get some statistics of surface height
- if(surface_y < lowest_ground_y)
- lowest_ground_y = surface_y;
- if(surface_y > highest_ground_y)
- highest_ground_y = surface_y;
+ is_ground = false;
+ if(real_y < noturb_surface_y)
+ is_cavern = true;
}
else
{
- if(is_carved(m_seed, real_pos_f))
- is_ground = false;
+ if(turb_for_node)
+ {
+ double depth_guess;
+ is_ground = is_base_ground(m_seed,
+ real_pos_f, &depth_guess);
+
+ // Estimate the surface height
+ surface_y_f = (float)real_y + depth_guess;
+ surface_y = real_y + depth_guess;
+
+ // Get some statistics of surface height
+ if(surface_y < lowest_ground_y)
+ lowest_ground_y = surface_y;
+ if(surface_y > highest_ground_y)
+ highest_ground_y = surface_y;
+ }
else
- is_ground = (real_y <= surface_y);
+ {
+ surface_y = noturb_surface_y;
+ }
+
+ is_ground = (real_y <= surface_y);
}
// If node is not ground, it's air or water
if(is_ground == false)
{
// If under water level, it's water
- if(real_y < WATER_LEVEL)
+ if(real_y < WATER_LEVEL && !is_cavern)
{
n.d = water_material;
u8 dist = 16;
void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
{
- assert(mapType() == MAPTYPE_CLIENT);
-
try{
v3s16 p = blockpos + v3s16(0,0,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh(daynight_ratio);
}
catch(InvalidPositionException &e){}
- /*// Trailing edge
- try{
- v3s16 p = blockpos + v3s16(1,0,0);
- MapBlock *b = getBlockNoCreate(p);
- b->updateMesh(daynight_ratio);
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,1,0);
- MapBlock *b = getBlockNoCreate(p);
- b->updateMesh(daynight_ratio);
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,0,1);
- MapBlock *b = getBlockNoCreate(p);
+}
+
+/*
+ Update mesh of block in which the node is, and if the node is at the
+ leading edge, update the appropriate leading blocks too.
+*/
+void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
+{
+ v3s16 dirs[4] = {
+ v3s16(0,0,0),
+ v3s16(-1,0,0),
+ v3s16(0,-1,0),
+ v3s16(0,0,-1),
+ };
+ v3s16 blockposes[4];
+ for(u32 i=0; i<4; i++)
+ {
+ v3s16 np = nodepos + dirs[i];
+ blockposes[i] = getNodeBlockPos(np);
+ // Don't update mesh of block if it has been done already
+ bool already_updated = false;
+ for(u32 j=0; j<i; j++)
+ {
+ if(blockposes[j] == blockposes[i])
+ {
+ already_updated = true;
+ break;
+ }
+ }
+ if(already_updated)
+ continue;
+ // Update mesh
+ MapBlock *b = getBlockNoCreate(blockposes[i]);
b->updateMesh(daynight_ratio);
}
- catch(InvalidPositionException &e){}*/
}
void ClientMap::PrintInfo(std::ostream &out)
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
// Update meshes that touch the node
- //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
+ void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
// For debug printing
virtual void PrintInfo(std::ostream &out);
return dtime;
}
+const v3s16 g_6dirs[6] =
+{
+ // +right, +top, +back
+ v3s16( 0, 0, 1), // back
+ v3s16( 0, 1, 0), // top
+ v3s16( 1, 0, 0), // right
+ v3s16( 0, 0,-1), // front
+ v3s16( 0,-1, 0), // bottom
+ v3s16(-1, 0, 0) // left
+};
+
const v3s16 g_26dirs[26] =
{
// +right, +top, +back
#include "exceptions.h"
#include "porting.h"
+extern const v3s16 g_6dirs[6];
+
extern const v3s16 g_26dirs[26];
// 26th is (0,0,0)