#include "IMeshCache.h"
#include "client.h"
#include "server.h"
-#include "guiPauseMenu.h"
#include "guiPasswordChange.h"
#include "guiVolumeChange.h"
#include "guiFormSpecMenu.h"
#include "guiTextInputMenu.h"
-#include "guiDeathScreen.h"
#include "tool.h"
#include "guiChatConsole.h"
#include "config.h"
+#include "version.h"
#include "clouds.h"
#include "particles.h"
#include "camera.h"
-#include "farmesh.h"
#include "mapblock.h"
#include "settings.h"
#include "profiler.h"
#include <iomanip>
#include <list>
#include "util/directiontables.h"
+#include "util/pointedthing.h"
/*
Text input system
*/
-struct TextDestChat : public TextDest
-{
- TextDestChat(Client *client)
- {
- m_client = client;
- }
- void gotText(std::wstring text)
- {
- m_client->typeChatMessage(text);
- }
- void gotText(std::map<std::string, std::string> fields)
- {
- m_client->typeChatMessage(narrow_to_wide(fields["text"]));
- }
-
- Client *m_client;
-};
-
struct TextDestNodeMetadata : public TextDest
{
TextDestNodeMetadata(v3s16 p, Client *client)
m_client->sendInventoryFields(m_formname, fields);
}
- void setFormName(std::string formname) {
- m_formname = formname;
- }
-
Client *m_client;
- std::string m_formname;
};
-/* Respawn menu callback */
-
-class MainRespawnInitiator: public IRespawnInitiator
+struct LocalFormspecHandler : public TextDest
{
-public:
- MainRespawnInitiator(bool *active, Client *client):
- m_active(active), m_client(client)
- {
- *m_active = true;
+ LocalFormspecHandler();
+ LocalFormspecHandler(std::string formname) {
+ m_formname = formname;
}
- void respawn()
+
+ LocalFormspecHandler(std::string formname,Client *client) {
+ m_formname = formname;
+ m_client = client;
+ }
+
+ void gotText(std::wstring message) {
+ errorstream << "LocalFormspecHandler::gotText old style message received" << std::endl;
+ }
+
+ void gotText(std::map<std::string, std::string> fields)
{
- *m_active = false;
- m_client->sendRespawn();
+ if (m_formname == "MT_PAUSE_MENU") {
+ if (fields.find("btn_sound") != fields.end()) {
+ g_gamecallback->changeVolume();
+ return;
+ }
+
+ if (fields.find("btn_exit_menu") != fields.end()) {
+ g_gamecallback->disconnect();
+ return;
+ }
+
+ if (fields.find("btn_exit_os") != fields.end()) {
+ g_gamecallback->exitToOS();
+ return;
+ }
+
+ if (fields.find("btn_change_password") != fields.end()) {
+ g_gamecallback->changePassword();
+ return;
+ }
+
+ if (fields.find("quit") != fields.end()) {
+ return;
+ }
+
+ if (fields.find("btn_continue") != fields.end()) {
+ return;
+ }
+ }
+ if (m_formname == "MT_CHAT_MENU") {
+ if ((fields.find("btn_send") != fields.end()) ||
+ (fields.find("quit") != fields.end())) {
+ if (fields.find("f_text") != fields.end()) {
+ if (m_client != 0) {
+ m_client->typeChatMessage(narrow_to_wide(fields["f_text"]));
+ }
+ else {
+ errorstream << "LocalFormspecHandler::gotText received chat message but m_client is NULL" << std::endl;
+ }
+ }
+ return;
+ }
+ }
+
+ if (m_formname == "MT_DEATH_SCREEN") {
+ if ((fields.find("btn_respawn") != fields.end())) {
+ m_client->sendRespawn();
+ return;
+ }
+ }
+
+ errorstream << "LocalFormspecHandler::gotText unhandled >" << m_formname << "< event" << std::endl;
+ int i = 0;
+ for (std::map<std::string,std::string>::iterator iter = fields.begin();
+ iter != fields.end(); iter++) {
+ errorstream << "\t"<< i << ": " << iter->first << "=" << iter->second << std::endl;
+ i++;
+ }
}
-private:
- bool *m_active;
+
Client *m_client;
};
Client *m_client;
};
-class FormspecFormSource: public IFormSource
-{
-public:
- FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
- {
- m_formspec = formspec;
- m_game_formspec = game_formspec;
- }
-
- ~FormspecFormSource()
- {
- *m_game_formspec = 0;
- }
-
- void setForm(std::string formspec) {
- m_formspec = formspec;
- }
-
- std::string getForm()
- {
- return m_formspec;
- }
-
- std::string m_formspec;
- FormspecFormSource** m_game_formspec;
-};
-
/*
Check if a node is pointable
*/
Find what the player is pointing at
*/
PointedThing getPointedThing(Client *client, v3f player_position,
- v3f camera_direction, v3f camera_position,
- core::line3d<f32> shootline, f32 d,
- bool liquids_pointable,
- bool look_for_object,
- std::vector<aabb3f> &hilightboxes,
- ClientActiveObject *&selected_object)
+ v3f camera_direction, v3f camera_position, core::line3d<f32> shootline,
+ f32 d, bool liquids_pointable, bool look_for_object, v3s16 camera_offset,
+ std::vector<aabb3f> &hilightboxes, ClientActiveObject *&selected_object)
{
PointedThing result;
INodeDefManager *nodedef = client->getNodeDefManager();
ClientMap &map = client->getEnv().getClientMap();
+ f32 mindistance = BS * 1001;
+
// First try to find a pointed at active object
if(look_for_object)
{
v3f pos = selected_object->getPosition();
hilightboxes.push_back(aabb3f(
- selection_box->MinEdge + pos,
- selection_box->MaxEdge + pos));
+ selection_box->MinEdge + pos - intToFloat(camera_offset, BS),
+ selection_box->MaxEdge + pos - intToFloat(camera_offset, BS)));
}
+ mindistance = (selected_object->getPosition() - camera_position).getLength();
result.type = POINTEDTHING_OBJECT;
result.object_id = selected_object->getId();
- return result;
}
}
// That didn't work, try to find a pointed at node
- f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position, BS);
i2 != boxes.end(); i2++)
{
aabb3f box = *i2;
- box.MinEdge += npf + v3f(-d,-d,-d);
- box.MaxEdge += npf + v3f(d,d,d);
+ box.MinEdge += npf + v3f(-d,-d,-d) - intToFloat(camera_offset, BS);
+ box.MaxEdge += npf + v3f(d,d,d) - intToFloat(camera_offset, BS);
hilightboxes.push_back(box);
}
}
Additionally, a progressbar can be drawn when percent is set between 0 and 100.
*/
/*gui::IGUIStaticText **/
-void draw_load_screen(const std::wstring &text,
- IrrlichtDevice* device, gui::IGUIFont* font,
- float dtime=0 ,int percent=0, bool clouds=true)
+void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
+ gui::IGUIFont* font, float dtime=0 ,int percent=0, bool clouds=true)
{
video::IVideoDriver* driver = device->getVideoDriver();
v2u32 screensize = driver->getScreenSize();
/* Profiler display */
void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
- gui::IGUIFont *font, u32 text_height,
- u32 show_profiler, u32 show_profiler_max)
+ gui::IGUIFont *font, u32 text_height, u32 show_profiler,
+ u32 show_profiler_max)
{
if(show_profiler == 0)
{
services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
// Fog distance
- float fog_distance = *m_fog_range;
- if(*m_force_fog_off)
- fog_distance = 10000*BS;
+ float fog_distance = 10000*BS;
+ if(g_settings->getBool("enable_fog") && !*m_force_fog_off)
+ fog_distance = *m_fog_range;
services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
// Day-night ratio
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
float daynight_ratio_f = (float)daynight_ratio / 1000.0;
services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
+
+ u32 animation_timer = porting::getTimeMs() % 100000;
+ float animation_timer_f = (float)animation_timer / 100000.0;
+ services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1);
+ services->setVertexShaderConstant("animationTimer", &animation_timer_f, 1);
+
+ LocalPlayer* player = m_client->getEnv().getLocalPlayer();
+ v3f eye_position = player->getEyePosition();
+ services->setPixelShaderConstant("eyePosition", (irr::f32*)&eye_position, 3);
+ services->setVertexShaderConstant("eyePosition", (irr::f32*)&eye_position, 3);
+
+ // Uniform sampler layers
+ int layer0 = 0;
+ int layer1 = 1;
+ int layer2 = 2;
+ // before 1.8 there isn't a "integer interface", only float
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ services->setPixelShaderConstant("baseTexture" , (irr::f32*)&layer0, 1);
+ services->setPixelShaderConstant("normalTexture" , (irr::f32*)&layer1, 1);
+ services->setPixelShaderConstant("useNormalmap" , (irr::f32*)&layer2, 1);
+#else
+ services->setPixelShaderConstant("baseTexture" , (irr::s32*)&layer0, 1);
+ services->setPixelShaderConstant("normalTexture" , (irr::s32*)&layer1, 1);
+ services->setPixelShaderConstant("useNormalmap" , (irr::s32*)&layer2, 1);
+#endif
}
};
bool nodePlacementPrediction(Client &client,
- const ItemDefinition &playeritem_def,
- v3s16 nodepos, v3s16 neighbourpos)
+ const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
{
std::string prediction = playeritem_def.node_placement_prediction;
INodeDefManager *nodedef = client.ndef();
// Add node to client map
MapNode n(id, 0, param2);
try{
- // This triggers the required mesh update too
- client.addNode(p, n);
- return true;
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+
+ // Dont place node when player would be inside new node
+ // NOTE: This is to be eventually implemented by a mod as client-side Lua
+ if (!nodedef->get(n).walkable ||
+ (client.checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
+ (nodedef->get(n).walkable &&
+ neighbourpos != player->getStandingNodePos() + v3s16(0,1,0) &&
+ neighbourpos != player->getStandingNodePos() + v3s16(0,2,0))) {
+
+ // This triggers the required mesh update too
+ client.addNode(p, n);
+ return true;
+ }
}catch(InvalidPositionException &e){
errorstream<<"Node placement prediction failed for "
<<playeritem_def.name<<" (places "
return false;
}
+static void show_chat_menu(FormspecFormSource* current_formspec,
+ TextDest* current_textdest, IWritableTextureSource* tsrc,
+ IrrlichtDevice * device, Client* client, std::string text)
+{
+ std::string formspec =
+ "size[11,5.5,true]"
+ "field[3,2.35;6,0.5;f_text;;" + text + "]"
+ "button_exit[4,3;3,0.5;btn_send;" + wide_to_narrow(wstrgettext("Proceed")) + "]"
+ ;
+
+ /* Create menu */
+ /* Note: FormspecFormSource and LocalFormspecHandler
+ * are deleted by guiFormSpecMenu */
+ current_formspec = new FormspecFormSource(formspec,¤t_formspec);
+ current_textdest = new LocalFormspecHandler("MT_CHAT_MENU",client);
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(device, guiroot, -1,
+ &g_menumgr,
+ NULL, NULL, tsrc);
+ menu->doPause = false;
+ menu->setFormSource(current_formspec);
+ menu->setTextDest(current_textdest);
+ menu->drop();
+}
+
+static void show_deathscreen(FormspecFormSource* current_formspec,
+ TextDest* current_textdest, IWritableTextureSource* tsrc,
+ IrrlichtDevice * device, Client* client)
+{
+ std::string formspec =
+ std::string("") +
+ "size[11,5.5,true]"
+ "bgcolor[#320000b4;true]"
+ "label[4.85,1.35;You died.]"
+ "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]"
+ ;
+
+ /* Create menu */
+ /* Note: FormspecFormSource and LocalFormspecHandler
+ * are deleted by guiFormSpecMenu */
+ current_formspec = new FormspecFormSource(formspec,¤t_formspec);
+ current_textdest = new LocalFormspecHandler("MT_DEATH_SCREEN",client);
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(device, guiroot, -1,
+ &g_menumgr,
+ NULL, NULL, tsrc);
+ menu->doPause = false;
+ menu->setFormSource(current_formspec);
+ menu->setTextDest(current_textdest);
+ menu->drop();
+}
+
+/******************************************************************************/
+static void show_pause_menu(FormspecFormSource* current_formspec,
+ TextDest* current_textdest, IWritableTextureSource* tsrc,
+ IrrlichtDevice * device, bool singleplayermode)
+{
+
+ std::string control_text = wide_to_narrow(wstrgettext("Default Controls:\n"
+ "- WASD: move\n"
+ "- Space: jump/climb\n"
+ "- Shift: sneak/go down\n"
+ "- Q: drop item\n"
+ "- I: inventory\n"
+ "- Mouse: turn/look\n"
+ "- Mouse left: dig/punch\n"
+ "- Mouse right: place/use\n"
+ "- Mouse wheel: select item\n"
+ "- T: chat\n"
+ ));
+
+ float ypos = singleplayermode ? 1.0 : 0.5;
+ std::ostringstream os;
+
+ os << "size[11,5.5,true]"
+ << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
+ << wide_to_narrow(wstrgettext("Continue")) << "]";
+
+ if (!singleplayermode) {
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
+ << wide_to_narrow(wstrgettext("Change Password")) << "]";
+ }
+
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
+ << wide_to_narrow(wstrgettext("Sound Volume")) << "]";
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
+ << wide_to_narrow(wstrgettext("Exit to Menu")) << "]";
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
+ << wide_to_narrow(wstrgettext("Exit to OS")) << "]"
+ << "textarea[7.5,0.25;3.75,6;;" << control_text << ";]"
+ << "textarea[0.4,0.25;3.5,6;;" << "Minetest\n"
+ << minetest_build_info << "\n"
+ << "path_user = " << wrap_rows(porting::path_user, 20)
+ << "\n;]";
+
+ /* Create menu */
+ /* Note: FormspecFormSource and LocalFormspecHandler *
+ * are deleted by guiFormSpecMenu */
+ current_formspec = new FormspecFormSource(os.str(),¤t_formspec);
+ current_textdest = new LocalFormspecHandler("MT_PAUSE_MENU");
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, NULL, NULL, tsrc);
+ menu->doPause = true;
+ menu->setFormSource(current_formspec);
+ menu->setTextDest(current_textdest);
+ menu->drop();
+}
-void the_game(
- bool &kill,
- bool random_input,
- InputHandler *input,
- IrrlichtDevice *device,
- gui::IGUIFont* font,
- std::string map_dir,
- std::string playername,
- std::string password,
- std::string address, // If "", local server is used
- u16 port,
- std::wstring &error_message,
- std::string configpath,
- ChatBackend &chat_backend,
- const SubgameSpec &gamespec, // Used for local game,
- bool simple_singleplayer_mode
-)
+/******************************************************************************/
+void the_game(bool &kill, bool random_input, InputHandler *input,
+ IrrlichtDevice *device, gui::IGUIFont* font, std::string map_dir,
+ std::string playername, std::string password,
+ std::string address /* If "", local server is used */,
+ u16 port, std::wstring &error_message, ChatBackend &chat_backend,
+ const SubgameSpec &gamespec /* Used for local game */,
+ bool simple_singleplayer_mode)
{
FormspecFormSource* current_formspec = 0;
- TextDestPlayerInventory* current_textdest = 0;
+ TextDest* current_textdest = 0;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
draw_load_screen(text, device, font,0,25);
delete[] text;
infostream<<"Creating server"<<std::endl;
- server = new Server(map_dir, configpath, gamespec,
- simple_singleplayer_mode);
- server->start(port);
+
+ std::string bind_str = g_settings->get("bind_address");
+ Address bind_addr(0,0,0,0, port);
+
+ if (g_settings->getBool("ipv6_server")) {
+ bind_addr.setAddress((IPv6AddressBytes*) NULL);
+ }
+ try {
+ bind_addr.Resolve(bind_str.c_str());
+ address = bind_str;
+ } catch (ResolveError &e) {
+ infostream << "Resolving bind address \"" << bind_str
+ << "\" failed: " << e.what()
+ << " -- Listening on all addresses." << std::endl;
+ }
+
+ if(bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
+ error_message = L"Unable to listen on " +
+ narrow_to_wide(bind_addr.serializeString()) +
+ L" because IPv6 is disabled";
+ errorstream<<wide_to_narrow(error_message)<<std::endl;
+ // Break out of client scope
+ return;
+ }
+
+ server = new Server(map_dir, gamespec,
+ simple_singleplayer_mode,
+ bind_addr.isIPv6());
+
+ server->start(bind_addr);
}
do{ // Client scope (breakable do-while(0))
infostream<<"Creating client"<<std::endl;
MapDrawControl draw_control;
-
- Client client(device, playername.c_str(), password, draw_control,
- tsrc, shsrc, itemdef, nodedef, sound, &eventmgr);
-
- // Client acts as our GameDef
- IGameDef *gamedef = &client;
{
wchar_t* text = wgettext("Resolving address...");
delete[] text;
}
Address connect_address(0,0,0,0, port);
- try{
- if(address == "")
+ try {
+ connect_address.Resolve(address.c_str());
+ if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY
//connect_address.Resolve("localhost");
- connect_address.setAddress(127,0,0,1);
- else
- connect_address.Resolve(address.c_str());
+ if (connect_address.isIPv6()) {
+ IPv6AddressBytes addr_bytes;
+ addr_bytes.bytes[15] = 1;
+ connect_address.setAddress(&addr_bytes);
+ } else {
+ connect_address.setAddress(127,0,0,1);
+ }
+ }
}
- catch(ResolveError &e)
- {
- error_message = L"Couldn't resolve address";
+ catch(ResolveError &e) {
+ error_message = L"Couldn't resolve address: " + narrow_to_wide(e.what());
errorstream<<wide_to_narrow(error_message)<<std::endl;
// Break out of client scope
break;
}
+ if(connect_address.isIPv6() && !g_settings->getBool("enable_ipv6")) {
+ error_message = L"Unable to connect to " +
+ narrow_to_wide(connect_address.serializeString()) +
+ L" because IPv6 is disabled";
+ errorstream<<wide_to_narrow(error_message)<<std::endl;
+ // Break out of client scope
+ break;
+ }
+
+ /*
+ Create client
+ */
+ Client client(device, playername.c_str(), password, draw_control,
+ tsrc, shsrc, itemdef, nodedef, sound, &eventmgr,
+ connect_address.isIPv6());
+
+ // Client acts as our GameDef
+ IGameDef *gamedef = &client;
/*
Attempt to connect to the server
server->step(dtime);
// End condition
- if(client.connectedAndInitialized()){
+ if(client.getState() == LC_Init){
could_connect = true;
break;
}
server->step(dtime);
// End condition
- if(client.texturesReceived() &&
+ if(client.mediaReceived() &&
client.itemdefReceived() &&
client.nodedefReceived()){
got_content = true;
break;
}
// Break conditions
- if(!client.connectedAndInitialized()){
+ if(client.accessDenied()){
+ error_message = L"Access denied. Reason: "
+ +client.accessDeniedReason();
+ errorstream<<wide_to_narrow(error_message)<<std::endl;
+ break;
+ }
+ if(client.getState() < LC_Init){
error_message = L"Client disconnected";
errorstream<<wide_to_narrow(error_message)<<std::endl;
break;
}
// Display status
- std::ostringstream ss;
int progress=0;
if (!client.itemdefReceived())
{
- ss << "Item definitions...";
+ wchar_t* text = wgettext("Item definitions...");
progress = 0;
+ draw_load_screen(text, device, font, dtime, progress);
+ delete[] text;
}
else if (!client.nodedefReceived())
{
- ss << "Node definitions...";
+ wchar_t* text = wgettext("Node definitions...");
progress = 25;
+ draw_load_screen(text, device, font, dtime, progress);
+ delete[] text;
}
else
{
- ss << "Media...";
+ wchar_t* text = wgettext("Media...");
progress = 50+client.mediaReceiveProgress()*50+0.5;
+ draw_load_screen(text, device, font, dtime, progress);
+ delete[] text;
}
- wchar_t* text = wgettext(ss.str().c_str());
- draw_load_screen(text, device, font, dtime, progress);
- delete[] text;
// On some computers framerate doesn't seem to be
// automatically limited
f32 camera_yaw = 0; // "right/left"
f32 camera_pitch = 0; // "up/down"
+ int current_camera_mode = CAMERA_MODE_FIRST; // start in first-person view
+
/*
Clouds
*/
*/
Sky *sky = NULL;
- sky = new Sky(smgr->getRootSceneNode(), smgr, -1);
-
- /*
- FarMesh
- */
-
- FarMesh *farmesh = NULL;
- if(g_settings->getBool("enable_farmesh"))
- {
- farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
- }
+ sky = new Sky(smgr->getRootSceneNode(), smgr, -1, client.getEnv().getLocalPlayer());
+ scene::ISceneNode* skybox = NULL;
+
/*
A copy of the local inventory
*/
*/
int crack_animation_length = 5;
{
- video::ITexture *t = tsrc->getTextureRaw("crack_anylength.png");
+ video::ITexture *t = tsrc->getTexture("crack_anylength.png");
v2u32 size = t->getOriginalSize();
crack_animation_length = size.Y / size.X;
}
bool ldown_for_dig = false;
float damage_flash = 0;
- s16 farmesh_range = 20*MAP_BLOCKSIZE;
float jump_timer = 0;
bool reset_jump_timer = false;
bool invert_mouse = g_settings->getBool("invert_mouse");
- bool respawn_menu_active = false;
- bool update_wielded_item_trigger = false;
+ bool update_wielded_item_trigger = true;
bool show_hud = true;
bool show_chat = true;
/*
HUD object
*/
- Hud hud(driver, guienv, font, text_height,
+ Hud hud(driver, smgr, guienv, font, text_height,
gamedef, player, &local_inventory);
+ core::stringw str = L"Minetest [";
+ str += driver->getName();
+ str += "]";
+ device->setWindowCaption(str.c_str());
+
+ // Info text
+ std::wstring infotext;
+
for(;;)
{
if(device->run() == false || kill == true)
*/
{
- float fps_max = g_settings->getFloat("fps_max");
+ float fps_max = g_menumgr.pausesGame() ?
+ g_settings->getFloat("pause_fps_max") :
+ g_settings->getFloat("fps_max");
u32 frametime_min = 1000./fps_max;
if(busytime_u32 < frametime_min)
// Hilight boxes collected during the loop and displayed
std::vector<aabb3f> hilightboxes;
-
- // Info text
- std::wstring infotext;
-
- /*
- Debug info for client
- */
- {
- static float counter = 0.0;
- counter -= dtime;
- if(counter < 0)
- {
- counter = 30.0;
- client.printDebugInfo(infostream);
- }
- }
+ /* reset infotext */
+ infotext = L"";
/*
Profiler
*/
GUIFormSpecMenu *menu =
new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr,
- &client, gamedef);
+ &client, gamedef, tsrc);
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
assert(src);
+ menu->doPause = false;
menu->setFormSpec(src->getForm(), inventoryloc);
menu->setFormSource(src);
menu->setTextDest(new TextDestPlayerInventory(&client));
}
else if(input->wasKeyDown(EscapeKey))
{
- infostream<<"the_game: "
- <<"Launching pause menu"<<std::endl;
- // It will delete itself by itself
- (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
- &g_menumgr, simple_singleplayer_mode))->drop();
-
- // Move mouse cursor on top of the disconnect button
- if(simple_singleplayer_mode)
- input->setMousePos(displaycenter.X, displaycenter.Y+0);
- else
- input->setMousePos(displaycenter.X, displaycenter.Y+25);
+ show_pause_menu(current_formspec, current_textdest, tsrc, device,
+ simple_singleplayer_mode);
}
else if(input->wasKeyDown(getKeySetting("keymap_chat")))
{
- TextDest *dest = new TextDestChat(&client);
-
- (new GUITextInputMenu(guienv, guiroot, -1,
- &g_menumgr, dest,
- L""))->drop();
+ show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,"");
}
else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
{
- TextDest *dest = new TextDestChat(&client);
-
- (new GUITextInputMenu(guienv, guiroot, -1,
- &g_menumgr, dest,
- L"/"))->drop();
+ show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,"/");
}
else if(input->wasKeyDown(getKeySetting("keymap_console")))
{
}
else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
{
- irr::video::IImage* const image = driver->createScreenShot();
- if (image) {
- irr::c8 filename[256];
- snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
+ irr::video::IImage* const image = driver->createScreenShot();
+ if (image) {
+ irr::c8 filename[256];
+ snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
g_settings->get("screenshot_path").c_str(),
- device->getTimer()->getRealTime());
+ device->getTimer()->getRealTime());
if (driver->writeImageToFile(image, filename)) {
std::wstringstream sstr;
sstr<<"Saved screenshot to '"<<filename<<"'";
} else{
infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
}
- image->drop();
- }
+ image->drop();
+ }
}
else if(input->wasKeyDown(getKeySetting("keymap_toggle_hud")))
{
else{
s32 dx = input->getMousePos().X - displaycenter.X;
s32 dy = input->getMousePos().Y - displaycenter.Y;
- if(invert_mouse)
+ if(invert_mouse || player->camera_mode == CAMERA_MODE_THIRD_FRONT)
dy = -dy;
//infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
camera_yaw
);
client.setPlayerControl(control);
- u32 keyPressed=
- 1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
- 2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
- 4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
- 8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
- 16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
- 32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
- 64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
- 128*(int)input->getLeftState()+
- 256*(int)input->getRightState();
LocalPlayer* player = client.getEnv().getLocalPlayer();
- player->keyPressed=keyPressed;
+ player->keyPressed=
+ (((int)input->isKeyDown(getKeySetting("keymap_forward")) & 0x1) << 0) |
+ (((int)input->isKeyDown(getKeySetting("keymap_backward")) & 0x1) << 1) |
+ (((int)input->isKeyDown(getKeySetting("keymap_left")) & 0x1) << 2) |
+ (((int)input->isKeyDown(getKeySetting("keymap_right")) & 0x1) << 3) |
+ (((int)input->isKeyDown(getKeySetting("keymap_jump")) & 0x1) << 4) |
+ (((int)input->isKeyDown(getKeySetting("keymap_special1")) & 0x1) << 5) |
+ (((int)input->isKeyDown(getKeySetting("keymap_sneak")) & 0x1) << 6) |
+ (((int)input->getLeftState() & 0x1) << 7) |
+ (((int)input->getRightState() & 0x1) << 8);
}
-
+
/*
- Run server
+ Run server, client (and process environments)
*/
-
- if(server != NULL)
+ bool can_be_and_is_paused =
+ (simple_singleplayer_mode && g_menumgr.pausesGame());
+ if(can_be_and_is_paused)
{
- //TimeTaker timer("server->step(dtime)");
- server->step(dtime);
+ // No time passes
+ dtime = 0;
}
-
- /*
- Process environment
- */
-
+ else
{
- //TimeTaker timer("client.step(dtime)");
- client.step(dtime);
- //client.step(dtime_avg1);
+ if(server != NULL)
+ {
+ //TimeTaker timer("server->step(dtime)");
+ server->step(dtime);
+ }
+ {
+ //TimeTaker timer("client.step(dtime)");
+ client.step(dtime);
+ }
}
{
}
else if(event.type == CE_DEATHSCREEN)
{
- if(respawn_menu_active)
- continue;
+ show_deathscreen(current_formspec, current_textdest,
+ tsrc, device, &client);
- /*bool set_camera_point_target =
- event.deathscreen.set_camera_point_target;
- v3f camera_point_target;
- camera_point_target.X = event.deathscreen.camera_point_target_x;
- camera_point_target.Y = event.deathscreen.camera_point_target_y;
- camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
- MainRespawnInitiator *respawner =
- new MainRespawnInitiator(
- &respawn_menu_active, &client);
- GUIDeathScreen *menu =
- new GUIDeathScreen(guienv, guiroot, -1,
- &g_menumgr, respawner);
- menu->drop();
-
chat_backend.addMessage(L"", L"You died.");
/* Handle visualization */
-
damage_flash = 0;
LocalPlayer* player = client.getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- /*LocalPlayer* player = client.getLocalPlayer();
- player->setPosition(player->getPosition() + v3f(0,-BS,0));
- camera.update(player, busytime, screensize);*/
}
else if (event.type == CE_SHOW_FORMSPEC)
{
GUIFormSpecMenu *menu =
new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr,
- &client, gamedef);
+ &client, gamedef, tsrc);
+ menu->doPause = false;
menu->setFormSource(current_formspec);
menu->setTextDest(current_textdest);
menu->drop();
delete(event.show_formspec.formspec);
delete(event.show_formspec.formname);
}
- else if(event.type == CE_TEXTURES_UPDATED)
- {
- update_wielded_item_trigger = true;
- }
else if(event.type == CE_SPAWN_PARTICLE)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
- AtlasPointer ap =
+ video::ITexture *texture =
gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
new Particle(gamedef, smgr, player, client.getEnv(),
*event.spawn_particle.acc,
event.spawn_particle.expirationtime,
event.spawn_particle.size,
- event.spawn_particle.collisiondetection, ap);
+ event.spawn_particle.collisiondetection,
+ event.spawn_particle.vertical,
+ texture,
+ v2f(0.0, 0.0),
+ v2f(1.0, 1.0));
}
else if(event.type == CE_ADD_PARTICLESPAWNER)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
- AtlasPointer ap =
+ video::ITexture *texture =
gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
new ParticleSpawner(gamedef, smgr, player,
event.add_particlespawner.minsize,
event.add_particlespawner.maxsize,
event.add_particlespawner.collisiondetection,
- ap,
+ event.add_particlespawner.vertical,
+ texture,
event.add_particlespawner.id);
}
else if(event.type == CE_DELETE_PARTICLESPAWNER)
delete event.hudadd.text;
delete event.hudadd.align;
delete event.hudadd.offset;
+ delete event.hudadd.world_pos;
continue;
}
e->dir = event.hudadd.dir;
e->align = *event.hudadd.align;
e->offset = *event.hudadd.offset;
+ e->world_pos = *event.hudadd.world_pos;
if (id == nhudelem)
player->hud.push_back(e);
delete event.hudadd.text;
delete event.hudadd.align;
delete event.hudadd.offset;
+ delete event.hudadd.world_pos;
}
else if (event.type == CE_HUDRM)
{
{
u32 id = event.hudchange.id;
if (id >= player->hud.size() || !player->hud[id]) {
+ delete event.hudchange.v3fdata;
delete event.hudchange.v2fdata;
delete event.hudchange.sdata;
continue;
case HUD_STAT_OFFSET:
e->offset = *event.hudchange.v2fdata;
break;
+ case HUD_STAT_WORLD_POS:
+ e->world_pos = *event.hudchange.v3fdata;
+ break;
}
+ delete event.hudchange.v3fdata;
delete event.hudchange.v2fdata;
delete event.hudchange.sdata;
}
+ else if (event.type == CE_SET_SKY)
+ {
+ sky->setVisible(false);
+ if(skybox){
+ skybox->drop();
+ skybox = NULL;
+ }
+ // Handle according to type
+ if(*event.set_sky.type == "regular"){
+ sky->setVisible(true);
+ }
+ else if(*event.set_sky.type == "skybox" &&
+ event.set_sky.params->size() == 6){
+ sky->setFallbackBgColor(*event.set_sky.bgcolor);
+ skybox = smgr->addSkyBoxSceneNode(
+ tsrc->getTexture((*event.set_sky.params)[0]),
+ tsrc->getTexture((*event.set_sky.params)[1]),
+ tsrc->getTexture((*event.set_sky.params)[2]),
+ tsrc->getTexture((*event.set_sky.params)[3]),
+ tsrc->getTexture((*event.set_sky.params)[4]),
+ tsrc->getTexture((*event.set_sky.params)[5]));
+ }
+ // Handle everything else as plain color
+ else {
+ if(*event.set_sky.type != "plain")
+ infostream<<"Unknown sky type: "
+ <<(*event.set_sky.type)<<std::endl;
+ sky->setFallbackBgColor(*event.set_sky.bgcolor);
+ }
+
+ delete event.set_sky.bgcolor;
+ delete event.set_sky.type;
+ delete event.set_sky.params;
+ }
+ else if (event.type == CE_OVERRIDE_DAY_NIGHT_RATIO)
+ {
+ bool enable = event.override_day_night_ratio.do_override;
+ u32 value = event.override_day_night_ratio.ratio_f * 1000;
+ client.getEnv().setDayNightRatioOverride(enable, value);
+ }
}
}
Update camera
*/
+ v3s16 old_camera_offset = camera.getOffset();
+
LocalPlayer* player = client.getEnv().getLocalPlayer();
float full_punch_interval = playeritem_toolcap.full_punch_interval;
float tool_reload_ratio = time_from_last_punch / full_punch_interval;
+
+ if(input->wasKeyDown(getKeySetting("keymap_camera_mode"))) {
+
+ if (current_camera_mode == CAMERA_MODE_FIRST)
+ current_camera_mode = CAMERA_MODE_THIRD;
+ else if (current_camera_mode == CAMERA_MODE_THIRD)
+ current_camera_mode = CAMERA_MODE_THIRD_FRONT;
+ else
+ current_camera_mode = CAMERA_MODE_FIRST;
+
+ }
+ player->camera_mode = current_camera_mode;
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
- camera.update(player, busytime, screensize, tool_reload_ratio);
+ camera.update(player, dtime, busytime, screensize, tool_reload_ratio,
+ current_camera_mode, client.getEnv());
camera.step(dtime);
v3f player_position = player->getPosition();
v3f camera_position = camera.getPosition();
v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax();
+ v3s16 camera_offset = camera.getOffset();
+
+ bool camera_offset_changed = (camera_offset != old_camera_offset);
if(!disable_camera_update){
client.getEnv().getClientMap().updateCamera(camera_position,
- camera_direction, camera_fov);
+ camera_direction, camera_fov, camera_offset);
+ if (camera_offset_changed){
+ client.updateCameraOffset(camera_offset);
+ client.getEnv().updateCameraOffset(camera_offset);
+ if (clouds)
+ clouds->updateCameraOffset(camera_offset);
+ }
}
// Update sound listener
- sound->updateListener(camera.getCameraNode()->getPosition(),
+ sound->updateListener(camera.getCameraNode()->getPosition()+intToFloat(camera_offset, BS),
v3f(0,0,0), // velocity
camera.getDirection(),
camera.getCameraNode()->getUpVector());
//u32 t1 = device->getTimer()->getRealTime();
- f32 d = 4; // max. distance
+ f32 d = playeritem_def.range; // max. distance
+ f32 d_hand = itemdef->get("").range;
+ if(d < 0 && d_hand >= 0)
+ d = d_hand;
+ else if(d < 0)
+ d = 4.0;
core::line3d<f32> shootline(camera_position,
camera_position + camera_direction * BS * (d+1));
+ // prevent player pointing anything in front-view
+ if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
+ shootline = core::line3d<f32>(0,0,0,0,0,0);
+
ClientActiveObject *selected_object = NULL;
PointedThing pointed = getPointedThing(
&client, player_position, camera_direction,
camera_position, shootline, d,
playeritem_def.liquids_pointable, !ldown_for_dig,
+ camera_offset,
// output
hilightboxes,
selected_object);
if(tp)
params = getDigParams(nodedef->get(n).groups, tp);
}
-
- SimpleSoundSpec sound_dig = nodedef->get(n).sound_dig;
- if(sound_dig.exists()){
- if(sound_dig.name == "__group"){
- if(params.main_group != ""){
- soundmaker.m_player_leftpunch_sound.gain = 0.5;
- soundmaker.m_player_leftpunch_sound.name =
- std::string("default_dig_") +
- params.main_group;
- }
- } else{
- soundmaker.m_player_leftpunch_sound = sound_dig;
- }
- }
float dig_time_complete = 0.0;
dig_index = crack_animation_length;
}
+ SimpleSoundSpec sound_dig = nodedef->get(n).sound_dig;
+ if(sound_dig.exists() && params.diggable){
+ if(sound_dig.name == "__group"){
+ if(params.main_group != ""){
+ soundmaker.m_player_leftpunch_sound.gain = 0.5;
+ soundmaker.m_player_leftpunch_sound.name =
+ std::string("default_dig_") +
+ params.main_group;
+ }
+ } else{
+ soundmaker.m_player_leftpunch_sound = sound_dig;
+ }
+ }
+
// Don't show cracks if not diggable
if(dig_time_complete >= 100000.0)
{
// Sign special case, at least until formspec is properly implemented.
// Deprecated?
- if(meta && meta->getString("formspec") == "hack:sign_text_input"
+ if(meta && meta->getString("formspec") == "hack:sign_text_input"
&& !random_input
&& !input->isKeyDown(getKeySetting("keymap_sneak")))
{
GUIFormSpecMenu *menu =
new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr,
- &client, gamedef);
+ &client, gamedef, tsrc);
+ menu->doPause = false;
menu->setFormSpec(meta->getString("formspec"),
inventoryloc);
menu->setFormSource(new NodeMetadataFormSource(
// Otherwise report right click to server
else
{
- // Report to server
- client.interact(3, pointed);
- camera.setDigging(1); // right click animation
-
+ camera.setDigging(1); // right click animation (always shown for feedback)
+
// If the wielded item has node placement prediction,
// make that happen
bool placed = nodePlacementPrediction(client,
- playeritem_def,
- nodepos, neighbourpos);
-
- // Read the sound
- if(placed)
+ playeritem_def,
+ nodepos, neighbourpos);
+
+ if(placed) {
+ // Report to server
+ client.interact(3, pointed);
+ // Read the sound
soundmaker.m_player_rightpunch_sound =
- playeritem_def.sound_place;
- else
+ playeritem_def.sound_place;
+ } else {
soundmaker.m_player_rightpunch_sound =
- SimpleSoundSpec();
+ SimpleSoundSpec();
+ }
+
+ if (playeritem_def.node_placement_prediction == "" ||
+ nodedef->get(map.getNode(nodepos)).rightclickable)
+ client.interact(3, pointed); // Report to server
}
}
}
Fog range
*/
- if(farmesh)
- {
- fog_range = BS*farmesh_range;
- }
- else
- {
+ if(draw_control.range_all)
+ fog_range = 100000*BS;
+ else {
fog_range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS;
+ fog_range = MYMIN(fog_range, (draw_control.farthest_drawn+20)*BS);
fog_range *= 0.9;
- if(draw_control.range_all)
- fog_range = 100000*BS;
}
/*
sky->update(time_of_day_smooth, time_brightness, direct_brightness,
sunlight_seen);
- float brightness = sky->getBrightness();
video::SColor bgcolor = sky->getBgColor();
video::SColor skycolor = sky->getSkyColor();
}
}
- /*
- Update farmesh
- */
- if(farmesh)
- {
- farmesh_range = draw_control.wanted_range * 10;
- if(draw_control.range_all && farmesh_range < 500)
- farmesh_range = 500;
- if(farmesh_range > 1000)
- farmesh_range = 1000;
-
- farmesh->step(dtime);
- farmesh->update(v2f(player_position.X, player_position.Z),
- brightness, farmesh_range);
- }
-
/*
Update particles
*/
- allparticles_step(dtime, client.getEnv());
+ allparticles_step(dtime);
allparticlespawners_step(dtime, client.getEnv());
/*
Fog
*/
- if(g_settings->getBool("enable_fog") == true && !force_fog_off)
+ if(g_settings->getBool("enable_fog") && !force_fog_off)
{
driver->setFog(
bgcolor,
//TimeTaker guiupdatetimer("Gui updating");
- const char program_name_and_version[] =
- "Minetest " VERSION_STRING;
-
if(show_debug)
{
static float drawtime_avg = 0;
scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
static float endscenetime_avg = 0;
endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/
-
+
+ u16 fps = (1.0/dtime_avg1);
+
std::ostringstream os(std::ios_base::binary);
os<<std::fixed
- <<program_name_and_version
+ <<"Minetest "<<minetest_version_hash
+ <<" FPS = "<<fps
<<" (R: range_all="<<draw_control.range_all<<")"
<<std::setprecision(0)
<<" drawtime = "<<drawtime_avg
}
else if(show_hud || show_chat)
{
- guitext->setText(narrow_to_wide(program_name_and_version).c_str());
+ std::ostringstream os(std::ios_base::binary);
+ os<<"Minetest "<<minetest_version_hash;
+ guitext->setText(narrow_to_wide(os.str()).c_str());
guitext->setVisible(true);
}
else
<<", "<<(player_position.Y/BS)
<<", "<<(player_position.Z/BS)
<<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
- <<") (seed = "<<((unsigned long long)client.getMapSeed())
+ <<") (seed = "<<((u64)client.getMapSeed())
<<")";
guitext2->setText(narrow_to_wide(os.str()).c_str());
guitext2->setVisible(true);
*/
update_draw_list_timer += dtime;
if(update_draw_list_timer >= 0.2 ||
- update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){
+ update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2 ||
+ camera_offset_changed){
update_draw_list_timer = 0;
client.getEnv().getClientMap().updateDrawList(driver);
update_draw_list_last_cam_dir = camera_direction;
driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
- driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
+ driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
irr::scene::ESNRP_SOLID +
irr::scene::ESNRP_TRANSPARENT +
irr::scene::ESNRP_TRANSPARENT_EFFECT +
smgr->drawAll(); // 'smgr->drawAll();' may go here
+ driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
+
+ if (show_hud)
+ hud.drawSelectionBoxes(hilightboxes);
+
//Right eye...
irr::core::vector3df rightEye;
smgr->drawAll(); // 'smgr->drawAll();' may go here
+ driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
+
+ if (show_hud)
+ hud.drawSelectionBoxes(hilightboxes);
+
//driver->endScene();
driver->setMaterial(m);
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
-
- if (show_hud)
+ if((!g_settings->getBool("anaglyph")) && (show_hud))
+ {
hud.drawSelectionBoxes(hilightboxes);
+ }
+
/*
Wielded tool
*/
- if(show_hud && (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE))
+ if(show_hud &&
+ (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
+ current_camera_mode < CAMERA_MODE_THIRD)
{
// Warning: This clears the Z buffer.
camera.drawWieldedTool();
*/
{
TimeTaker timer("endScene");
- endSceneX(driver);
+ driver->endScene();
endscenetime = timer.stop(true);
}
End of drawing
*/
- static s16 lastFPS = 0;
- //u16 fps = driver->getFPS();
- u16 fps = (1.0/dtime_avg1);
-
- if (lastFPS != fps)
- {
- core::stringw str = L"Minetest [";
- str += driver->getName();
- str += "] FPS=";
- str += fps;
-
- device->setWindowCaption(str.c_str());
- lastFPS = fps;
- }
-
/*
Log times and stuff for visualization
*/
chat_backend.addMessage(L"", L"# Disconnected.");
chat_backend.addMessage(L"", L"");
+ client.Stop();
+
+ //force answer all texture and shader jobs (TODO return empty values)
+
+ while(!client.isShutdown()) {
+ tsrc->processQueue();
+ shsrc->processQueue();
+ sleep_ms(100);
+ }
+
// Client scope (client is destructed before destructing *def and tsrc)
}while(0);
} // try-catch
L" running a different version of Minetest.";
errorstream<<wide_to_narrow(error_message)<<std::endl;
}
- catch(ServerError &e)
- {
+ catch(ServerError &e) {
error_message = narrow_to_wide(e.what());
- errorstream<<wide_to_narrow(error_message)<<std::endl;
+ errorstream << "ServerError: " << e.what() << std::endl;
}
- catch(ModError &e)
- {
- errorstream<<e.what()<<std::endl;
+ catch(ModError &e) {
+ errorstream << "ModError: " << e.what() << std::endl;
error_message = narrow_to_wide(e.what()) + wgettext("\nCheck debug.txt for details.");
}
infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str()
<< std::endl;
}
+ clearTextureNameCache();
infostream << "\tRemaining materials: "
<< driver-> getMaterialRendererCount ()
<< " (note: irrlicht doesn't support removing renderers)"<< std::endl;