if something is already in it)\r
- Use it in active block queue in water flowing\r
\r
-SUGG: Signs could be done in the same way as torches. For this, blocks\r
- need an additional metadata field for the texts\r
-\r
SUGG: Precalculate lighting translation table at runtime (at startup)\r
\r
SUGG: A version number to blocks, which increments when the block is\r
- This can then be used to make sure the most recent version of\r
a block has been sent to client\r
\r
+SUGG: Make the amount of blocks sending to client and the total\r
+ amount of blocks dynamically limited. Transferring blocks is the\r
+ main network eater of this system, so it is the one that has\r
+ to be throttled so that RTTs stay low.\r
+\r
+SUGG: Meshes of blocks could be split into 6 meshes facing into\r
+ different directions and then only those drawn that need to be\r
+ - Also an 1-dimensional tile map would be nice probably\r
+\r
+TODO: Untie client network operations from framerate\r
+ - Needs some input queues or something\r
+ - Not really necessary?\r
+\r
TODO: Combine MapBlock's face caches to so big pieces that VBO\r
gets used\r
- That is >500 vertices\r
\r
-TODO: Better dungeons\r
-TODO: Cliffs, arcs\r
-\r
-TODO: Menus\r
-\r
-TODO: Moving players more smoothly. Calculate moving animation\r
- in a way that doesn't make the player jump to the right place\r
- immediately when the server sends a new position\r
+TODO: Startup and configuration menu\r
\r
TODO: There are some lighting-related todos and fixmes in\r
ServerMap::emergeBlock\r
is not in the middle of an ocean (some land to stand on at\r
least) and save it in map config.\r
\r
-TODO: Make the amount of blocks sending to client and the total\r
- amount of blocks dynamically limited. Transferring blocks is the\r
- main network eater of this system, so it is the one that has\r
- to be throttled so that RTTs stay low.\r
-\r
-TODO: Server to load starting inventory from disk\r
-\r
TODO: Players to only be hidden when the client quits.\r
TODO: - Players to be saved on disk, with inventory\r
TODO: Players to be saved as text in map/players/<name>\r
+TODO: Player inventory to be saved on disk\r
\r
TODO: Make fetching sector's blocks more efficient when rendering\r
sectors that have very large amounts of blocks (on client)\r
\r
TODO: Make the video backend selectable\r
\r
+TODO: Copy the text of the last picked sign to inventory in creative\r
+ mode\r
+\r
+TODO: Get rid of GotSplitPacketException\r
+\r
+TODO: Check what goes wrong with caching map to disk (Kray)\r
+ - Nothing?\r
+\r
Block object server side:\r
- A "near blocks" buffer, in which some nearby blocks are stored.\r
- For all blocks in the buffer, objects are stepped(). This\r
- TODO: For incoming blocks, time difference is calculated and\r
objects are stepped according to it.\r
\r
-TODO: Copy the text of the last picked sign to inventory in creative\r
- mode\r
-\r
-TODO: Untie client network operations from framerate\r
- - Needs some input queues or something\r
-\r
-TODO: Get rid of GotSplitPacketException\r
-\r
-TODO: Check what goes wrong with caching map to disk (Kray)\r
-\r
-TODO: Remove LazyMeshUpdater. It is not used as supposed.\r
-\r
-TODO: TOSERVER_LEAVE\r
-\r
TODO: Better handling of objects and mobs\r
- Scripting?\r
- There has to be some way to do it with less spaghetti code\r
- Make separate classes for client and server\r
- Client should not discriminate between blocks, server should\r
- Make other players utilize the same framework\r
+ - This is also needed for objects that don't get sent to client\r
+ but are used for triggers etc\r
+\r
+TODO: Draw big amounts of torches better (that is, throw them in the\r
+ same meshbuffer (can the meshcollector class be used?))\r
+\r
+TODO: Make an option to the server to disable building and digging near\r
+ the starting position\r
\r
-SUGG: Split Inventory into ClientInventory and ServerInventory\r
+SUGG: Signs could be done in the same way as torches. For this, blocks\r
+ need an additional metadata field for the texts\r
+ - This is also needed for item container chests\r
+TODO: There has to be some better way to handle static objects than to\r
+ send them all the time. This affects signs and item objects.\r
+\r
+TODO: When server sees that client is removing an inexistent block or\r
+ adding a block to an existent position, resend the MapBlock.\r
+\r
+TODO: When player dies, throw items on map\r
+\r
+TODO: Use porting::path_userdata for configuration file\r
+\r
+TODO: Optimize day/night mesh updating somehow\r
+ - create copies of all textures for all lighting values and only\r
+ change texture for material?\r
+ - Umm... the collecting of the faces is the slow part\r
+ -> what about just changing the color values of the existing\r
+ meshbuffers? It should go quite fast.\r
+\r
+TODO: 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
+ - Flat land, mountains, forest, jungle\r
+ - Cliffs, arcs\r
+\r
+TODO: Add gui option to remove map\r
\r
Doing now:\r
======================================================================\r
\r
-\r
======================================================================\r
\r
*/\r
*/\r
#define FIELD_OF_VIEW_TEST 0\r
\r
-#ifdef UNITTEST_DISABLE\r
+#ifdef NDEBUG\r
#ifdef _WIN32\r
#pragma message ("Disabling unit tests")\r
#else\r
#include "constants.h"\r
#include "strfnd.h"\r
#include "porting.h"\r
-#include "guiPauseMenu.h"\r
#include "irrlichtwrapper.h"\r
#include "gettime.h"\r
#include "porting.h"\r
+#include "guiPauseMenu.h"\r
#include "guiInventoryMenu.h"\r
+#include "guiTextInputMenu.h"\r
+#include "materials.h"\r
+#include "guiMessageMenu.h"\r
+#include "filesys.h"\r
+#include "config.h"\r
\r
IrrlichtWrapper *g_irrlicht;\r
\r
-// All range-related stuff below is locked behind this\r
-JMutex g_range_mutex;\r
-\r
-// Blocks are viewed in this range from the player\r
-s16 g_viewing_range_nodes = 60;\r
-//s16 g_viewing_range_nodes = 0;\r
-\r
-// This is updated by the client's fetchBlocks routine\r
-//s16 g_actual_viewing_range_nodes = VIEWING_RANGE_NODES_DEFAULT;\r
-\r
-// If true, the preceding value has no meaning and all blocks\r
-// already existing in memory are drawn\r
-bool g_viewing_range_all = false;\r
-\r
-// This is the freetime ratio imposed by the dynamic viewing\r
-// range changing code.\r
-// It is controlled by the main loop to the smallest value that\r
-// inhibits glitches (dtime jitter) in the main loop.\r
-//float g_freetime_ratio = FREETIME_RATIO_MAX;\r
+MapDrawControl draw_control;\r
\r
/*\r
Settings.\r
Random stuff\r
*/\r
\r
-//u16 g_selected_material = 0;\r
-u16 g_selected_item = 0;\r
+IrrlichtDevice *g_device = NULL;\r
+Client *g_client = NULL;\r
\r
+/*\r
+ GUI Stuff\r
+*/\r
gui::IGUIEnvironment* guienv = NULL;\r
-GUIPauseMenu *pauseMenu = NULL;\r
-GUIInventoryMenu *inventoryMenu = NULL;\r
+gui::IGUIStaticText *guiroot = NULL;\r
+int g_active_menu_count = 0;\r
\r
-std::wstring g_text_buffer;\r
-bool g_text_buffer_accepted = false;\r
+bool noMenuActive()\r
+{\r
+ return (g_active_menu_count == 0);\r
+}\r
\r
-// When true, the mouse and keyboard are grabbed\r
-bool g_game_focused = true;\r
+// Inventory actions from the menu are buffered here before sending\r
+Queue<InventoryAction*> inventory_action_queue;\r
+// This is a copy of the inventory that the client's environment has\r
+Inventory local_inventory;\r
+\r
+u16 g_selected_item = 0;\r
\r
/*\r
Debug streams\r
return g_irrlicht->getTime();\r
}\r
\r
+/*\r
+ Text input system\r
+*/\r
+\r
+struct TextDestSign : public TextDest\r
+{\r
+ TextDestSign(v3s16 blockpos, s16 id, Client *client)\r
+ {\r
+ m_blockpos = blockpos;\r
+ m_id = id;\r
+ m_client = client;\r
+ }\r
+ void gotText(std::wstring text)\r
+ {\r
+ std::string ntext = wide_to_narrow(text);\r
+ dstream<<"Changing text of a sign object: "\r
+ <<ntext<<std::endl;\r
+ m_client->sendSignText(m_blockpos, m_id, ntext);\r
+ }\r
+\r
+ v3s16 m_blockpos;\r
+ s16 m_id;\r
+ Client *m_client;\r
+};\r
+\r
+struct TextDestChat : public TextDest\r
+{\r
+ TextDestChat(Client *client)\r
+ {\r
+ m_client = client;\r
+ }\r
+ void gotText(std::wstring text)\r
+ {\r
+ m_client->sendChatMessage(text);\r
+ m_client->addChatMessage(text);\r
+ }\r
+\r
+ Client *m_client;\r
+};\r
+\r
class MyEventReceiver : public IEventReceiver\r
{\r
public:\r
// This is the one method that we have to implement\r
virtual bool OnEvent(const SEvent& event)\r
{\r
+ /*\r
+ React to nothing here if a menu is active\r
+ */\r
+ if(noMenuActive() == false)\r
+ {\r
+ clearInput();\r
+ return false;\r
+ }\r
+\r
// Remember whether each key is down or up\r
if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
{\r
if(event.KeyInput.PressedDown)\r
{\r
//dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;\r
- if(g_game_focused == false)\r
- {\r
- s16 key = event.KeyInput.Key;\r
- if(key == irr::KEY_RETURN || key == irr::KEY_ESCAPE)\r
- {\r
- g_text_buffer_accepted = true;\r
- }\r
- else if(key == irr::KEY_BACK)\r
- {\r
- if(g_text_buffer.size() > 0)\r
- g_text_buffer = g_text_buffer.substr\r
- (0, g_text_buffer.size()-1);\r
- }\r
- else\r
- {\r
- wchar_t wc = event.KeyInput.Char;\r
- if(wc != 0)\r
- g_text_buffer += wc;\r
- }\r
- }\r
\r
- if(pauseMenu != NULL)\r
+ /*\r
+ Launch menus\r
+ */\r
+\r
+ if(guienv != NULL && guiroot != NULL && g_device != NULL)\r
{\r
if(event.KeyInput.Key == irr::KEY_ESCAPE)\r
{\r
- if(g_game_focused == true\r
- && !pauseMenu->isVisible()\r
- && !inventoryMenu->isVisible())\r
- {\r
- dstream<<DTIME<<"MyEventReceiver: "\r
- <<"Launching pause menu"<<std::endl;\r
- pauseMenu->launch();\r
- return true;\r
- }\r
+ dstream<<DTIME<<"MyEventReceiver: "\r
+ <<"Launching pause menu"<<std::endl;\r
+ // It will delete itself by itself\r
+ (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
+ &g_active_menu_count))->drop();\r
+ return true;\r
}\r
- }\r
-\r
- if(inventoryMenu != NULL)\r
- {\r
if(event.KeyInput.Key == irr::KEY_KEY_I)\r
{\r
- if(g_game_focused == true\r
- && !inventoryMenu->isVisible()\r
- && !pauseMenu->isVisible())\r
- {\r
- dstream<<DTIME<<"MyEventReceiver: "\r
- <<"Launching inventory"<<std::endl;\r
- inventoryMenu->launch();\r
- return true;\r
- }\r
+ dstream<<DTIME<<"MyEventReceiver: "\r
+ <<"Launching inventory"<<std::endl;\r
+ (new GUIInventoryMenu(guienv, guiroot, -1,\r
+ &local_inventory, &inventory_action_queue,\r
+ &g_active_menu_count))->drop();\r
+ return true;\r
+ }\r
+ if(event.KeyInput.Key == irr::KEY_KEY_T)\r
+ {\r
+ TextDest *dest = new TextDestChat(g_client);\r
+\r
+ (new GUITextInputMenu(guienv, guiroot, -1,\r
+ &g_active_menu_count, dest,\r
+ L""))->drop();\r
}\r
}\r
\r
// Material selection\r
if(event.KeyInput.Key == irr::KEY_KEY_F)\r
{\r
- if(g_game_focused == true)\r
- {\r
- if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
- g_selected_item++;\r
- else\r
- g_selected_item = 0;\r
- dstream<<DTIME<<"Selected item: "\r
- <<g_selected_item<<std::endl;\r
- }\r
+ if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
+ g_selected_item++;\r
+ else\r
+ g_selected_item = 0;\r
+ dstream<<DTIME<<"Selected item: "\r
+ <<g_selected_item<<std::endl;\r
}\r
\r
// Viewing range selection\r
- if(event.KeyInput.Key == irr::KEY_KEY_R\r
- && g_game_focused)\r
+ if(event.KeyInput.Key == irr::KEY_KEY_R)\r
{\r
- JMutexAutoLock lock(g_range_mutex);\r
- if(g_viewing_range_all)\r
+ if(draw_control.range_all)\r
{\r
- g_viewing_range_all = false;\r
+ draw_control.range_all = false;\r
dstream<<DTIME<<"Disabled full viewing range"<<std::endl;\r
}\r
else\r
{\r
- g_viewing_range_all = true;\r
+ draw_control.range_all = true;\r
dstream<<DTIME<<"Enabled full viewing range"<<std::endl;\r
}\r
}\r
\r
// Print debug stacks\r
- if(event.KeyInput.Key == irr::KEY_KEY_P\r
- && g_game_focused)\r
+ if(event.KeyInput.Key == irr::KEY_KEY_P)\r
{\r
dstream<<"-----------------------------------------"\r
<<std::endl;\r
\r
if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
{\r
- //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
- left_active = event.MouseInput.isLeftPressed();\r
- middle_active = event.MouseInput.isMiddlePressed();\r
- right_active = event.MouseInput.isRightPressed();\r
-\r
- if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
+ if(noMenuActive() == false)\r
{\r
- leftclicked = true;\r
- }\r
- if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
- {\r
- rightclicked = true;\r
+ left_active = false;\r
+ middle_active = false;\r
+ right_active = false;\r
}\r
- if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
- {\r
- leftreleased = true;\r
- }\r
- if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
- {\r
- rightreleased = true;\r
- }\r
- if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
+ else\r
{\r
- /*dstream<<"event.MouseInput.Wheel="\r
- <<event.MouseInput.Wheel<<std::endl;*/\r
- if(event.MouseInput.Wheel < 0)\r
+ //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
+ left_active = event.MouseInput.isLeftPressed();\r
+ middle_active = event.MouseInput.isMiddlePressed();\r
+ right_active = event.MouseInput.isRightPressed();\r
+\r
+ if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
{\r
- if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
- g_selected_item++;\r
- else\r
- g_selected_item = 0;\r
+ leftclicked = true;\r
}\r
- else if(event.MouseInput.Wheel > 0)\r
+ if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
{\r
- if(g_selected_item > 0)\r
- g_selected_item--;\r
- else\r
- g_selected_item = PLAYER_INVENTORY_SIZE-1;\r
+ rightclicked = true;\r
+ }\r
+ if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
+ {\r
+ leftreleased = true;\r
+ }\r
+ if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
+ {\r
+ rightreleased = true;\r
+ }\r
+ if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
+ {\r
+ /*dstream<<"event.MouseInput.Wheel="\r
+ <<event.MouseInput.Wheel<<std::endl;*/\r
+ if(event.MouseInput.Wheel < 0)\r
+ {\r
+ if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
+ g_selected_item++;\r
+ else\r
+ g_selected_item = 0;\r
+ }\r
+ else if(event.MouseInput.Wheel > 0)\r
+ {\r
+ if(g_selected_item > 0)\r
+ g_selected_item--;\r
+ else\r
+ g_selected_item = PLAYER_INVENTORY_SIZE-1;\r
+ }\r
}\r
}\r
}\r
return keyIsDown[keyCode];\r
}\r
\r
- MyEventReceiver()\r
+ void clearInput()\r
{\r
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
keyIsDown[i] = false;\r
+ \r
leftclicked = false;\r
rightclicked = false;\r
leftreleased = false;\r
right_active = false;\r
}\r
\r
+ MyEventReceiver()\r
+ {\r
+ clearInput();\r
+ }\r
+\r
bool leftclicked;\r
bool rightclicked;\r
bool leftreleased;\r
bool keyIsDown[KEY_KEY_CODES_COUNT];\r
//s32 mouseX;\r
//s32 mouseY;\r
+ IrrlichtDevice *m_device;\r
};\r
\r
class InputHandler\r
\r
InputHandler *g_input = NULL;\r
\r
-void focusGame()\r
-{\r
- g_input->clear();\r
- g_game_focused = true;\r
-}\r
-\r
-void unFocusGame()\r
-{\r
- g_game_focused = false;\r
-}\r
-\r
class RealInputHandler : public InputHandler\r
{\r
public:\r
\r
virtual bool getLeftClicked()\r
{\r
- if(g_game_focused == false)\r
- return false;\r
return m_receiver->leftclicked;\r
}\r
virtual bool getRightClicked()\r
{\r
- if(g_game_focused == false)\r
- return false;\r
return m_receiver->rightclicked;\r
}\r
virtual void resetLeftClicked()\r
\r
virtual bool getLeftReleased()\r
{\r
- if(g_game_focused == false)\r
- return false;\r
return m_receiver->leftreleased;\r
}\r
virtual bool getRightReleased()\r
{\r
- if(g_game_focused == false)\r
- return false;\r
return m_receiver->rightreleased;\r
}\r
virtual void resetLeftReleased()\r
\r
s32 Rand(s32 min, s32 max)\r
{\r
- return (rand()%(max-min+1))+min;\r
+ return (myrand()%(max-min+1))+min;\r
}\r
private:\r
bool keydown[KEY_KEY_CODES_COUNT];\r
bool rightclicked;\r
};\r
\r
-void updateViewingRange(f32 frametime, Client *client)\r
+void updateViewingRange(f32 frametime_in, Client *client)\r
{\r
- // Range_all messes up frametime_avg\r
- if(g_viewing_range_all == true)\r
+ if(draw_control.range_all == true)\r
return;\r
-\r
- float wanted_fps = g_settings.getFloat("wanted_fps");\r
\r
- // Initialize to the target value\r
- static float frametime_avg = 1.0/wanted_fps;\r
- //frametime_avg = frametime_avg * 0.9 + frametime * 0.1;\r
- frametime_avg = frametime_avg * 0.7 + frametime * 0.3;\r
+ static f32 added_frametime = 0;\r
+ static s16 added_frames = 0;\r
\r
+ added_frametime += frametime_in;\r
+ added_frames += 1;\r
+\r
+ // Actually this counter kind of sucks because frametime is busytime\r
static f32 counter = 0;\r
- if(counter > 0){\r
- counter -= frametime;\r
+ counter -= frametime_in;\r
+ if(counter > 0)\r
return;\r
- }\r
- //counter = 1.0; //seconds\r
- counter = 0.5; //seconds\r
-\r
- //float freetime_ratio = 0.2;\r
- //float freetime_ratio = 0.4;\r
- float freetime_ratio = FREETIME_RATIO;\r
-\r
- float frametime_wanted = (1.0/(wanted_fps/(1.0-freetime_ratio)));\r
+ //counter = 0.1;\r
+ counter = 0.2;\r
\r
- float fraction = sqrt(frametime_avg / frametime_wanted);\r
-\r
- /*float fraction = sqrt(frametime_avg / frametime_wanted) / 2.0\r
- + frametime_avg / frametime_wanted / 2.0;*/\r
+ /*dstream<<__FUNCTION_NAME\r
+ <<": Collected "<<added_frames<<" frames, total of "\r
+ <<added_frametime<<"s."<<std::endl;*/\r
\r
- //float fraction = frametime_avg / frametime_wanted;\r
-\r
- static bool fraction_is_good = false;\r
+ /*dstream<<"draw_control.blocks_drawn="\r
+ <<draw_control.blocks_drawn\r
+ <<", draw_control.blocks_would_have_drawn="\r
+ <<draw_control.blocks_would_have_drawn\r
+ <<std::endl;*/\r
\r
- //float fraction_good_threshold = 0.1;\r
- //float fraction_bad_threshold = 0.25;\r
- float fraction_good_threshold = 0.075;\r
- float fraction_bad_threshold = 0.125;\r
- float fraction_limit;\r
- // Use high limit if fraction is good AND the fraction would\r
- // lower the range. We want to keep the range fairly high.\r
- if(fraction_is_good && fraction > 1.0)\r
- fraction_limit = fraction_bad_threshold;\r
- else\r
- fraction_limit = fraction_good_threshold;\r
-\r
- if(fabs(fraction - 1.0) < fraction_limit)\r
+ float range_min = g_settings.getS16("viewing_range_nodes_min");\r
+ float range_max = g_settings.getS16("viewing_range_nodes_max");\r
+ \r
+ draw_control.wanted_min_range = range_min;\r
+ draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;\r
+ \r
+ float block_draw_ratio = 1.0;\r
+ if(draw_control.blocks_would_have_drawn != 0)\r
{\r
- fraction_is_good = true;\r
- return;\r
+ block_draw_ratio = (float)draw_control.blocks_drawn\r
+ / (float)draw_control.blocks_would_have_drawn;\r
}\r
- else\r
+\r
+ // Calculate the average frametime in the case that all wanted\r
+ // blocks had been drawn\r
+ f32 frametime = added_frametime / added_frames / block_draw_ratio;\r
+ \r
+ added_frametime = 0.0;\r
+ added_frames = 0;\r
+ \r
+ float wanted_fps = g_settings.getFloat("wanted_fps");\r
+ float wanted_frametime = 1.0 / wanted_fps;\r
+ \r
+ f32 wanted_frametime_change = wanted_frametime - frametime;\r
+ //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;\r
+ \r
+ // If needed frametime change is very small, just return\r
+ if(fabs(wanted_frametime_change) < wanted_frametime*0.2)\r
{\r
- fraction_is_good = false;\r
+ //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
+ return;\r
}\r
\r
- //dstream<<"frametime_avg="<<frametime_avg<<std::endl;\r
- //dstream<<"frametime_wanted="<<frametime_wanted<<std::endl;\r
- /*dstream<<"fetching="<<client->isFetchingBlocks()\r
- <<" faction = "<<fraction<<std::endl;*/\r
+ float range = draw_control.wanted_range;\r
+ float new_range = range;\r
\r
- JMutexAutoLock lock(g_range_mutex);\r
+ static s16 range_old = 0;\r
+ static f32 frametime_old = 0;\r
\r
- s16 viewing_range_nodes_min = g_settings.getS16("viewing_range_nodes_min");\r
- s16 viewing_range_nodes_max = g_settings.getS16("viewing_range_nodes_max");\r
+ float d_range = range - range_old;\r
+ f32 d_frametime = frametime - frametime_old;\r
+ // A sane default of 30ms per 50 nodes of range\r
+ static f32 time_per_range = 30. / 50;\r
+ if(d_range != 0)\r
+ {\r
+ time_per_range = d_frametime / d_range;\r
+ }\r
+ \r
+ // The minimum allowed calculated frametime-range derivative:\r
+ // Practically this sets the maximum speed of changing the range.\r
+ // The lower this value, the higher the maximum changing speed.\r
+ // A low value here results in wobbly range (0.001)\r
+ // A high value here results in slow changing range (0.0025)\r
+ // SUGG: This could be dynamically adjusted so that when\r
+ // the camera is turning, this is lower\r
+ //float min_time_per_range = 0.0015;\r
+ float min_time_per_range = 0.0010;\r
+ //float min_time_per_range = 0.05 / range;\r
+ if(time_per_range < min_time_per_range)\r
+ {\r
+ time_per_range = min_time_per_range;\r
+ //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;\r
+ }\r
+ else\r
+ {\r
+ //dstream<<"time_per_range="<<time_per_range<<std::endl;\r
+ }\r
\r
- s16 n = (float)g_viewing_range_nodes / fraction;\r
- if(n < viewing_range_nodes_min)\r
- n = viewing_range_nodes_min;\r
- if(n > viewing_range_nodes_max)\r
- n = viewing_range_nodes_max;\r
+ f32 wanted_range_change = wanted_frametime_change / time_per_range;\r
+ // Dampen the change a bit to kill oscillations\r
+ //wanted_range_change *= 0.9;\r
+ //wanted_range_change *= 0.75;\r
+ wanted_range_change *= 0.5;\r
+ //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;\r
\r
- bool can_change = true;\r
+ // If needed range change is very small, just return\r
+ if(fabs(wanted_range_change) < 0.001)\r
+ {\r
+ //dstream<<"ignoring small wanted_range_change"<<std::endl;\r
+ return;\r
+ }\r
\r
- if(client->isFetchingBlocks() == true && n > g_viewing_range_nodes)\r
- can_change = false;\r
+ new_range += wanted_range_change;\r
+ //dstream<<"new_range="<<new_range/*<<std::endl*/;\r
\r
- if(can_change)\r
- g_viewing_range_nodes = n;\r
+ //float new_range_unclamped = new_range;\r
+ if(new_range < range_min)\r
+ new_range = range_min;\r
+ if(new_range > range_max)\r
+ new_range = range_max;\r
+ \r
+ /*if(new_range != new_range_unclamped)\r
+ dstream<<", clamped to "<<new_range<<std::endl;\r
+ else\r
+ dstream<<std::endl;*/\r
+\r
+ draw_control.wanted_range = new_range;\r
\r
- /*dstream<<"g_viewing_range_nodes = "\r
- <<g_viewing_range_nodes<<std::endl;*/\r
+ range_old = new_range;\r
+ frametime_old = frametime;\r
}\r
\r
class GUIQuickInventory : public IEventReceiver\r
\r
start = m_selection - m_itemcount / 2;\r
\r
+ InventoryList *mainlist = m_inventory->getList("main");\r
+\r
for(s32 i=0; i<m_itemcount; i++)\r
{\r
s32 j = i + start;\r
\r
- if(j > (s32)m_inventory->getSize() - 1)\r
- j -= m_inventory->getSize();\r
+ if(j > (s32)mainlist->getSize() - 1)\r
+ j -= mainlist->getSize();\r
if(j < 0)\r
- j += m_inventory->getSize();\r
+ j += mainlist->getSize();\r
\r
- InventoryItem *item = m_inventory->getItem(j);\r
+ InventoryItem *item = mainlist->getItem(j);\r
// Null items\r
if(item == NULL)\r
{\r
s32 m_selection;\r
};\r
\r
+// Chat data\r
+struct ChatLine\r
+{\r
+ ChatLine():\r
+ age(0.0)\r
+ {\r
+ }\r
+ ChatLine(const std::wstring &a_text):\r
+ age(0.0),\r
+ text(a_text)\r
+ {\r
+ }\r
+ float age;\r
+ std::wstring text;\r
+};\r
+\r
int main(int argc, char *argv[])\r
{\r
/*\r
\r
DSTACK(__FUNCTION_NAME);\r
\r
+ porting::initializePaths();\r
+ // Create user data directory\r
+ fs::CreateDir(porting::path_userdata);\r
+\r
+ initializeMaterialProperties();\r
+\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
try\r
{\r
\r
allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\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
\r
Settings cmd_args;\r
\r
// Initialize default settings\r
set_default_settings();\r
\r
- // Print startup message\r
- dstream<<DTIME<<"minetest-c55"\r
- " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
- <<", ENABLE_TESTS="<<ENABLE_TESTS\r
- <<std::endl;\r
- \r
// Set locale. This is for forcing '.' as the decimal point.\r
std::locale::global(std::locale("C"));\r
// This enables printing all characters in bitmap font\r
}\r
else\r
{\r
- const char *filenames[2] =\r
- {\r
- "../minetest.conf",\r
- "../../minetest.conf"\r
- };\r
+ core::array<std::string> filenames;\r
+ filenames.push_back(porting::path_userdata + "/minetest.conf");\r
+#ifdef RUN_IN_PLACE\r
+ filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
+#endif\r
\r
- for(u32 i=0; i<2; i++)\r
+ for(u32 i=0; i<filenames.size(); i++)\r
{\r
- bool r = g_settings.readConfigFile(filenames[i]);\r
+ bool r = g_settings.readConfigFile(filenames[i].c_str());\r
if(r)\r
{\r
configpath = filenames[i];\r
\r
// Initialize random seed\r
srand(time(0));\r
+ mysrand(time(0));\r
\r
/*\r
Run unit tests\r
run_tests();\r
}\r
\r
- /*\r
- Global range mutex\r
- */\r
- g_range_mutex.Init();\r
- assert(g_range_mutex.IsInitialized());\r
-\r
// Read map parameters from settings\r
\r
HMParams hm_params;\r
std::cout<<"-> "<<port<<std::endl;\r
}\r
\r
+ //Map directory\r
+ std::string map_dir = porting::path_userdata+"/map";\r
+ if(cmd_args.exists("map-dir"))\r
+ map_dir = cmd_args.get("map-dir");\r
+ else if(g_settings.exists("map-dir"))\r
+ map_dir = g_settings.get("map-dir");\r
+ \r
if(cmd_args.getFlag("server"))\r
{\r
DSTACK("Dedicated server branch");\r
std::cout<<"========================"<<std::endl;\r
std::cout<<std::endl;\r
\r
- Server server("../map", hm_params, map_params);\r
+ Server server(map_dir, hm_params, map_params);\r
server.start(port);\r
\r
for(;;)\r
{\r
snprintf(connect_name, 100, "%s", cmd_args.get("address").c_str());\r
}\r
- else if(g_settings.get("address") != "" && is_yes(g_settings.get("host_game")) == false)\r
- {\r
- std::cout<<g_settings.get("address")<<std::endl;\r
- snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
- }\r
- else\r
+ else if(is_yes(g_settings.get("host_game")) == false)\r
{\r
- std::cout<<"Address to connect to [empty = host a game]: ";\r
- std::cin.getline(connect_name, 100);\r
+ if(g_settings.get("address") != "")\r
+ {\r
+ std::cout<<g_settings.get("address")<<std::endl;\r
+ snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
+ }\r
+ else\r
+ {\r
+ std::cout<<"Address to connect to [empty = host a game]: ";\r
+ std::cin.getline(connect_name, 100);\r
+ }\r
}\r
\r
if(connect_name[0] == 0){\r
if (device == 0)\r
return 1; // could not create selected driver.\r
\r
+ g_device = device;\r
g_irrlicht = new IrrlichtWrapper(device);\r
\r
//g_device = device;\r
/*\r
This changes the minimum allowed number of vertices in a VBO\r
*/\r
- //driver->setMinHardwareBufferVertexCount(1);\r
+ //driver->setMinHardwareBufferVertexCount(50);\r
\r
scene::ISceneManager* smgr = device->getSceneManager();\r
\r
guienv = device->getGUIEnvironment();\r
gui::IGUISkin* skin = guienv->getSkin();\r
- gui::IGUIFont* font = guienv->getFont("../data/fontlucida.png");\r
+ gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());\r
if(font)\r
skin->setFont(font);\r
+ \r
+ u32 text_height = font->getDimension(L"Hello, world!").Height;\r
+ dstream<<"text_height="<<text_height<<std::endl;\r
+\r
//skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
//skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
\r
const wchar_t *text = L"Loading and connecting...";\r
core::vector2d<s32> center(screenW/2, screenH/2);\r
- core::dimension2d<u32> textd = font->getDimension(text);\r
- std::cout<<DTIME<<"Text w="<<textd.Width<<" h="<<textd.Height<<std::endl;\r
- // Have to add a bit to disable the text from word wrapping\r
- //core::vector2d<s32> textsize(textd.Width+4, textd.Height);\r
- core::vector2d<s32> textsize(300, textd.Height);\r
+ core::vector2d<s32> textsize(300, text_height);\r
core::rect<s32> textrect(center - textsize/2, center + textsize/2);\r
\r
gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(\r
driver->endScene();\r
\r
/*\r
- Preload some random textures that are used in threads\r
+ Preload some textures\r
*/\r
-#if 0\r
- g_texturecache.set("torch", driver->getTexture("../data/torch.png"));\r
- g_texturecache.set("torch_on_floor", driver->getTexture("../data/torch_on_floor.png"));\r
- g_texturecache.set("torch_on_ceiling", driver->getTexture("../data/torch_on_ceiling.png"));\r
- g_texturecache.set("crack", driver->getTexture("../data/crack.png"));\r
- \r
- /*\r
- Load tile textures\r
- */\r
- for(s32 i=0; i<TILES_COUNT; i++)\r
- {\r
- if(g_tile_texture_names[i] == NULL)\r
- continue;\r
- std::string name = g_tile_texture_names[i];\r
- std::string filename;\r
- filename += "../data/";\r
- filename += name;\r
- filename += ".png";\r
- g_texturecache.set(name, driver->getTexture(filename.c_str()));\r
- }\r
\r
-#endif\r
-\r
- //tile_materials_preload(g_texturecache);\r
+ init_content_inventory_texture_paths();\r
+ init_tile_texture_paths();\r
tile_materials_preload(g_irrlicht);\r
- //tile_materials_init();\r
\r
/*\r
Make a scope here for the client so that it gets removed\r
*/\r
SharedPtr<Server> server;\r
if(hosting){\r
- server = new Server("../map", hm_params, map_params);\r
+ server = new Server(map_dir, hm_params, map_params);\r
server->start(port);\r
}\r
\r
Create client\r
*/\r
\r
- Client client(device, playername,\r
- g_range_mutex,\r
- g_viewing_range_nodes,\r
- g_viewing_range_all);\r
+ Client client(device, playername, draw_control);\r
+ \r
+ g_client = &client;\r
\r
Address connect_address(0,0,0,0, port);\r
try{\r
*/\r
/*scene::ISceneNode* skybox;\r
skybox = smgr->addSkyBoxSceneNode(\r
- driver->getTexture("../data/skybox2.png"),\r
- driver->getTexture("../data/skybox3.png"),\r
- driver->getTexture("../data/skybox1.png"),\r
- driver->getTexture("../data/skybox1.png"),\r
- driver->getTexture("../data/skybox1.png"),\r
- driver->getTexture("../data/skybox1.png"));*/\r
+ driver->getTexture(porting::getDataPath("skybox2.png").c_str()),\r
+ driver->getTexture(porting::getDataPath("skybox3.png").c_str()),\r
+ driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+ driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+ driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
+ driver->getTexture(porting::getDataPath("skybox1.png").c_str()));*/\r
\r
/*\r
Create the camera node\r
/*\r
Add some gui stuff\r
*/\r
- \r
- // This is a copy of the inventory that the client's environment has\r
- Inventory local_inventory(PLAYER_INVENTORY_SIZE);\r
- \r
+\r
GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
(guienv, NULL, v2s32(10, 70), 5, &local_inventory);\r
\r
custom elements directly on the screen.\r
Otherwise they won't be automatically drawn.\r
*/\r
- gui::IGUIStaticText *root = guienv->addStaticText(L"",\r
+ guiroot = guienv->addStaticText(L"",\r
core::rect<s32>(0, 0, 10000, 10000));\r
\r
- // Pause menu\r
- pauseMenu = new GUIPauseMenu(guienv, root, -1, device);\r
+ // Test the text input system\r
+ /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
+ NULL))->drop();*/\r
+ /*GUIMessageMenu *menu =\r
+ new GUIMessageMenu(guienv, guiroot, -1, \r
+ &g_active_menu_count,\r
+ L"Asd");\r
+ menu->drop();*/\r
\r
- // Inventory menu\r
- inventoryMenu = new GUIInventoryMenu(guienv, root, -1, &local_inventory);\r
-\r
- pauseMenu->launch();\r
- //inventoryMenu->launch();\r
+ // Launch pause menu\r
+ (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
+ &g_active_menu_count))->drop();\r
\r
// First line of debug text\r
gui::IGUIStaticText *guitext = guienv->addStaticText(\r
core::rect<s32>(100, 70, 100+400, 70+(textsize.Y+5)),\r
false, false);\r
\r
+ // Chat text\r
+ gui::IGUIStaticText *chat_guitext = guienv->addStaticText(\r
+ L"Chat here\nOther line\nOther line\nOther line\nOther line",\r
+ core::rect<s32>(70, 60, 795, 150),\r
+ false, true);\r
+ chat_guitext->setBackgroundColor(video::SColor(96,0,0,0));\r
+ core::list<ChatLine> chat_lines;\r
+ \r
/*\r
Some statistics are collected in these\r
*/\r
u32 beginscenetime = 0;\r
u32 scenetime = 0;\r
u32 endscenetime = 0;\r
-\r
- /*\r
- Text input system\r
- */\r
- \r
- struct TextDest\r
- {\r
- virtual void sendText(std::string text) = 0;\r
- };\r
\r
- struct TextDestSign : public TextDest\r
- {\r
- TextDestSign(v3s16 blockpos, s16 id, Client *client)\r
- {\r
- m_blockpos = blockpos;\r
- m_id = id;\r
- m_client = client;\r
- }\r
- void sendText(std::string text)\r
- {\r
- dstream<<"Changing text of a sign object: "\r
- <<text<<std::endl;\r
- m_client->sendSignText(m_blockpos, m_id, text);\r
- }\r
-\r
- v3s16 m_blockpos;\r
- s16 m_id;\r
- Client *m_client;\r
- };\r
-\r
- TextDest *textbuf_dest = NULL;\r
- \r
- //gui::IGUIWindow* input_window = NULL;\r
- gui::IGUIStaticText* input_guitext = NULL;\r
+ // A test\r
+ //throw con::PeerNotFoundException("lol");\r
\r
/*\r
Main loop\r
bool first_loop_after_window_activation = true;\r
\r
// Time is in milliseconds\r
- // NOTE: getRealTime() without run()s causes strange problems in wine\r
- // NOTE: Have to call run() between calls of this to update the timer\r
+ // NOTE: getRealTime() causes strange problems in wine (imprecision?)\r
+ // NOTE: So we have to use getTime() and call run()s between them\r
u32 lasttime = device->getTimer()->getTime();\r
\r
while(device->run())\r
v2u32 screensize = driver->getScreenSize();\r
core::vector2d<s32> displaycenter(screensize.X/2,screensize.Y/2);\r
\r
- pauseMenu->resizeGui();\r
- inventoryMenu->resizeGui();\r
-\r
// Hilight boxes collected during the loop and displayed\r
core::list< core::aabbox3d<f32> > hilightboxes;\r
\r
Viewing range\r
*/\r
\r
- //updateViewingRange(dtime, &client);\r
updateViewingRange(busytime, &client);\r
\r
/*\r
*/\r
g_input->step(dtime);\r
\r
- /*\r
- Special keys\r
- */\r
- /*if(g_esc_pressed)\r
- {\r
- break;\r
- }*/\r
- /*if(g_i_pressed)\r
- {\r
- inventoryMenu->setVisible(true);\r
- g_i_pressed = false;\r
- }*/\r
-\r
/*\r
Player speed control\r
*/\r
\r
- if(g_game_focused)\r
{\r
/*bool a_up,\r
bool a_down,\r
);\r
client.setPlayerControl(control);\r
}\r
- else\r
- {\r
- // Set every key to inactive\r
- PlayerControl control;\r
- client.setPlayerControl(control);\r
- }\r
\r
- //timer1.stop();\r
/*\r
Process environment\r
*/\r
Mouse and camera control\r
*/\r
\r
- if((device->isWindowActive()\r
- && g_game_focused\r
- && !pauseMenu->isVisible()\r
- && !inventoryMenu->isVisible()\r
- )\r
- || random_input)\r
+ if((device->isWindowActive() && noMenuActive()) || random_input)\r
{\r
if(!random_input)\r
device->getCursorControl()->setVisible(false);\r
v3f camera_direction = v3f(0,0,1);\r
camera_direction.rotateYZBy(camera_pitch);\r
camera_direction.rotateXZBy(camera_yaw);\r
-\r
+ \r
+ // This is at the height of the eyes of the current figure\r
v3f camera_position =\r
player_position + v3f(0, BS+BS/2, 0);\r
+ // This is more like in minecraft\r
+ /*v3f camera_position =\r
+ player_position + v3f(0, BS+BS*0.65, 0);*/\r
\r
camera->setPosition(camera_position);\r
// *100.0 helps in large map coordinates\r
MapBlockObject *selected_object = client.getSelectedObject\r
(d*BS, camera_position, shootline);\r
\r
+ /*\r
+ If it's pointing to a MapBlockObject\r
+ */\r
+\r
if(selected_object != NULL)\r
{\r
//dstream<<"Client returned selected_object != NULL"<<std::endl;\r
{\r
dstream<<"Sign object right-clicked"<<std::endl;\r
\r
- unFocusGame();\r
+ if(random_input == false)\r
+ {\r
+ // Get a new text for it\r
\r
- input_guitext = guienv->addStaticText(L"",\r
- core::rect<s32>(150,100,350,120),\r
- true, // border?\r
- false, // wordwrap?\r
- NULL);\r
+ TextDest *dest = new TextDestSign(\r
+ selected_object->getBlock()->getPos(),\r
+ selected_object->getId(),\r
+ &client);\r
\r
- input_guitext->setDrawBackground(true);\r
+ SignObject *sign_object = (SignObject*)selected_object;\r
\r
- if(random_input)\r
- {\r
- g_text_buffer = L"ASD LOL 8)";\r
- g_text_buffer_accepted = true;\r
- }\r
- else\r
- {\r
- g_text_buffer = L"";\r
- g_text_buffer_accepted = false;\r
- }\r
+ std::wstring wtext =\r
+ narrow_to_wide(sign_object->getText());\r
\r
- textbuf_dest = new TextDestSign(\r
- selected_object->getBlock()->getPos(),\r
- selected_object->getId(),\r
- &client);\r
+ (new GUITextInputMenu(guienv, guiroot, -1,\r
+ &g_active_menu_count, dest,\r
+ wtext))->drop();\r
+ }\r
}\r
/*\r
Otherwise pass the event to the server as-is\r
} // regular block\r
} // for coords\r
\r
+ static float nodig_delay_counter = 0.0;\r
+\r
if(nodefound)\r
{\r
static v3s16 nodepos_old(-32768,-32768,-32768);\r
\r
static float dig_time = 0.0;\r
-\r
- if(nodepos != nodepos_old)\r
- {\r
- std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
- <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
-\r
- if(nodepos_old != v3s16(-32768,-32768,-32768))\r
- {\r
- client.clearTempMod(nodepos_old);\r
- dig_time = 0.0;\r
- }\r
- }\r
+ static u16 dig_index = 0;\r
\r
hilightboxes.push_back(nodefacebox);\r
\r
client.clearTempMod(nodepos);\r
dig_time = 0.0;\r
}\r
- if(g_input->getLeftClicked() ||\r
- (g_input->getLeftState() && nodepos != nodepos_old))\r
- {\r
- std::cout<<DTIME<<"Ground left-clicked"<<std::endl;\r
- client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
- }\r
- if(g_input->getLeftClicked())\r
+ \r
+ if(nodig_delay_counter > 0.0)\r
{\r
- client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
+ nodig_delay_counter -= dtime;\r
}\r
- if(g_input->getLeftState())\r
+ else\r
{\r
- dig_time += dtime;\r
- \r
- float dig_time_complete = 0.5;\r
- MapNode n = client.getNode(nodepos);\r
- if(n.d == CONTENT_STONE)\r
- dig_time_complete = 1.5;\r
+ if(nodepos != nodepos_old)\r
+ {\r
+ std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
+ <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
+\r
+ if(nodepos_old != v3s16(-32768,-32768,-32768))\r
+ {\r
+ client.clearTempMod(nodepos_old);\r
+ dig_time = 0.0;\r
+ }\r
+ }\r
\r
- u16 dig_index = (u16)(3.99*dig_time/dig_time_complete);\r
- if(dig_time > 0.125)\r
+ if(g_input->getLeftClicked() ||\r
+ (g_input->getLeftState() && nodepos != nodepos_old))\r
+ {\r
+ dstream<<DTIME<<"Started digging"<<std::endl;\r
+ client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
+ }\r
+ if(g_input->getLeftClicked())\r
+ {\r
+ client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
+ }\r
+ if(g_input->getLeftState())\r
{\r
- //dstream<<"dig_index="<<dig_index<<std::endl;\r
- client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
+ MapNode n = client.getNode(nodepos);\r
+ \r
+ // Get tool name. Default is "" = bare hands\r
+ std::string toolname = "";\r
+ InventoryList *mlist = local_inventory.getList("main");\r
+ if(mlist != NULL)\r
+ {\r
+ InventoryItem *item = mlist->getItem(g_selected_item);\r
+ if(item && (std::string)item->getName() == "ToolItem")\r
+ {\r
+ ToolItem *titem = (ToolItem*)item;\r
+ toolname = titem->getToolName();\r
+ }\r
+ }\r
+\r
+ // Get digging properties for material and tool\r
+ u8 material = n.d;\r
+ DiggingProperties prop =\r
+ getDiggingProperties(material, toolname);\r
+ \r
+ float dig_time_complete = 0.0;\r
+\r
+ if(prop.diggable == false)\r
+ {\r
+ /*dstream<<"Material "<<(int)material\r
+ <<" not diggable with \""\r
+ <<toolname<<"\""<<std::endl;*/\r
+ // I guess nobody will wait for this long\r
+ dig_time_complete = 10000000.0;\r
+ }\r
+ else\r
+ {\r
+ dig_time_complete = prop.time;\r
+ }\r
+ \r
+ if(dig_time_complete >= 0.001)\r
+ {\r
+ dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
+ * dig_time/dig_time_complete);\r
+ }\r
+ // This is for torches\r
+ else\r
+ {\r
+ dig_index = CRACK_ANIMATION_LENGTH;\r
+ }\r
+\r
+ if(dig_index < CRACK_ANIMATION_LENGTH)\r
+ {\r
+ //dstream<<"dig_index="<<dig_index<<std::endl;\r
+ client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
+ }\r
+ else\r
+ {\r
+ dstream<<DTIME<<"Digging completed"<<std::endl;\r
+ client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
+ client.clearTempMod(nodepos);\r
+ client.removeNode(nodepos);\r
+\r
+ dig_time = 0;\r
+\r
+ nodig_delay_counter = dig_time_complete\r
+ / (float)CRACK_ANIMATION_LENGTH;\r
+\r
+ // We don't want a corresponding delay to\r
+ // very time consuming nodes\r
+ if(nodig_delay_counter > 0.5)\r
+ {\r
+ nodig_delay_counter = 0.5;\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
+ if(nodig_delay_counter < mindelay)\r
+ {\r
+ nodig_delay_counter = mindelay;\r
+ }\r
+ }\r
+\r
+ dig_time += dtime;\r
}\r
}\r
\r
\r
if(g_input->getLeftReleased())\r
{\r
- std::cout<<DTIME<<"Left released"<<std::endl;\r
+ std::cout<<DTIME<<"Left button released (stopped digging)"\r
+ <<std::endl;\r
client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);\r
}\r
if(g_input->getRightReleased())\r
camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
\r
u32 daynight_ratio = client.getDayNightRatio();\r
- video::SColor bgcolor = video::SColor(\r
+ /*video::SColor bgcolor = video::SColor(\r
255,\r
skycolor.getRed() * daynight_ratio / 1000,\r
skycolor.getGreen() * daynight_ratio / 1000,\r
- skycolor.getBlue() * daynight_ratio / 1000);\r
+ skycolor.getBlue() * daynight_ratio / 1000);*/\r
+\r
+ u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);\r
+ video::SColor bgcolor = video::SColor(\r
+ 255,\r
+ skycolor.getRed() * l / 255,\r
+ skycolor.getGreen() * l / 255,\r
+ skycolor.getBlue() * l / 255);\r
\r
/*\r
Fog\r
\r
if(g_settings.getBool("enable_fog") == true)\r
{\r
- f32 range = g_viewing_range_nodes * BS;\r
- if(g_viewing_range_all)\r
+ f32 range = draw_control.wanted_range * BS;\r
+ if(draw_control.range_all)\r
range = 100000*BS;\r
\r
driver->setFog(\r
wchar_t temptext[150];\r
\r
static float drawtime_avg = 0;\r
- drawtime_avg = drawtime_avg * 0.98 + (float)drawtime*0.02;\r
+ drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;\r
static float beginscenetime_avg = 0;\r
- beginscenetime_avg = beginscenetime_avg * 0.98 + (float)beginscenetime*0.02;\r
+ beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;\r
static float scenetime_avg = 0;\r
- scenetime_avg = scenetime_avg * 0.98 + (float)scenetime*0.02;\r
+ scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;\r
static float endscenetime_avg = 0;\r
- endscenetime_avg = endscenetime_avg * 0.98 + (float)endscenetime*0.02;\r
+ endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;\r
\r
swprintf(temptext, 150, L"Minetest-c55 ("\r
L"F: item=%i"\r
L")"\r
L" drawtime=%.0f, beginscenetime=%.0f, scenetime=%.0f, endscenetime=%.0f",\r
g_selected_item,\r
- g_viewing_range_all,\r
+ draw_control.range_all,\r
drawtime_avg,\r
beginscenetime_avg,\r
scenetime_avg,\r
swprintf(temptext, 150,\r
L"(% .1f, % .1f, % .1f)"\r
L" (% .3f < btime_jitter < % .3f"\r
- L", dtime_jitter = % .1f %%)",\r
+ L", dtime_jitter = % .1f %%"\r
+ L", v_range = %.1f)",\r
player_position.X/BS,\r
player_position.Y/BS,\r
player_position.Z/BS,\r
busytime_jitter1_min_sample,\r
busytime_jitter1_max_sample,\r
- dtime_jitter1_max_fraction * 100.0\r
+ dtime_jitter1_max_fraction * 100.0,\r
+ draw_control.wanted_range\r
);\r
\r
guitext2->setText(temptext);\r
}\r
\r
{\r
- /*wchar_t temptext[100];\r
- swprintf(temptext, 100,\r
- SWPRINTF_CHARSTRING,\r
- infotext.substr(0,99).c_str()\r
- );\r
+ guitext_info->setText(infotext.c_str());\r
+ }\r
+ \r
+ /*\r
+ Get chat messages from client\r
+ */\r
+ {\r
+ // Get new messages\r
+ std::wstring message;\r
+ while(client.getChatMessage(message))\r
+ {\r
+ chat_lines.push_back(ChatLine(message));\r
+ /*if(chat_lines.size() > 6)\r
+ {\r
+ core::list<ChatLine>::Iterator\r
+ i = chat_lines.begin();\r
+ chat_lines.erase(i);\r
+ }*/\r
+ }\r
+ // Append them to form the whole static text and throw\r
+ // it to the gui element\r
+ std::wstring whole;\r
+ // This will correspond to the line number counted from\r
+ // top to bottom, from size-1 to 0\r
+ s16 line_number = chat_lines.size();\r
+ // Count of messages to be removed from the top\r
+ u16 to_be_removed_count = 0;\r
+ for(core::list<ChatLine>::Iterator\r
+ i = chat_lines.begin();\r
+ i != chat_lines.end(); i++)\r
+ {\r
+ // After this, line number is valid for this loop\r
+ line_number--;\r
+ // Increment age\r
+ (*i).age += dtime;\r
+ /*\r
+ This results in a maximum age of 60*6 to the\r
+ lowermost line and a maximum of 6 lines\r
+ */\r
+ float allowed_age = (6-line_number) * 60.0;\r
\r
- guitext_info->setText(temptext);*/\r
+ if((*i).age > allowed_age)\r
+ {\r
+ to_be_removed_count++;\r
+ continue;\r
+ }\r
+ whole += (*i).text + L'\n';\r
+ }\r
+ for(u16 i=0; i<to_be_removed_count; i++)\r
+ {\r
+ core::list<ChatLine>::Iterator\r
+ it = chat_lines.begin();\r
+ chat_lines.erase(it);\r
+ }\r
+ chat_guitext->setText(whole.c_str());\r
+ // Update gui element size and position\r
+ core::rect<s32> rect(\r
+ 10,\r
+ screensize.Y - 10 - text_height*chat_lines.size(),\r
+ screensize.X - 10,\r
+ screensize.Y - 10\r
+ );\r
+ chat_guitext->setRelativePosition(rect);\r
\r
- guitext_info->setText(infotext.c_str());\r
+ if(chat_lines.size() == 0)\r
+ chat_guitext->setVisible(false);\r
+ else\r
+ chat_guitext->setVisible(true);\r
}\r
\r
/*\r
client.getLocalInventory(local_inventory);\r
quick_inventory->setSelection(g_selected_item);\r
quick_inventory->update();\r
- inventoryMenu->update();\r
- }\r
-\r
- if(input_guitext != NULL)\r
- {\r
- /*wchar_t temptext[100];\r
- swprintf(temptext, 100,\r
- SWPRINTF_CHARSTRING,\r
- g_text_buffer.substr(0,99).c_str()\r
- );*/\r
- input_guitext->setText(g_text_buffer.c_str());\r
}\r
-\r
+ \r
/*\r
- Text input stuff\r
+ Send actions returned by the inventory menu\r
*/\r
- if(input_guitext != NULL && g_text_buffer_accepted)\r
+ while(inventory_action_queue.size() != 0)\r
{\r
- input_guitext->remove();\r
- input_guitext = NULL;\r
- \r
- if(textbuf_dest != NULL)\r
- {\r
- std::string text = wide_to_narrow(g_text_buffer);\r
- dstream<<"Sending text: "<<text<<std::endl;\r
- textbuf_dest->sendText(text);\r
- delete textbuf_dest;\r
- textbuf_dest = NULL;\r
- }\r
+ InventoryAction *a = inventory_action_queue.pop_front();\r
\r
- focusGame();\r
+ client.sendInventoryAction(a);\r
+ // Eat it\r
+ delete a;\r
}\r
\r
- //guiupdatetimer.stop();\r
-\r
/*\r
Drawing begins\r
*/\r
{\r
//TimeTaker timer9("auxiliary drawings");\r
// 0ms\r
-\r
- driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
- displaycenter + core::vector2d<s32>(10,0),\r
- video::SColor(255,255,255,255));\r
- driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
- displaycenter + core::vector2d<s32>(0,10),\r
- video::SColor(255,255,255,255));\r
-\r
+ \r
//timer9.stop();\r
//TimeTaker //timer10("//timer10");\r
\r
driver->draw3DBox(*i, video::SColor(255,0,0,0));\r
}\r
\r
+ /*\r
+ Draw crosshair\r
+ */\r
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
+ displaycenter + core::vector2d<s32>(10,0),\r
+ video::SColor(255,255,255,255));\r
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
+ displaycenter + core::vector2d<s32>(0,10),\r
+ video::SColor(255,255,255,255));\r
+\r
}\r
\r
//timer10.stop();\r
catch(con::PeerNotFoundException &e)\r
{\r
dstream<<DTIME<<"Connection timed out."<<std::endl;\r
+ \r
+ /*if(g_device)\r
+ {\r
+ GUIMessageMenu *menu =\r
+ new GUIMessageMenu(guienv, guiroot, -1, \r
+ &g_active_menu_count,\r
+ L"Connection timed out");\r
+\r
+ video::IVideoDriver* driver = g_device->getVideoDriver();\r
+ \r
+ dstream<<"Created menu"<<std::endl;\r
+\r
+ while(g_device->run() && menu->getStatus() == false)\r
+ {\r
+ driver->beginScene(true, true, video::SColor(255,0,0,0));\r
+ guienv->drawAll();\r
+ driver->endScene();\r
+ }\r
+ \r
+ dstream<<"Dropping menu"<<std::endl;\r
+\r
+ menu->drop();\r
+ }*/\r
}\r
-#if CATCH_UNHANDLED_EXCEPTIONS\r
- /*\r
- This is what has to be done in every thread to get suitable debug info\r
- */\r
- catch(std::exception &e)\r
- {\r
- dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "\r
- <<e.what()<<std::endl;\r
- assert(0);\r
- }\r
-#endif\r
\r
+ END_DEBUG_EXCEPTION_HANDLER\r
+ \r
debugstreams_deinit();\r
\r
return 0;\r