Gaming ideas:\r
-------------\r
\r
-- How would some GTA-style ideas work?\r
- - Cars? Stealing? Unlawful stuff and cops? Lots of guns?\r
+- Aim for something like controlling a single dwarf in Dwarf Fortress\r
\r
-- RPG style?\r
+- The player could go faster by a crafting a boat, or riding an animal\r
\r
-- Space racer style?\r
+- Random NPC traders. what else?\r
\r
Documentation:\r
--------------\r
meshbuffers? It should go quite fast.\r
- This is not easy; There'd need to be a buffer somewhere\r
that would contain the night and day lighting values.\r
+ - Actually if FastFaces would be stored, they could\r
+ hold both values\r
\r
-TODO: Combine MapBlock's face caches to so big pieces that VBO\r
+FEATURE: Combine MapBlock's face caches to so big pieces that VBO\r
gets used\r
- That is >500 vertices\r
- This is not easy; all the MapBlocks close to the player would\r
\r
TODO: Flowing water animation\r
\r
+FIXME(FIXED): The new texture stuff is slow on wine\r
+ - A basic grassy ground block takes 20-40ms\r
+ - A bit more complicated block can take 270ms\r
+ - On linux, a similar one doesn't take long at all (14ms)\r
+ - It is NOT a bad std::string implementation of MSVC.\r
+ - Can take up to 200ms? Is it when loading textures or always?\r
+ - Updating excess amount of meshes when making footprints is too\r
+ slow. It has to be fixed.\r
+ -> implement Map::updateNodeMeshes()\r
+ The fix:\r
+ * Optimize TileSpec to only contain a reference number that\r
+ is fast to compare, which refers to a cached string, or\r
+ * Make TextureSpec for using instead of strings\r
+\r
+FIXME(FIXED): A lock condition is possible:\r
+ 1) MapBlock::updateMesh() is called from client asynchronously:\r
+ - AsyncProcessData() -> Map::updateMeshes()\r
+ 2) Asynchronous locks m_temp_mods_mutex\r
+ 3) MapBlock::updateMesh() is called from client synchronously:\r
+ - Client::step() -> Environment::step()\r
+ 4) Synchronous starts waiting for m_temp_mods_mutex\r
+ 5) Asynchronous calls getTexture, which starts waiting for main thread\r
+\r
Configuration:\r
--------------\r
\r
\r
TODO: Make morning and evening shorter\r
\r
+TODO: Don't update all meshes always on single node changes, but\r
+ check which ones should be updated\r
+ - implement Map::updateNodeMeshes()\r
+\r
Server:\r
-------\r
\r
NOTE: There are some lighting-related todos and fixmes in\r
ServerMap::emergeBlock. And there always will be. 8)\r
\r
-TODO: Map generator version 2\r
+TODO: Mineral and ground material properties\r
+ - This way mineral ground toughness can be calculated with just\r
+ some formula, as well as tool strengths\r
+\r
+TODO: Change AttributeList to split the area into smaller sections so\r
+ that searching won't be as heavy.\r
+\r
+TODO: Remove HMParams\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: Map generator version 2\r
- Create surface areas based on central points; a given point's\r
area type is given by the nearest central point\r
- Separate points for heightmap, caves, plants and minerals?\r
- Create a system that allows a huge amount of different "map\r
generator modules/filters"\r
\r
-TODO: Change AttributeList to split the area into smaller sections so\r
- that searching won't be as heavy.\r
-TODO: Change AttributeList to be 2D, as it would be too slow to search\r
- in 3D fields anyway.\r
-\r
-FIXME: The new pre-sunlight-propagation code messes up with initial\r
- water lighting. Does it any more?\r
-\r
-TODO: Remove HMParams\r
-\r
-TODO: Flowing water to actually contain flow direction information\r
-\r
-TODO: Faster lighting using VoxelManipulator\r
+FEATURE: The map could be generated procedually:\r
+ - This would need the map to be generated in larger pieces\r
+ - How large? How do they connect to each other?\r
+ - It has to be split vertically also\r
+ - Lighting would not have to be necessarily calculated until\r
+ the blocks are actually needed - it would be quite fast\r
+ - Something like 64*64*16 MapBlocks?\r
+ - No, MapSectors. And as much as it is efficient to do,\r
+ 64x64 might be too much.\r
+ - FIXME: This is currently halfway done and the generator is\r
+ fairly broken\r
+ * Make the stone level with a heightmap\r
+ * Carve out stuff in the stone\r
+ * Dump dirt all around, and simulate it falling off steep\r
+ places\r
+ * Erosion simulation at map generation time\r
+ - Simulate water flows, which would carve out dirt fast and\r
+ then turn stone into gravel and sand and relocate it.\r
+ - How about relocating minerals, too? Coal and gold in\r
+ downstream sand and gravel would be kind of cool\r
+ - This would need a better way of handling minerals, mainly\r
+ to have mineral content as a separate field. the first\r
+ parameter field is free for this.\r
+ - Simulate rock falling from cliffs when water has removed\r
+ enough solid rock from the bottom\r
\r
Doing now:\r
----------\r
+# maybe done\r
+* not done\r
+\r
+* Remove all kinds of systems that are made redundant by the new map\r
+ generator\r
+ - Sector heightmaps? At least they should be made redundant.\r
+ - Sector objects\r
+* Do something about AttributeDatabase/List being too slow\r
+* Save chunk metadata on disk\r
+* Change water side textures so that buggy water doesn't look bad\r
+* Make server find the spawning place from the real map data, not from\r
+ the heightmap\r
+* only_from_disk doesn't work that well anymore\r
+* Make the generator to run in background and not blocking block\r
+ placement and transfer\r
+* Fix the strange mineral occurences\r
+* When the map is generated and a place is found for the player, the\r
+ first chunk is actually still volatile and will have stuff still\r
+ changed after spawning, which creates a lot of glitches.\r
+ - This is partly fixed by now allowing only 2-sector deeep\r
+ modification of volatile chunks. But it should still be fixed?\r
+ - How about checking that the neighbors are fully generated too and\r
+ generate them when the middle piece is needed\r
+ - This is very slow\r
+ - How about just enabling changed_blocks properly\r
+ - This is probably a good idea\r
+ - The server has to make sure the spawn point is not at the\r
+ changing borders of a chunk\r
+* Add some kind of erosion and other stuff that now is possible\r
\r
======================================================================\r
\r
#pragma comment(lib, "Irrlicht.lib")\r
//#pragma comment(lib, "jthread.lib")\r
#pragma comment(lib, "zlibwapi.lib")\r
+#pragma comment(lib, "Shell32.lib")\r
// This would get rid of the console window\r
//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
#endif\r
#include "filesys.h"\r
#include "config.h"\r
#include "guiMainMenu.h"\r
+#include "mineral.h"\r
\r
IrrlichtWrapper *g_irrlicht;\r
\r
std::wstring text;\r
};\r
\r
-int main(int argc, char *argv[])\r
-{\r
- /*\r
- Low-level initialization\r
- */\r
+// These are defined global so that they're not optimized too much.\r
+// Can't change them to volatile.\r
+s16 temp16;\r
+f32 tempf;\r
+v3f tempv3f1;\r
+v3f tempv3f2;\r
+std::string tempstring;\r
+std::string tempstring2;\r
\r
- bool disable_stderr = false;\r
-#ifdef _WIN32\r
- disable_stderr = true;\r
-#endif\r
+void SpeedTests()\r
+{\r
+ {\r
+ dstream<<"The following test should take around 20ms."<<std::endl;\r
+ TimeTaker timer("Testing std::string speed");\r
+ const u32 jj = 10000;\r
+ for(u32 j=0; j<jj; j++)\r
+ {\r
+ tempstring = "";\r
+ tempstring2 = "";\r
+ const u32 ii = 10;\r
+ for(u32 i=0; i<ii; i++){\r
+ tempstring2 += "asd";\r
+ }\r
+ for(u32 i=0; i<ii+1; i++){\r
+ tempstring += "asd";\r
+ if(tempstring == tempstring2)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ dstream<<"All of the following tests should take around 100ms each."\r
+ <<std::endl;\r
\r
- // Initialize debug streams\r
- debugstreams_init(disable_stderr, DEBUGFILE);\r
- // Initialize debug stacks\r
- debug_stacks_init();\r
+ {\r
+ TimeTaker timer("Testing floating-point conversion speed");\r
+ tempf = 0.001;\r
+ for(u32 i=0; i<4000000; i++){\r
+ temp16 += tempf;\r
+ tempf += 0.001;\r
+ }\r
+ }\r
+ \r
+ {\r
+ TimeTaker timer("Testing floating-point vector speed");\r
\r
- DSTACK(__FUNCTION_NAME);\r
+ tempv3f1 = v3f(1,2,3);\r
+ tempv3f2 = v3f(4,5,6);\r
+ for(u32 i=0; i<10000000; i++){\r
+ tempf += tempv3f1.dotProduct(tempv3f2);\r
+ tempv3f2 += v3f(7,8,9);\r
+ }\r
+ }\r
\r
- porting::initializePaths();\r
- // Create user data directory\r
- fs::CreateDir(porting::path_userdata);\r
+ {\r
+ TimeTaker timer("Testing core::map speed");\r
+ \r
+ core::map<v2s16, f32> map1;\r
+ tempf = -324;\r
+ const s16 ii=300;\r
+ for(s16 y=0; y<ii; y++){\r
+ for(s16 x=0; x<ii; x++){\r
+ map1.insert(v2s16(x,y), tempf);\r
+ tempf += 1;\r
+ }\r
+ }\r
+ for(s16 y=ii-1; y>=0; y--){\r
+ for(s16 x=0; x<ii; x++){\r
+ tempf = map1[v2s16(x,y)];\r
+ }\r
+ }\r
+ }\r
\r
- initializeMaterialProperties();\r
+ {\r
+ dstream<<"Around 5000/ms should do well here."<<std::endl;\r
+ TimeTaker timer("Testing mutex speed");\r
+ \r
+ JMutex m;\r
+ m.Init();\r
+ u32 n = 0;\r
+ u32 i = 0;\r
+ do{\r
+ n += 10000;\r
+ for(; i<n; i++){\r
+ m.Lock();\r
+ m.Unlock();\r
+ }\r
+ }\r
+ // Do at least 10ms\r
+ while(timer.getTime() < 10);\r
\r
- BEGIN_DEBUG_EXCEPTION_HANDLER\r
+ u32 dtime = timer.stop();\r
+ u32 per_ms = n / dtime;\r
+ std::cout<<"Done. "<<dtime<<"ms, "\r
+ <<per_ms<<"/ms"<<std::endl;\r
+ }\r
+}\r
\r
- // Print startup message\r
- dstream<<DTIME<<"minetest-c55"\r
- " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
- <<", "<<BUILD_INFO\r
- <<std::endl;\r
- \r
+int main(int argc, char *argv[])\r
+{\r
/*\r
Parse command line\r
*/\r
allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
+#ifdef _WIN32\r
+ allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
+#endif\r
+ allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
\r
Settings cmd_args;\r
\r
\r
return cmd_args.getFlag("help") ? 0 : 1;\r
}\r
+ \r
+ /*\r
+ Low-level initialization\r
+ */\r
\r
+ bool disable_stderr = false;\r
+#ifdef _WIN32\r
+ if(cmd_args.getFlag("dstream-on-stderr") == false)\r
+ disable_stderr = true;\r
+#endif\r
\r
+ // Initialize debug streams\r
+ debugstreams_init(disable_stderr, DEBUGFILE);\r
+ // Initialize debug stacks\r
+ debug_stacks_init();\r
+\r
+ DSTACK(__FUNCTION_NAME);\r
+\r
+ porting::initializePaths();\r
+ // Create user data directory\r
+ fs::CreateDir(porting::path_userdata);\r
+ \r
+ // C-style stuff initialization\r
+ initializeMaterialProperties();\r
+\r
+ // Debug handler\r
+ BEGIN_DEBUG_EXCEPTION_HANDLER\r
+\r
+ // Print startup message\r
+ dstream<<DTIME<<"minetest-c55"\r
+ " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
+ <<", "<<BUILD_INFO\r
+ <<std::endl;\r
+ \r
/*\r
Basic initialization\r
*/\r
srand(time(0));\r
mysrand(time(0));\r
\r
+ /*\r
+ Pre-initialize some stuff with a dummy irrlicht wrapper.\r
+\r
+ These are needed for unit tests at least.\r
+ */\r
+ \r
+ IIrrlichtWrapper irrlicht_dummy;\r
+\r
+ init_mapnode(&irrlicht_dummy);\r
+\r
/*\r
Run unit tests\r
*/\r
g_device = device;\r
g_irrlicht = new IrrlichtWrapper(device);\r
\r
- //g_device = device;\r
+ /*\r
+ Speed tests (done after irrlicht is loaded to get timer)\r
+ */\r
+ if(cmd_args.getFlag("speedtests"))\r
+ {\r
+ dstream<<"Running speed tests"<<std::endl;\r
+ SpeedTests();\r
+ return 0;\r
+ }\r
\r
device->setResizable(true);\r
\r
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
\r
/*\r
- Preload some textures\r
+ Preload some textures and stuff\r
*/\r
\r
init_content_inventory_texture_paths();\r
- init_tile_textures();\r
+ init_mapnode(g_irrlicht);\r
+ init_mineral(g_irrlicht);\r
\r
/*\r
GUI stuff\r
{\r
\r
/*\r
- Out-of-game menu loop\r
+ Out-of-game menu loop.\r
+\r
+ Loop quits when menu returns proper parameters.\r
*/\r
- \r
- // Wait for proper parameters\r
for(;;)\r
{\r
// Cursor can be non-visible when coming from the game\r
dstream<<"Dropping main menu"<<std::endl;\r
\r
menu->drop();\r
+ \r
+ // Delete map if requested\r
+ if(menudata.delete_map)\r
+ {\r
+ bool r = fs::RecursiveDeleteContent(map_dir);\r
+ if(r == false)\r
+ error_message = L"Delete failed";\r
+ continue;\r
+ }\r
\r
playername = wide_to_narrow(menudata.name);\r
address = wide_to_narrow(menudata.address);\r
*/\r
{\r
\r
+ // This is set to true at the end of the scope\r
+ g_irrlicht->Shutdown(false);\r
+\r
/*\r
Draw "Loading" screen\r
*/\r
dtime_jitter1_max_fraction\r
= dtime_jitter1_max_sample / (dtime_avg1+0.001);\r
jitter1_max = 0.0;\r
- \r
- /*\r
- Control freetime ratio\r
- */\r
- /*if(dtime_jitter1_max_fraction > DTIME_JITTER_MAX_FRACTION)\r
- {\r
- if(g_freetime_ratio < FREETIME_RATIO_MAX)\r
- g_freetime_ratio += 0.01;\r
- }\r
- else\r
- {\r
- if(g_freetime_ratio > FREETIME_RATIO_MIN)\r
- g_freetime_ratio -= 0.01;\r
- }*/\r
}\r
}\r
\r
camera_direction.rotateXZBy(camera_yaw);\r
\r
// This is at the height of the eyes of the current figure\r
- v3f camera_position = player_position + v3f(0, BS+BS/2, 0);\r
+ //v3f camera_position = player_position + v3f(0, BS+BS/2, 0);\r
// This is more like in minecraft\r
- //v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);\r
+ v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);\r
\r
camera->setPosition(camera_position);\r
// *100.0 helps in large map coordinates\r
bool nodefound = false;\r
v3s16 nodepos;\r
v3s16 neighbourpos;\r
- core::aabbox3d<f32> nodefacebox;\r
+ core::aabbox3d<f32> nodehilightbox;\r
f32 mindistance = BS * 1001;\r
\r
v3s16 pos_i = floatToInt(player_position);\r
nodepos = np;\r
neighbourpos = np;\r
mindistance = distance;\r
- nodefacebox = box;\r
+ nodehilightbox = box;\r
}\r
}\r
}\r
nodepos = np;\r
neighbourpos = np + dirs[i];\r
mindistance = distance;\r
- nodefacebox = facebox;\r
+\r
+ //nodehilightbox = facebox;\r
+\r
+ const float d = 0.502;\r
+ core::aabbox3d<f32> nodebox\r
+ (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
+ v3f nodepos_f = intToFloat(nodepos);\r
+ nodebox.MinEdge += nodepos_f;\r
+ nodebox.MaxEdge += nodepos_f;\r
+ nodehilightbox = nodebox;\r
}\r
} // if distance < mindistance\r
} // for dirs\r
\r
static float dig_time = 0.0;\r
static u16 dig_index = 0;\r
+ \r
+ // Visualize selection\r
+\r
+ hilightboxes.push_back(nodehilightbox);\r
\r
- hilightboxes.push_back(nodefacebox);\r
+ // Handle digging\r
\r
if(g_input->getLeftReleased())\r
{\r
\r
if(dig_index < CRACK_ANIMATION_LENGTH)\r
{\r
+ //TimeTaker timer("client.setTempMod");\r
//dstream<<"dig_index="<<dig_index<<std::endl;\r
client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
}\r
}\r
// We want a slight delay to very little\r
// time consuming nodes\r
- //float mindelay = 0.15;\r
- float mindelay = 0.20;\r
+ float mindelay = 0.15;\r
if(nodig_delay_counter < mindelay)\r
{\r
nodig_delay_counter = mindelay;\r
//TimeTaker //timer10("//timer10");\r
\r
video::SMaterial m;\r
- m.Thickness = 10;\r
+ //m.Thickness = 10;\r
+ m.Thickness = 3;\r
m.Lighting = false;\r
driver->setMaterial(m);\r
\r
\r
delete quick_inventory;\r
\r
+ /*\r
+ Disable texture fetches and other stuff that is queued\r
+ to be processed by the main loop.\r
+\r
+ This has to be done before client goes out of scope.\r
+ */\r
+ g_irrlicht->Shutdown(true);\r
+\r
} // client and server are deleted at this point\r
\r
} //try\r